discourse/lib/discourse_tagging.rb

117 lines
3.9 KiB
Ruby
Raw Normal View History

module DiscourseTagging
TAGS_FIELD_NAME = "tags"
TAGS_FILTER_REGEXP = /[<\\\/\>\#\?\&\s]/
# class Engine < ::Rails::Engine
# engine_name "discourse_tagging"
# isolate_namespace DiscourseTagging
# end
def self.clean_tag(tag)
tag.downcase.strip[0...SiteSetting.max_tag_length].gsub(TAGS_FILTER_REGEXP, '')
end
def self.staff_only_tags(tags)
return nil if tags.nil?
staff_tags = SiteSetting.staff_tags.split("|")
tag_diff = tags - staff_tags
tag_diff = tags - tag_diff
tag_diff.present? ? tag_diff : nil
end
def self.tags_for_saving(tags, guardian)
return [] unless guardian.can_tag_topics?
return unless tags.present?
tags.map! {|t| clean_tag(t) }
tags.delete_if {|t| t.blank? }
tags.uniq!
# If the user can't create tags, remove any tags that don't already exist
# TODO: this is doing a full count, it should just check first or use a cache
unless guardian.can_create_tag?
tag_count = TopicCustomField.where(name: TAGS_FIELD_NAME, value: tags).group(:value).count
tags.delete_if {|t| !tag_count.has_key?(t) }
end
return tags[0...SiteSetting.max_tags_per_topic]
end
def self.notification_key(tag_id)
"tags_notification:#{tag_id}"
end
def self.auto_notify_for(tags, topic)
# This insert will run up to SiteSetting.max_tags_per_topic times
tags.each do |tag|
key_name_sql = ActiveRecord::Base.sql_fragment("('#{notification_key(tag)}')", tag)
sql = <<-SQL
INSERT INTO topic_users(user_id, topic_id, notification_level, notifications_reason_id)
SELECT ucf.user_id,
#{topic.id.to_i},
CAST(ucf.value AS INTEGER),
#{TopicUser.notification_reasons[:plugin_changed]}
FROM user_custom_fields AS ucf
WHERE ucf.name IN #{key_name_sql}
AND NOT EXISTS(SELECT 1 FROM topic_users WHERE topic_id = #{topic.id.to_i} AND user_id = ucf.user_id)
AND CAST(ucf.value AS INTEGER) <> #{TopicUser.notification_levels[:regular]}
SQL
ActiveRecord::Base.exec_sql(sql)
end
end
def self.rename_tag(current_user, old_id, new_id)
sql = <<-SQL
UPDATE topic_custom_fields AS tcf
SET value = :new_id
WHERE value = :old_id
AND name = :tags_field_name
AND NOT EXISTS(SELECT 1
FROM topic_custom_fields
WHERE value = :new_id AND name = :tags_field_name AND topic_id = tcf.topic_id)
SQL
user_sql = <<-SQL
UPDATE user_custom_fields
SET name = :new_user_tag_id
WHERE name = :old_user_tag_id
AND NOT EXISTS(SELECT 1
FROM user_custom_fields
WHERE name = :new_user_tag_id)
SQL
ActiveRecord::Base.transaction do
ActiveRecord::Base.exec_sql(sql, new_id: new_id, old_id: old_id, tags_field_name: TAGS_FIELD_NAME)
TopicCustomField.delete_all(name: TAGS_FIELD_NAME, value: old_id)
ActiveRecord::Base.exec_sql(user_sql, new_user_tag_id: notification_key(new_id),
old_user_tag_id: notification_key(old_id))
UserCustomField.delete_all(name: notification_key(old_id))
StaffActionLogger.new(current_user).log_custom('renamed_tag', previous_value: old_id, new_value: new_id)
end
end
def self.top_tags(limit_arg=nil)
# TODO: cache
# TODO: need an index for this (name,value)
TopicCustomField.where(name: TAGS_FIELD_NAME)
.group(:value)
.limit(limit_arg || SiteSetting.max_tags_in_filter_list)
.order('COUNT(value) DESC')
.count
.map {|name, count| name}
end
def self.muted_tags(user)
return [] unless user
UserCustomField.where(user_id: user.id, value: TopicUser.notification_levels[:muted]).pluck(:name).map { |x| x[0,17] == "tags_notification" ? x[18..-1] : nil}.compact
end
end