Skip to content

Commit 2f24136

Browse files
committed
.
1 parent 608ea8a commit 2f24136

File tree

14 files changed

+367
-248
lines changed

14 files changed

+367
-248
lines changed

app.rb

Lines changed: 24 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ module Web
2828
class App < Roda
2929
CONTENT_TYPE_RSS = 'application/xml'
3030

31-
def self.development? = ENV['RACK_ENV'] == 'development'
31+
def self.development? = EnvironmentValidator.development?
3232
def development? = self.class.development?
3333

3434
EnvironmentValidator.validate_environment!
@@ -116,7 +116,7 @@ def development? = self.class.development?
116116
route do |r|
117117
r.public
118118

119-
r.on 'api', 'v1' do
119+
r.on 'api', 'v1' do # rubocop:disable Metrics/BlockLength
120120
r.response['Content-Type'] = 'application/json'
121121

122122
r.on 'health' do
@@ -189,28 +189,6 @@ def development? = self.class.development?
189189
end
190190
end
191191

192-
def fallback_html
193-
<<~HTML
194-
<!DOCTYPE html>
195-
<html>
196-
<head>
197-
<title>html2rss-web</title>
198-
<meta name="viewport" content="width=device-width,initial-scale=1">
199-
<style>
200-
body{font-family:system-ui,sans-serif;max-width:800px;margin:0 auto;padding:2rem;line-height:1.6}
201-
h1{color:#111827}
202-
code{background:#f3f4f6;padding:0.2rem 0.4rem;border-radius:0.25rem}
203-
</style>
204-
</head>
205-
<body>
206-
<h1>html2rss-web</h1>
207-
<p>Convert websites to RSS feeds</p>
208-
<p>API available at <code>/api/</code></p>
209-
</body>
210-
</html>
211-
HTML
212-
end
213-
214192
private
215193

216194
def handle_feed_generation(router, feed_name)
@@ -221,34 +199,36 @@ def handle_feed_generation(router, feed_name)
221199
rss_content
222200
end
223201

224-
def generate_rss_response(router, url)
225-
router.response['Content-Type'] = 'application/xml'
226-
HttpCache.expires(router.response, 600, cache_control: 'public')
202+
def handle_health_check(router)
203+
router.response['Content-Type'] = 'text/plain'
227204

228-
AutoSource.generate_feed_content(url, router.params['strategy'] || 'ssrf_filter').to_s
229-
end
205+
health_response = Api::V1::Health.show(router)
230206

231-
def error_response(router, status, message)
232-
router.response.status = status
233-
message
234-
end
207+
raise 'unhealthy' unless health_response[:success] && health_response.dig(:data, :health, :status) == 'healthy'
235208

236-
def handle_health_check(router)
237-
health_response = Api::V1::Health.show(router)
238-
if health_response[:success] && health_response.dig(:data, :health, :status) == 'healthy'
239-
router.response['Content-Type'] = 'text/plain'
240-
'success'
241-
else
242-
router.response.status = 500
243-
router.response['Content-Type'] = 'text/plain'
244-
'health check failed'
245-
end
209+
'success'
246210
rescue StandardError => error
247211
router.response.status = 500
248212

249-
router.response['Content-Type'] = 'text/plain'
250213
"health check error: #{error.message}"
251214
end
215+
216+
def fallback_html
217+
<<~HTML
218+
<!DOCTYPE html>
219+
<html>
220+
<head>
221+
<title>html2rss-web</title>
222+
<meta name="viewport" content="width=device-width,initial-scale=1">
223+
</head>
224+
<body>
225+
<h1>html2rss-web</h1>
226+
<p>Convert websites to RSS feeds</p>
227+
<p>API available at <code>/api/</code></p>
228+
</body>
229+
</html>
230+
HTML
231+
end
252232
end
253233
end
254234
end

app/account_manager.rb

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# frozen_string_literal: true
2+
3+
require_relative 'local_config'
4+
5+
module Html2rss
6+
module Web
7+
##
8+
# Account management functionality
9+
module AccountManager
10+
module_function
11+
12+
# @param token [String]
13+
# @return [Hash, nil]
14+
def get_account(token)
15+
return nil unless token && token_index.key?(token)
16+
17+
token_index[token]
18+
end
19+
20+
# @return [Hash] token to account mapping
21+
def token_index
22+
@token_index ||= build_token_index # rubocop:disable ThreadSafety/ClassInstanceVariable
23+
end
24+
25+
# @return [Hash]
26+
def build_token_index
27+
accounts.each_with_object({}) { |account, hash| hash[account[:token]] = account }
28+
end
29+
30+
# @return [Array<Hash>]
31+
def accounts
32+
load_accounts
33+
end
34+
35+
# @param username [String]
36+
# @return [Hash, nil]
37+
def get_account_by_username(username)
38+
return nil unless username
39+
40+
accounts.find { |account| account[:username] == username }
41+
end
42+
43+
# @return [Array<Hash>]
44+
def load_accounts
45+
auth_config = LocalConfig.global[:auth]
46+
return [] unless auth_config&.dig(:accounts)
47+
48+
auth_config[:accounts].map do |account|
49+
{
50+
username: account[:username].to_s,
51+
token: account[:token].to_s,
52+
allowed_urls: Array(account[:allowed_urls]).map(&:to_s)
53+
}
54+
end
55+
end
56+
end
57+
end
58+
end

app/api/v1/feeds.rb

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module V1
1515
module Feeds
1616
module_function
1717

18-
def index(_request)
18+
def index(_request) # rubocop:disable Metrics/MethodLength
1919
feeds = Html2rss::Web::Feeds.list_feeds.map do |feed|
2020
{
2121
id: feed[:name],
@@ -50,19 +50,24 @@ def json_request?(request)
5050
accept_header.include?('application/json') && !accept_header.include?('application/xml')
5151
end
5252

53-
def show_feed_metadata(feed_id)
53+
def show_feed_metadata(feed_id) # rubocop:disable Metrics/MethodLength
5454
config = LocalConfig.find(feed_id)
5555
raise NotFoundError, 'Feed not found' unless config
5656

57-
{ success: true, data: { feed: {
58-
id: feed_id,
59-
name: feed_id,
60-
description: "RSS feed for #{feed_id}",
61-
url: "/api/v1/feeds/#{feed_id}",
62-
strategy: config[:strategy] || 'ssrf_filter',
63-
created_at: nil,
64-
updated_at: nil
65-
} } }
57+
{
58+
success: true,
59+
data: {
60+
feed: {
61+
id: feed_id,
62+
name: feed_id,
63+
description: "RSS feed for #{feed_id}",
64+
url: "/api/v1/feeds/#{feed_id}",
65+
strategy: config[:strategy] || 'ssrf_filter',
66+
created_at: nil,
67+
updated_at: nil
68+
}
69+
}
70+
}
6671
end
6772

6873
def generate_feed_content(request, feed_id)

app/api/v1/health.rb

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,30 @@ module V1
1414
module Health
1515
module_function
1616

17-
def show(request)
17+
def show(request) # rubocop:disable Metrics/MethodLength
1818
health_check_account = HealthCheck.find_health_check_account
1919
account = Auth.authenticate(request)
2020

2121
unless account && health_check_account && account[:token] == health_check_account[:token]
22-
raise UnauthorizedError,
23-
'Health check authentication required'
22+
raise UnauthorizedError, 'Health check authentication required'
2423
end
2524

2625
health_result = HealthCheck.run
2726

2827
raise InternalServerError, 'Health check failed' unless health_result == 'success'
2928

30-
{ success: true, data: { health: {
31-
status: 'healthy',
32-
timestamp: Time.now.iso8601,
33-
version: '1.0.0',
34-
environment: ENV['RACK_ENV'] || 'development',
35-
checks: {}
36-
} } }
29+
{
30+
success: true,
31+
data: {
32+
health: {
33+
status: 'healthy',
34+
timestamp: Time.now.iso8601,
35+
version: '1.0.0',
36+
environment: ENV['RACK_ENV'] || 'development',
37+
checks: {}
38+
}
39+
}
40+
}
3741
end
3842

3943
def ready(_request)

0 commit comments

Comments
 (0)