mirror of
https://github.com/discourse/discourse.git
synced 2025-01-19 17:02:45 +08:00
6c8f491dc3
This targets only the local Oneboxes and allows plugins to customize regular or inline Oneboxes for routes inside the site.
128 lines
3.3 KiB
Ruby
128 lines
3.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class InlineOneboxer
|
|
|
|
MIN_TITLE_LENGTH = 2
|
|
|
|
def initialize(urls, opts = nil)
|
|
@urls = urls
|
|
@opts = opts || {}
|
|
end
|
|
|
|
def process
|
|
@urls.map { |url| InlineOneboxer.lookup(url, @opts) }.compact
|
|
end
|
|
|
|
def self.invalidate(url)
|
|
Discourse.cache.delete(cache_key(url))
|
|
end
|
|
|
|
def self.cache_lookup(url)
|
|
Discourse.cache.read(cache_key(url))
|
|
end
|
|
|
|
def self.local_handlers
|
|
@local_handlers ||= {}
|
|
end
|
|
|
|
def self.register_local_handler(controller, &handler)
|
|
local_handlers[controller] = handler
|
|
end
|
|
|
|
def self.lookup(url, opts = nil)
|
|
opts ||= {}
|
|
opts = opts.with_indifferent_access
|
|
|
|
unless opts[:skip_cache] || opts[:invalidate]
|
|
cached = cache_lookup(url)
|
|
return cached if cached.present?
|
|
end
|
|
|
|
return unless url
|
|
|
|
if route = Discourse.route_for(url)
|
|
if route[:controller] == "topics"
|
|
if topic = Oneboxer.local_topic(url, route, opts)
|
|
opts[:skip_cache] = true
|
|
post_number = [route[:post_number].to_i, topic.highest_post_number].min
|
|
if post_number > 1
|
|
opts[:post_number] = post_number
|
|
opts[:post_author] = post_author_for_title(topic, post_number)
|
|
end
|
|
return onebox_for(url, topic.title, opts)
|
|
else
|
|
# not permitted to see topic
|
|
return nil
|
|
end
|
|
elsif handler = local_handlers[route[:controller]]
|
|
return handler.call(url, route)
|
|
end
|
|
end
|
|
|
|
always_allow = SiteSetting.enable_inline_onebox_on_all_domains
|
|
allowed_domains = SiteSetting.allowed_inline_onebox_domains&.split('|') unless always_allow
|
|
|
|
if always_allow || allowed_domains
|
|
uri = begin
|
|
URI(url)
|
|
rescue URI::Error
|
|
end
|
|
|
|
if uri.present? &&
|
|
uri.hostname.present? &&
|
|
(always_allow || allowed_domains.include?(uri.hostname)) &&
|
|
!Onebox::DomainChecker.is_blocked?(uri.hostname)
|
|
if SiteSetting.block_onebox_on_redirect
|
|
max_redirects = 0
|
|
end
|
|
title = RetrieveTitle.crawl(
|
|
url,
|
|
max_redirects: max_redirects,
|
|
initial_https_redirect_ignore_limit: SiteSetting.block_onebox_on_redirect
|
|
)
|
|
title = nil if title && title.length < MIN_TITLE_LENGTH
|
|
return onebox_for(url, title, opts)
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
private
|
|
|
|
def self.onebox_for(url, title, opts)
|
|
title = title && Emoji.gsub_emoji_to_unicode(title)
|
|
if title && opts[:post_number]
|
|
title += " - "
|
|
if opts[:post_author]
|
|
title += I18n.t(
|
|
"inline_oneboxer.topic_page_title_post_number_by_user",
|
|
post_number: opts[:post_number],
|
|
username: opts[:post_author]
|
|
)
|
|
else
|
|
title += I18n.t(
|
|
"inline_oneboxer.topic_page_title_post_number",
|
|
post_number: opts[:post_number]
|
|
)
|
|
end
|
|
end
|
|
onebox = { url: url, title: title && Emoji.gsub_emoji_to_unicode(title) }
|
|
Discourse.cache.write(cache_key(url), onebox, expires_in: 1.day) if !opts[:skip_cache]
|
|
onebox
|
|
end
|
|
|
|
def self.cache_key(url)
|
|
"inline_onebox:#{url}"
|
|
end
|
|
|
|
def self.post_author_for_title(topic, post_number)
|
|
guardian = Guardian.new
|
|
post = topic.posts.find_by(post_number: post_number)
|
|
author = post&.user
|
|
if author && guardian.can_see_post?(post) && post.post_type == Post.types[:regular]
|
|
author.username
|
|
end
|
|
end
|
|
end
|