mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-28 01:56:01 -05:00
113 lines
3.6 KiB
Ruby
113 lines
3.6 KiB
Ruby
|
require 'uri'
|
||
|
require_dependency 'slug'
|
||
|
|
||
|
class TopicLink < ActiveRecord::Base
|
||
|
|
||
|
belongs_to :topic
|
||
|
belongs_to :user
|
||
|
belongs_to :post
|
||
|
belongs_to :link_topic, class_name: 'Topic'
|
||
|
|
||
|
validates_presence_of :url
|
||
|
|
||
|
validates_length_of :url, maximum: 500
|
||
|
|
||
|
validates_uniqueness_of :url, scope: [:topic_id, :post_id]
|
||
|
|
||
|
has_many :topic_link_clicks
|
||
|
|
||
|
validate :link_to_self
|
||
|
|
||
|
# Make sure a topic can't link to itself
|
||
|
def link_to_self
|
||
|
errors.add(:base, "can't link to the same topic") if (topic_id == link_topic_id)
|
||
|
end
|
||
|
|
||
|
# Extract any urls in body
|
||
|
def self.extract_from(post)
|
||
|
return unless post.present?
|
||
|
|
||
|
TopicLink.transaction do
|
||
|
|
||
|
added_urls = []
|
||
|
reflected_urls = []
|
||
|
|
||
|
PrettyText
|
||
|
.extract_links(post.cooked)
|
||
|
.map{|u| [u, URI.parse(u)] rescue nil}
|
||
|
.reject{|u,p| p.nil?}
|
||
|
.uniq{|u,p| u}
|
||
|
.each do |url, parsed|
|
||
|
begin
|
||
|
|
||
|
internal = false
|
||
|
topic_id = nil
|
||
|
post_number = nil
|
||
|
if parsed.host == Discourse.current_hostname || !parsed.host
|
||
|
internal = true
|
||
|
|
||
|
route = Rails.application.routes.recognize_path(parsed.path)
|
||
|
topic_id = route[:topic_id]
|
||
|
post_number = route[:post_number] || 1
|
||
|
end
|
||
|
|
||
|
# Skip linking to ourselves
|
||
|
next if topic_id == post.topic_id
|
||
|
|
||
|
added_urls << url
|
||
|
TopicLink.create(post_id: post.id,
|
||
|
user_id: post.user_id,
|
||
|
topic_id: post.topic_id,
|
||
|
url: url,
|
||
|
domain: parsed.host || Discourse.current_hostname,
|
||
|
internal: internal,
|
||
|
link_topic_id: topic_id)
|
||
|
|
||
|
# Create the reflection if we can
|
||
|
if topic_id.present?
|
||
|
topic = Topic.where(id: topic_id).first
|
||
|
|
||
|
if topic && post.topic.archetype != 'private_message' && topic.archetype != 'private_message'
|
||
|
|
||
|
prefix = Discourse.base_url
|
||
|
|
||
|
reflected_post = nil
|
||
|
if post_number.present?
|
||
|
reflected_post = Post.where(topic_id: topic_id, post_number: post_number.to_i).first
|
||
|
end
|
||
|
|
||
|
reflected_url = "#{prefix}#{post.topic.relative_url(post.post_number)}"
|
||
|
|
||
|
reflected_urls << reflected_url
|
||
|
TopicLink.create(user_id: post.user_id,
|
||
|
topic_id: topic_id,
|
||
|
post_id: reflected_post.try(:id),
|
||
|
url: reflected_url,
|
||
|
domain: Discourse.current_hostname,
|
||
|
reflection: true,
|
||
|
internal: true,
|
||
|
link_topic_id: post.topic_id,
|
||
|
link_post_id: post.id)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
rescue URI::InvalidURIError
|
||
|
# if the URI is invalid, don't store it.
|
||
|
rescue ActionController::RoutingError
|
||
|
# If we can't find the route, no big deal
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Remove links that aren't there anymore
|
||
|
if added_urls.present?
|
||
|
TopicLink.delete_all ["(url not in (:urls)) AND (post_id = :post_id)", urls: added_urls, post_id: post.id]
|
||
|
TopicLink.delete_all ["(url not in (:urls)) AND (link_post_id = :post_id)", urls: reflected_urls, post_id: post.id]
|
||
|
else
|
||
|
TopicLink.delete_all ["post_id = :post_id OR link_post_id = :post_id", post_id: post.id]
|
||
|
end
|
||
|
|
||
|
end
|
||
|
end
|
||
|
|
||
|
end
|