0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-09 21:45:25 +08:00
discourse/plugins/discourse-rss-polling/app/services/discourse_rss_polling/feed_url.rb
Régis Hanol 4fc1144521
UX: Redesign the RSS Polling admin interface (#40790)
Previously, the RSS Polling plugin's admin page predated Discourse's
admin interface guidelines: it was a single inline-editable table with
no breadcrumbs or page header, it truncated long feed URLs, it required
horizontal scrolling on mobile, and it gave admins no way to verify a
feed before saving it.

This change rebuilds the page on the standard plugin "show route"
structure (breadcrumbs, page header, and Settings + Feeds tabs) with a
`d-table` feed list and dedicated FormKit new/edit routes, so the UI now
matches the rest of the admin interface and works on mobile. It also:

- Adds a **Test feed** dry-run that fetches a feed and previews which
items would be imported or skipped, with plain-language reasons, so
admins can validate a feed (and fix setup errors) before saving it.
- Adds the `rss_polling_feed_request_timeout` and
`rss_polling_verbose_logging` site settings.
- Extracts the fetch/parse and import/skip logic into `FeedFetcher` and
`FeedAnalyzer`, shared by the poll job and the new preview so the
dry-run and the real import always agree.
- Normalizes feed dates and categories so Atom feeds (which use
`<updated>` and `term`-style `<category>` elements) are handled like
RSS, and returns a clean error instead of a 500 when a feed cannot be
read.

---------

Co-authored-by: Martin Brennan <martin@discourse.org>
2026-07-02 07:40:25 +02:00

29 lines
820 B
Ruby
Vendored

# frozen_string_literal: true
module DiscourseRssPolling
module FeedUrl
CREDENTIAL_PARAMS = %w[api_key api_username]
HTTP_URL = %r{\Ahttps?://}i
def self.http?(url)
url.to_s.match?(HTTP_URL)
end
def self.redact(url)
split_credentials(url).first
end
# Returns [url_without_credentials, { "api_key" => ..., "api_username" => ... }].
def self.split_credentials(url)
uri = URI.parse(url.to_s.strip)
return url.to_s, {} if uri.query.blank?
params = CGI.parse(uri.query)
credentials = CREDENTIAL_PARAMS.to_h { |param| [param, params.delete(param)&.first] }
uri.query = params.empty? ? nil : URI.encode_www_form(params)
[uri.to_s, credentials]
rescue URI::InvalidURIError
[url.to_s.split("?", 2).first.to_s, {}]
end
end
end