Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2025-10-01 17:50:25 UTC using RuboCop version 1.81.1.
# on 2026-10-25 21:30:32 UTC using RuboCop version 1.81.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
Expand Down Expand Up @@ -44,7 +44,7 @@ RSpec/ContextWording:
- 'spec/slack-api-explorer/commands/slack_spec.rb'
- 'spec/support/api/endpoints/it_behaves_like_a_cursor_api.rb'

# Offense count: 12
# Offense count: 14
# Configuration parameters: CountAsOne.
RSpec/ExampleLength:
Max: 27
Expand All @@ -67,7 +67,7 @@ RSpec/LetSetup:
RSpec/MessageSpies:
EnforcedStyle: receive

# Offense count: 26
# Offense count: 29
RSpec/MultipleExpectations:
Max: 7

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### Changelog

* 2026/10/25: Upgrade slack-ruby-bot-server to 2.3.0 and rack-server-pages to 0.3.0, version local website assets, and centrally configure private, revalidating page caching without changing Slack installation or API behavior - [@dblock](https://github.com/dblock), [@Copilot](https://github.com/apps/copilot-swe-agent).
* 2023/01/16: Replaced Travis-CI with GHA - [@dblock](https://github.com/dblock).
* 2018/05/10: Use ERB instead of static pages - [@dblock](https://github.com/dblock).
* 2017/03/14: Use slack-ruby-bot-server - [@dblock](https://github.com/dblock).
Expand Down
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ gem 'ostruct'
gem 'puma'
gem 'rack'
gem 'rack-robotz'
gem 'rack-server-pages'
gem 'rack-server-pages', '~> 0.3.0'
gem 'slack-ruby-bot-server', '~> 2.3.0'
gem 'slack-ruby-bot-server-mailchimp'
gem 'slack-ruby-bot-server-rtm'

Expand Down
7 changes: 4 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ GEM
rack-rewrite (1.5.1)
rack-robotz (0.0.4)
rack
rack-server-pages (0.2.1)
rack-server-pages (0.3.0)
rack
rack-test (2.2.0)
rack (>= 1.3)
Expand Down Expand Up @@ -305,7 +305,7 @@ GEM
activesupport
hashie
slack-ruby-client (>= 0.14.0)
slack-ruby-bot-server (2.2.0)
slack-ruby-bot-server (2.3.0)
async
foreman
grape
Expand Down Expand Up @@ -390,7 +390,7 @@ DEPENDENCIES
puma
rack
rack-robotz
rack-server-pages
rack-server-pages (~> 0.3.0)
rack-test
rackup
rake
Expand All @@ -400,6 +400,7 @@ DEPENDENCIES
rubocop-rake
rubocop-rspec
selenium-webdriver
slack-ruby-bot-server (~> 2.3.0)
slack-ruby-bot-server-mailchimp
slack-ruby-bot-server-rtm
vcr
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ Post a message into a channel.

![](public/img/post.gif)

## Website asset caching

Local scripts and images use content-hashed `asset_path` URLs from rack-server-pages 0.3.0. The custom middleware applies slack-ruby-bot-server 2.3.0's `config.server_pages` callback, setting `Cache-Control: private, no-cache` for rendered pages so browsers revalidate and discover changed asset URLs. Static files retain the middleware's content ETags and timestamp validation defaults, without long-lived or immutable caching. Versioned URLs are cache keys, not archives; old query strings still serve current files.

## Usage

### Help
Expand Down
5 changes: 5 additions & 0 deletions config/initializers/slack_ruby_bot_server.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SlackRubyBotServer.configure do |config|
config.server_pages do |pages|
pages.cache_control = 'private, no-cache'
end
end
3 changes: 1 addition & 2 deletions public/help.html → public/help.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<body style="text-align: left; margin: 50px;">
<p style="text-align: center">
<img src='img/icon.png' width="100px" height="100px">
<img src="<%= h asset_path('/img/icon.png') %>" width="100px" height="100px">
</p>
<h3>Help</h3>
<p>
Expand Down Expand Up @@ -141,4 +141,3 @@ <h3>Help</h3>
</p>
</body>
</html>

13 changes: 6 additions & 7 deletions public/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<html>
<head>
<title>API Explorer for Slack</title>
<script src="/scripts/jquery-1.7.1.min.js"></script>
<script src="/scripts/url.min.js"></script>
<script src="/scripts/register.js"></script>
<script src="/scripts/stats.js"></script>
<script src="<%= h asset_path('/scripts/jquery-1.7.1.min.js') %>"></script>
<script src="<%= h asset_path('/scripts/url.min.js') %>"></script>
<script src="<%= h asset_path('/scripts/register.js') %>"></script>
<script src="<%= h asset_path('/scripts/stats.js') %>"></script>
</head>
<body style="text-align: center">
<p>
<img src='img/icon.png' width="100px" height="100px">
<img src="<%= h asset_path('/img/icon.png') %>" width="100px" height="100px">
</p>
<p>
<h3>Whoa, an API explorer for the Slack Web API.</h3>
Expand All @@ -19,7 +19,7 @@
</p>
<p id='active_teams_count'>&nbsp;</p>
<p>
<img src="img/dm.gif">
<img src="<%= h asset_path('/img/dm.gif') %>">
</p>
<p>
<a href="https://twitter.com/share" class="twitter-share-button"{count} data-text="Whoa, an API explorer for the Slack Web API!" data-via="dblockdotorg">Tweet</a>
Expand All @@ -43,4 +43,3 @@
</p>
</body>
</html>

2 changes: 1 addition & 1 deletion public/privacy.html → public/privacy.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<body style="text-align: left; margin: 50px;">
<p style="text-align: center">
<img src='img/icon.png' width="100px" height="100px">
<img src="<%= h asset_path('/img/icon.png') %>" width="100px" height="100px">
</p>
<h3>tl;dr</h3>
<p>
Expand Down
4 changes: 3 additions & 1 deletion slack-api-explorer/api/middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ def self.instance

use Rack::Robotz, 'User-Agent' => '*', 'Disallow' => '/api'

use Rack::ServerPages
use Rack::ServerPages do |pages|
SlackRubyBotServer.config.server_pages&.call(pages)
end

run Api::Middleware.new
}.to_app
Expand Down
37 changes: 37 additions & 0 deletions spec/api/middleware_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'spec_helper'

describe Api::Middleware do
include Rack::Test::Methods

let(:app) { described_class.instance }

['/', '/help.html', '/privacy.html'].each do |path|
it "serves #{path} with versioned assets and private revalidation" do
get path

assets = Capybara.string(last_response.body).all('script[src^="/"], img[src^="/"]', visible: :all)
expect(last_response.status).to eq 200
expect(last_response.headers['Cache-Control']).to eq 'private, no-cache'
expect(assets).not_to be_empty
expect(assets.map { |asset| asset[:src] }).to all(match(/\?v=[a-f0-9]{64}\z/))
end
end

it 'revalidates static assets using their content ETag' do
get '/scripts/register.js'
etag = last_response.headers['ETag']
expect(etag).to eq %("#{Digest::SHA256.file('public/scripts/register.js').hexdigest}")

get '/scripts/register.js', {}, 'HTTP_IF_NONE_MATCH' => etag
expect(last_response.status).to eq 304
expect(last_response.body).to be_empty
end

it 'returns current bytes when an old ETag accompanies a matching timestamp' do
get '/scripts/register.js', {}, 'HTTP_IF_NONE_MATCH' => '"old-content"',
'HTTP_IF_MODIFIED_SINCE' => File.mtime('public/scripts/register.js').httpdate

expect(last_response.status).to eq 200
expect(last_response.body).to eq File.read('public/scripts/register.js')
end
end
12 changes: 12 additions & 0 deletions spec/integration/website_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require 'spec_helper'

describe 'Website', :js, type: :feature do
it 'loads the content-versioned logo after a reload' do
visit '/help.html'
page.refresh

expect(page).to have_css('img[src^="/img/icon.png?v="]') do |image|
image.evaluate_script('this.complete && this.naturalWidth > 0')
end
end
end
Loading