discourse/app/models/permalink.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

155 lines
4.1 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
class Permalink < ActiveRecord::Base
attr_accessor :permalink_type, :permalink_type_value
belongs_to :topic
belongs_to :post
belongs_to :category
2020-05-25 17:48:54 +08:00
belongs_to :tag
2024-02-06 00:31:31 +08:00
belongs_to :user
before_validation :clear_associations
before_validation :normalize_url, :encode_url
before_validation :set_association_value
validates :url, uniqueness: true
validates :topic_id, presence: true, if: Proc.new { |permalink| permalink.topic_type? }
validates :post_id, presence: true, if: Proc.new { |permalink| permalink.post_type? }
validates :category_id, presence: true, if: Proc.new { |permalink| permalink.category_type? }
validates :tag_id, presence: true, if: Proc.new { |permalink| permalink.tag_type? }
validates :user_id, presence: true, if: Proc.new { |permalink| permalink.user_type? }
validates :external_url, presence: true, if: Proc.new { |permalink| permalink.external_url_type? }
%i[topic post category tag user external_url].each do |association|
define_method("#{association}_type?") { self.permalink_type == association.to_s }
end
class Normalizer
attr_reader :source
def initialize(source)
@source = source
@rules = source.split("|").map { |rule| parse_rule(rule) }.compact if source.present?
end
def parse_rule(rule)
return unless rule =~ %r{/.*/}
escaping = false
regex = +""
sub = +""
c = 0
rule.chars.each do |l|
c += 1 if !escaping && l == "/"
escaping = l == "\\"
if c > 1
sub << l
else
regex << l
end
end
[Regexp.new(regex[1..-1]), sub[1..-1] || ""] if regex.length > 1
end
def normalize(url)
return url unless @rules
@rules.each { |(regex, sub)| url = url.sub(regex, sub) }
url
end
end
def self.normalize_url(url)
if url
url = url.strip
url = url[1..-1] if url[0, 1] == "/"
end
normalizations = SiteSetting.permalink_normalizations
@normalizer = Normalizer.new(normalizations) unless @normalizer &&
@normalizer.source == normalizations
@normalizer.normalize(url)
end
def self.find_by_url(url)
find_by(url: normalize_url(url))
end
def target_url
return relative_external_url if external_url
return post.relative_url if post
return topic.relative_url if topic
return category.relative_url if category
return tag.relative_url if tag
return user.relative_url if user
nil
end
def self.filter_by(url = nil)
permalinks =
2024-02-06 00:31:31 +08:00
Permalink.includes(:topic, :post, :category, :tag, :user).order("permalinks.created_at desc")
permalinks.where!("url ILIKE :url OR external_url ILIKE :url", url: "%#{url}%") if url.present?
permalinks.limit!(100)
permalinks.to_a
end
private
def normalize_url
self.url = Permalink.normalize_url(url) if url
end
def encode_url
self.url = UrlHelper.encode(url) if url
end
def relative_external_url
external_url.match?(%r{\A/[^/]}) ? "#{Discourse.base_path}#{external_url}" : external_url
end
def clear_associations
self.topic_id = nil
self.post_id = nil
self.category_id = nil
self.user_id = nil
self.tag_id = nil
self.external_url = nil
end
def set_association_value
self.topic_id = self.permalink_type_value if self.topic_type?
self.post_id = self.permalink_type_value if self.post_type?
self.user_id = self.permalink_type_value if self.user_type?
self.category_id = self.permalink_type_value if self.category_type?
self.external_url = self.permalink_type_value if self.external_url_type?
self.tag_id = Tag.where(name: self.permalink_type_value).first&.id if self.tag_type?
end
end
# == Schema Information
#
# Table name: permalinks
#
# id :integer not null, primary key
# url :string(1000) not null
# topic_id :integer
# post_id :integer
# category_id :integer
2019-01-12 03:29:56 +08:00
# created_at :datetime not null
# updated_at :datetime not null
# external_url :string(1000)
2020-05-25 17:48:54 +08:00
# tag_id :integer
2024-02-06 00:31:31 +08:00
# user_id :integer
#
# Indexes
#
# index_permalinks_on_url (url) UNIQUE
#