mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 14:03:22 +08:00
141 lines
3.7 KiB
Ruby
141 lines
3.7 KiB
Ruby
|
require 'open-uri'
|
||
|
|
||
|
require_dependency 'oneboxer/base'
|
||
|
require_dependency 'oneboxer/whitelist'
|
||
|
Dir["#{Rails.root}/lib/oneboxer/*_onebox.rb"].each {|f|
|
||
|
require_dependency(f.split('/')[-2..-1].join('/'))
|
||
|
}
|
||
|
|
||
|
module Oneboxer
|
||
|
extend Oneboxer::Base
|
||
|
|
||
|
Dir["#{Rails.root}/lib/oneboxer/*_onebox.rb"].each do |f|
|
||
|
add_onebox "Oneboxer::#{Pathname.new(f).basename.to_s.gsub(/\.rb$/, '').classify}".constantize
|
||
|
end
|
||
|
|
||
|
def self.default_expiry
|
||
|
1.month
|
||
|
end
|
||
|
|
||
|
# Return a oneboxer for a given URL
|
||
|
def self.onebox_for_url(url)
|
||
|
matchers.each do |regexp, oneboxer|
|
||
|
return oneboxer.new(url) if url =~ regexp
|
||
|
end
|
||
|
nil
|
||
|
end
|
||
|
|
||
|
# Retrieve the onebox for a url without caching
|
||
|
def self.onebox_nocache(url)
|
||
|
oneboxer = onebox_for_url(url)
|
||
|
return oneboxer.onebox if oneboxer.present?
|
||
|
|
||
|
if Whitelist.allowed?(url)
|
||
|
page_html = open(url).read
|
||
|
if page_html.present?
|
||
|
doc = Hpricot(page_html)
|
||
|
|
||
|
# See if if it has an oembed thing we can use
|
||
|
(doc/"link[@type='application/json+oembed']").each do |oembed|
|
||
|
return OembedOnebox.new(oembed[:href]).onebox
|
||
|
end
|
||
|
(doc/"link[@type='text/json+oembed']").each do |oembed|
|
||
|
return OembedOnebox.new(oembed[:href]).onebox
|
||
|
end
|
||
|
|
||
|
# Check for opengraph
|
||
|
open_graph = Oneboxer.parse_open_graph(doc)
|
||
|
return OpenGraphOnebox.new(url, open_graph).onebox if open_graph.present?
|
||
|
end
|
||
|
end
|
||
|
|
||
|
nil
|
||
|
end
|
||
|
|
||
|
# Parse URLs out of HTML, returning the document when finished.
|
||
|
def self.each_onebox_link(string_or_doc)
|
||
|
doc = string_or_doc
|
||
|
doc = Hpricot(doc) if doc.is_a?(String)
|
||
|
|
||
|
onebox_links = doc.search("a.onebox")
|
||
|
if onebox_links.present?
|
||
|
onebox_links.each do |link|
|
||
|
if link['href'].present?
|
||
|
yield link['href'], link
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
doc
|
||
|
end
|
||
|
|
||
|
def self.create_post_reference(result, args={})
|
||
|
result.post_onebox_renders.create(post_id: args[:post_id]) if args[:post_id].present?
|
||
|
rescue ActiveRecord::RecordNotUnique
|
||
|
end
|
||
|
|
||
|
def self.render_from_cache(url, args={})
|
||
|
result = OneboxRender.where(url: url).first
|
||
|
|
||
|
# Return the result but also create a reference to it
|
||
|
if result.present?
|
||
|
create_post_reference(result, args)
|
||
|
return result
|
||
|
end
|
||
|
nil
|
||
|
end
|
||
|
|
||
|
# Cache results from a onebox call
|
||
|
def self.fetch_and_cache(url, args)
|
||
|
cooked, preview = onebox_nocache(url)
|
||
|
return nil if cooked.blank?
|
||
|
|
||
|
# Store a cooked version in the database
|
||
|
OneboxRender.transaction do
|
||
|
begin
|
||
|
render = OneboxRender.create(url: url, preview: preview, cooked: cooked, expires_at: Oneboxer.default_expiry.from_now)
|
||
|
create_post_reference(render, args)
|
||
|
rescue ActiveRecord::RecordNotUnique
|
||
|
end
|
||
|
end
|
||
|
|
||
|
[cooked, preview]
|
||
|
end
|
||
|
|
||
|
# Retrieve a preview of a onebox, caching the result for performance
|
||
|
def self.preview(url, args={})
|
||
|
cached = render_from_cache(url, args) unless args[:no_cache].present?
|
||
|
|
||
|
# If we have a preview stored, return that. Otherwise return cooked content.
|
||
|
if cached.present?
|
||
|
return cached.preview if cached.preview.present?
|
||
|
return cached.cooked
|
||
|
end
|
||
|
cooked, preview = fetch_and_cache(url, args)
|
||
|
|
||
|
return preview if preview.present?
|
||
|
cooked
|
||
|
end
|
||
|
|
||
|
def self.invalidate(url)
|
||
|
OneboxRender.destroy_all(url: url)
|
||
|
end
|
||
|
|
||
|
# Return the cooked content for a url, caching the result for performance
|
||
|
def self.onebox(url, args={})
|
||
|
|
||
|
if args[:invalidate_oneboxes].present?
|
||
|
# Remove the onebox from the cache
|
||
|
Oneboxer.invalidate(url)
|
||
|
else
|
||
|
cached = render_from_cache(url, args) unless args[:no_cache].present?
|
||
|
return cached.cooked if cached.present?
|
||
|
end
|
||
|
|
||
|
|
||
|
cooked, preview = fetch_and_cache(url, args)
|
||
|
cooked
|
||
|
end
|
||
|
|
||
|
end
|