FIX: Check whether group is mentionable by user when cooking post.

This commit is contained in:
Guo Xiang Tan
2018-11-22 16:01:03 +08:00
parent 0739c3b1d1
commit 3f636b2d19
4 changed files with 70 additions and 14 deletions

View File

@ -132,16 +132,13 @@ class Group < ActiveRecord::Base
} }
scope :mentionable, lambda { |user| scope :mentionable, lambda { |user|
where(self.mentionable_sql_clause,
where("mentionable_level in (:levels) OR levels: alias_levels(user),
( user_id: user&.id
mentionable_level = #{ALIAS_LEVELS[:members_mods_and_admins]} AND id in ( )
SELECT group_id FROM group_users WHERE user_id = :user_id)
)", levels: alias_levels(user), user_id: user && user.id)
} }
scope :messageable, lambda { |user| scope :messageable, lambda { |user|
where("messageable_level in (:levels) OR where("messageable_level in (:levels) OR
( (
messageable_level = #{ALIAS_LEVELS[:members_mods_and_admins]} AND id in ( messageable_level = #{ALIAS_LEVELS[:members_mods_and_admins]} AND id in (
@ -149,6 +146,17 @@ class Group < ActiveRecord::Base
)", levels: alias_levels(user), user_id: user && user.id) )", levels: alias_levels(user), user_id: user && user.id)
} }
def self.mentionable_sql_clause
<<~SQL
mentionable_level in (:levels)
OR (
mentionable_level = #{ALIAS_LEVELS[:members_mods_and_admins]}
AND id in (
SELECT group_id FROM group_users WHERE user_id = :user_id)
)
SQL
end
def self.alias_levels(user) def self.alias_levels(user)
levels = [ALIAS_LEVELS[:everyone]] levels = [ALIAS_LEVELS[:everyone]]

View File

@ -264,7 +264,9 @@ module PrettyText
add_s3_cdn(doc) add_s3_cdn(doc)
end end
add_mentions(doc) if SiteSetting.enable_mentions if SiteSetting.enable_mentions
add_mentions(doc, user_id: opts[:user_id])
end
doc.to_html doc.to_html
end end
@ -425,11 +427,11 @@ module PrettyText
USER_TYPE ||= 'user' USER_TYPE ||= 'user'
GROUP_TYPE ||= 'group' GROUP_TYPE ||= 'group'
def self.add_mentions(doc) def self.add_mentions(doc, user_id: nil)
elements = doc.css("span.mention") elements = doc.css("span.mention")
names = elements.map { |element| element.text[1..-1] } names = elements.map { |element| element.text[1..-1] }
mentions = lookup_mentions(names) mentions = lookup_mentions(names, user_id: user_id)
doc.css("span.mention").each do |element| doc.css("span.mention").each do |element|
name = element.text[1..-1] name = element.text[1..-1]
@ -453,7 +455,7 @@ module PrettyText
end end
end end
def self.lookup_mentions(names) def self.lookup_mentions(names, user_id: nil)
sql = <<~SQL sql = <<~SQL
( (
SELECT SELECT
@ -468,14 +470,18 @@ module PrettyText
:group_type AS type, :group_type AS type,
name name
FROM groups FROM groups
WHERE name IN (:names) WHERE name IN (:names) AND (#{Group.mentionable_sql_clause})
) )
SQL SQL
user = User.find_by(id: user_id)
results = DB.query(sql, results = DB.query(sql,
names: names, names: names,
user_type: USER_TYPE, user_type: USER_TYPE,
group_type: GROUP_TYPE group_type: GROUP_TYPE,
levels: Group.alias_levels(user),
user_id: user_id
) )
mentions = {} mentions = {}

View File

@ -225,7 +225,9 @@ describe PrettyText do
Fabricate(:user, username: username) Fabricate(:user, username: username)
end end
group = Fabricate(:group) group = Fabricate(:group,
mentionable_level: Group::ALIAS_LEVELS[:everyone]
)
[ [
[ [
@ -241,6 +243,14 @@ describe PrettyText do
end end
end end
it "does not create mention for a non mentionable group" do
group = Fabricate(:group, mentionable_level: Group::ALIAS_LEVELS[:nobody])
expect(PrettyText.cook("test @#{group.name} test")).to eq(
%Q|<p>test <span class="mention">@#{group.name}</span> test</p>|
)
end
it 'does not mention staged users' do it 'does not mention staged users' do
user = Fabricate(:user, staged: true) user = Fabricate(:user, staged: true)

View File

@ -969,6 +969,38 @@ describe Post do
post.save post.save
expect(post.cooked).to match(/nofollow noopener/) expect(post.cooked).to match(/nofollow noopener/)
end end
describe 'mentions' do
let(:group) do
Fabricate(:group,
mentionable_level: Group::ALIAS_LEVELS[:members_mods_and_admins]
)
end
describe 'when user can not mention a group' do
it "should not create the mention" do
post = Fabricate(:post, raw: "hello @#{group.name}")
expect(post.cooked).to eq(
%Q|<p>hello <span class="mention">@#{group.name}</span></p>|
)
end
end
describe 'when user can mention a group' do
before do
group.add(post.user)
end
it 'should create the mention' do
post.update!(raw: "hello @#{group.name}")
expect(post.cooked).to eq(
%Q|<p>hello <a class="mention-group" href="/groups/#{group.name}">@#{group.name}</a></p>|
)
end
end
end
end end
describe "calculate_avg_time" do describe "calculate_avg_time" do