discourse/app/models/incoming_link.rb
Ted Johansson 25a226279a
DEV: Replace #pluck_first freedom patch with AR #pick in core (#19893)
The #pluck_first freedom patch, first introduced by @danielwaterworth has served us well, and is used widely throughout both core and plugins. It seems to have been a common enough use case that Rails 6 introduced it's own method #pick with the exact same implementation. This allows us to retire the freedom patch and switch over to the built-in ActiveRecord method.

There is no replacement for #pluck_first!, but a quick search shows we are using this in a very limited capacity, and in some cases incorrectly (by assuming a nil return rather than an exception), which can quite easily be replaced with #pick plus some extra handling.
2023-02-13 12:39:45 +08:00

134 lines
3.2 KiB
Ruby

# frozen_string_literal: true
class IncomingLink < ActiveRecord::Base
belongs_to :post
belongs_to :user
belongs_to :incoming_referer
validate :referer_valid
validates :post_id, presence: true
after_create :update_link_counts
attr_accessor :url
def self.add(opts)
user_id, host, referer = nil
current_user = opts[:current_user]
username = opts[:username]
username = nil if !(String === username)
username = nil if username&.include?("\0")
if username
u = User.select(:id).find_by(username_lower: username.downcase)
user_id = u.id if u
end
ip_address = opts[:ip_address]
if opts[:referer].present?
begin
host = URI.parse(opts[:referer]).host
referer = opts[:referer][0..999]
rescue URI::Error
# bad uri, skip
end
end
if host != opts[:host] && (user_id || referer)
post_id = opts[:post_id]
post_id ||=
Post.where(topic_id: opts[:topic_id], post_number: opts[:post_number] || 1).pick(:id)
cid = current_user ? (current_user.id) : (nil)
ip_address = nil if cid
unless cid && cid == user_id
if post_id
create(
referer: referer,
user_id: user_id,
post_id: post_id,
current_user_id: cid,
ip_address: ip_address,
)
end
end
end
end
def referer=(referer)
self.incoming_referer_id = nil
# will set incoming_referer_id
return unless referer.present?
parsed = URI.parse(referer)
if parsed.scheme == "http" || parsed.scheme == "https"
domain = IncomingDomain.add!(parsed)
referer_record = IncomingReferer.add!(path: parsed.path, incoming_domain: domain) if domain
self.incoming_referer_id = referer_record.id if referer_record
end
rescue URI::Error
# ignore
end
def referer
if self.incoming_referer
self.incoming_referer.incoming_domain.to_url + self.incoming_referer.path
end
end
def domain
incoming_referer.incoming_domain.name if incoming_referer
end
# Internal: Update appropriate link counts.
def update_link_counts
DB.exec(
"UPDATE topics
SET incoming_link_count = incoming_link_count + 1
WHERE id = (SELECT topic_id FROM posts where id = ?)",
post_id,
)
DB.exec(
"UPDATE posts
SET incoming_link_count = incoming_link_count + 1
WHERE id = ?",
post_id,
)
end
protected
def referer_valid
return true unless referer
if (referer.length < 3 || referer.length > 100) || (domain.length < 1 || domain.length > 100)
# internal, no need to localize
errors.add(:referer, "referer is invalid")
false
else
true
end
end
end
# == Schema Information
#
# Table name: incoming_links
#
# id :integer not null, primary key
# created_at :datetime not null
# user_id :integer
# ip_address :inet
# current_user_id :integer
# post_id :integer not null
# incoming_referer_id :integer
#
# Indexes
#
# index_incoming_links_on_created_at_and_user_id (created_at,user_id)
# index_incoming_links_on_post_id (post_id)
#