Skip to content

Commit

Permalink
New: can_see_groups? method for better perf
Browse files Browse the repository at this point in the history
  • Loading branch information
romanrizzi authored and tgxworld committed May 30, 2019
1 parent e7ee556 commit 2fa8df7
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 1 deletion.
2 changes: 1 addition & 1 deletion app/models/user_search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def initialize(term, opts = {})
@limit = opts[:limit] || 20
@groups = opts[:groups]
@guardian = Guardian.new(@searching_user)
@groups.each { |group| @guardian.ensure_can_see_group!(group) } if @groups
@guardian.ensure_can_see_groups!(@groups) if @groups
end

def scoped_users
Expand Down
19 changes: 19 additions & 0 deletions lib/guardian.rb
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,25 @@ def can_see_group?(group)
true
end

def can_see_groups?(groups)
return false if groups.blank?
return true if groups.all? { |g| g.visibility_level == Group.visibility_levels[:public] }
return true if is_admin?
return true if is_staff? && groups.all? { |g| g.visibility_level == Group.visibility_levels[:staff] }
return false if user.blank?

memberships = GroupUser.where(group: groups, user_id: user.id).pluck(:owner)

return false if memberships.empty? || memberships.length < groups.size

if !memberships.all?
return false if groups.all? { |g| g.visibility_level == Group.visibility_levels[:owners] }
return false if groups.all? { |g| g.visibility_level == Group.visibility_levels[:staff] }
end

true
end

# Can we impersonate this user?
def can_impersonate?(target)
target &&
Expand Down
109 changes: 109 additions & 0 deletions spec/components/guardian_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3038,6 +3038,115 @@

end

describe '#can_see_groups?' do
it 'correctly handles owner visibile groups' do
group = Group.new(name: 'group', visibility_level: Group.visibility_levels[:owners])

member = Fabricate(:user)
group.add(member)
group.save!

owner = Fabricate(:user)
group.add_owner(owner)
group.reload

expect(Guardian.new(admin).can_see_groups?([group])).to eq(true)
expect(Guardian.new(moderator).can_see_groups?([group])).to eq(false)
expect(Guardian.new(member).can_see_groups?([group])).to eq(false)
expect(Guardian.new.can_see_groups?([group])).to eq(false)
expect(Guardian.new(owner).can_see_groups?([group])).to eq(true)
end

it 'correctly handles the case where the user does not own every group' do
group = Group.new(name: 'group', visibility_level: Group.visibility_levels[:owners])
group2 = Group.new(name: 'group2', visibility_level: Group.visibility_levels[:owners])
group2.save!

member = Fabricate(:user)
group.add(member)
group.save!

owner = Fabricate(:user)
group.add_owner(owner)
group.reload

expect(Guardian.new(admin).can_see_groups?([group, group2])).to eq(true)
expect(Guardian.new(moderator).can_see_groups?([group, group2])).to eq(false)
expect(Guardian.new(member).can_see_groups?([group, group2])).to eq(false)
expect(Guardian.new.can_see_groups?([group, group2])).to eq(false)
expect(Guardian.new(owner).can_see_groups?([group, group2])).to eq(false)
end

it 'correctly handles staff visibile groups' do
group = Group.new(name: 'group', visibility_level: Group.visibility_levels[:staff])

member = Fabricate(:user)
group.add(member)
group.save!

owner = Fabricate(:user)
group.add_owner(owner)
group.reload

expect(Guardian.new(member).can_see_groups?([group])).to eq(false)
expect(Guardian.new(admin).can_see_groups?([group])).to eq(true)
expect(Guardian.new(moderator).can_see_groups?([group])).to eq(true)
expect(Guardian.new(owner).can_see_groups?([group])).to eq(true)
expect(Guardian.new.can_see_groups?([group])).to eq(false)
end

it 'correctly handles member visibile groups' do
group = Group.new(name: 'group', visibility_level: Group.visibility_levels[:members])

member = Fabricate(:user)
group.add(member)
group.save!

owner = Fabricate(:user)
group.add_owner(owner)
group.reload

expect(Guardian.new(moderator).can_see_groups?([group])).to eq(false)
expect(Guardian.new.can_see_groups?([group])).to eq(false)
expect(Guardian.new(admin).can_see_groups?([group])).to eq(true)
expect(Guardian.new(member).can_see_groups?([group])).to eq(true)
expect(Guardian.new(owner).can_see_groups?([group])).to eq(true)
end

it 'correctly handles the case where the user is not a member of every group' do
group1 = Group.new(name: 'group', visibility_level: Group.visibility_levels[:members])
group2 = Group.new(name: 'group2', visibility_level: Group.visibility_levels[:members])
group2.save!

member = Fabricate(:user)
group1.add(member)
group1.save!

owner = Fabricate(:user)
group1.add_owner(owner)
group1.reload

expect(Guardian.new(moderator).can_see_groups?([group1, group2])).to eq(false)
expect(Guardian.new.can_see_groups?([group1, group2])).to eq(false)
expect(Guardian.new(admin).can_see_groups?([group1, group2])).to eq(true)
expect(Guardian.new(member).can_see_groups?([group1, group2])).to eq(false)
expect(Guardian.new(owner).can_see_groups?([group1, group2])).to eq(false)
end

it 'correctly handles public groups' do
group = Group.new(name: 'group', visibility_level: Group.visibility_levels[:public])

expect(Guardian.new.can_see_groups?([group])).to eq(true)
end

it 'correctly handles there case where not every group is public' do
group1 = Group.new(name: 'group', visibility_level: Group.visibility_levels[:public])
group2 = Group.new(name: 'group', visibility_level: Group.visibility_levels[:private])

expect(Guardian.new.can_see_groups?([group1, group2])).to eq(false)
end
end

context 'topic featured link category restriction' do
before { SiteSetting.topic_featured_link_enabled = true }
let(:guardian) { Guardian.new }
Expand Down

0 comments on commit 2fa8df7

Please sign in to comment.