discourse/app/models/incoming_link.rb
Sam Saffron 30990006a9 DEV: enable frozen string literal on all files
This reduces chances of errors where consumers of strings mutate inputs
and reduces memory usage of the app.

Test suite passes now, but there may be some stuff left, so we will run
a few sites on a branch prior to merging
2019-05-13 09:31:32 +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)
.pluck(:id).first
cid = current_user ? (current_user.id) : (nil)
ip_address = nil if cid
unless cid && cid == user_id
create(referer: referer,
user_id: user_id,
post_id: post_id,
current_user_id: cid,
ip_address: ip_address) if post_id
end
end
end
def referer=(referer)
self.incoming_referer_id = nil
# will set incoming_referer_id
unless referer.present?
return
end
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
if incoming_referer
incoming_referer.incoming_domain.name
end
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)
#