discourse/spec/requests/groups_controller_spec.rb

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

2338 lines
72 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
describe GroupsController do
fab!(:user) { Fabricate(:user) }
fab!(:user2) { Fabricate(:user) }
fab!(:other_user) { Fabricate(:user) }
let(:group) { Fabricate(:group, users: [user]) }
let(:moderator_group_id) { Group::AUTO_GROUPS[:moderators] }
fab!(:admin) { Fabricate(:admin) }
fab!(:moderator) { Fabricate(:moderator) }
describe '#index' do
let(:staff_group) do
Fabricate(:group, name: 'staff_group', visibility_level: Group.visibility_levels[:staff])
end
2016-12-14 04:26:16 -05:00
2020-01-16 17:57:34 -05:00
it "ensures that groups can be paginated" do
50.times { Fabricate(:group) }
get "/groups.json"
expect(response.status).to eq(200)
body = response.parsed_body
2020-01-16 17:57:34 -05:00
expect(body["groups"].size).to eq(36)
expect(body["total_rows_groups"]).to eq(50)
expect(body["load_more_groups"]).to eq("/groups?page=1")
get "/groups.json", params: { page: 1 }
expect(response.status).to eq(200)
body = response.parsed_body
2020-01-16 17:57:34 -05:00
expect(body["groups"].size).to eq(14)
expect(body["total_rows_groups"]).to eq(50)
expect(body["load_more_groups"]).to eq("/groups?page=2")
end
context 'when group directory is disabled' do
before do
SiteSetting.enable_group_directory = false
end
it 'should deny access for an anon' do
get "/groups.json"
expect(response.status).to eq(403)
end
it 'should deny access for a normal user' do
sign_in(user)
get "/groups.json"
expect(response.status).to eq(403)
end
it 'should allow access for an admin' do
sign_in(admin)
get "/groups.json"
expect(response.status).to eq(200)
end
it 'should allow access for a moderator' do
sign_in(moderator)
get "/groups.json"
expect(response.status).to eq(200)
end
end
context 'searchable' do
it 'should return the searched groups' do
testing_group = Fabricate(:group, name: 'testing')
get "/groups.json", params: { filter: 'test' }
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["groups"].first["id"]).to eq(testing_group.id)
expect(body["load_more_groups"]).to eq("/groups?filter=test&page=1")
end
end
context 'sortable' do
before do
group
sign_in(user)
end
fab!(:other_group) { Fabricate(:group, name: "other_group", users: [user, other_user]) }
context "with default (descending) order" do
it "sorts by name" do
get "/groups.json", params: { order: "name" }
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["groups"].map { |g| g["id"] }).to eq([
other_group.id, group.id, moderator_group_id
])
expect(body["load_more_groups"]).to eq("/groups?order=name&page=1")
end
it "sorts by user_count" do
get "/groups.json", params: { order: "user_count" }
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["groups"].map { |g| g["id"] }).to eq([
other_group.id, group.id, moderator_group_id
])
expect(body["load_more_groups"]).to eq("/groups?order=user_count&page=1")
end
end
context "with ascending order" do
it "sorts by name" do
get "/groups.json", params: { order: "name", asc: true }
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["groups"].map { |g| g["id"] }).to eq([
moderator_group_id, group.id, other_group.id
])
expect(body["load_more_groups"]).to eq("/groups?asc=true&order=name&page=1")
end
it "sorts by user_count" do
get "/groups.json", params: { order: "user_count", asc: "true" }
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["groups"].map { |g| g["id"] }).to eq([
moderator_group_id, group.id, other_group.id
])
expect(body["load_more_groups"]).to eq("/groups?asc=true&order=user_count&page=1")
end
end
end
it 'should return the right response' do
group
staff_group
2016-12-14 04:26:16 -05:00
get "/groups.json"
expect(response.status).to eq(200)
2016-12-14 04:26:16 -05:00
body = response.parsed_body
2016-12-14 04:26:16 -05:00
group_ids = body["groups"].map { |g| g["id"] }
2016-12-14 04:26:16 -05:00
expect(group_ids).to contain_exactly(group.id)
expect(body["load_more_groups"]).to eq("/groups?page=1")
expect(body["total_rows_groups"]).to eq(1)
expect(body["extras"]["type_filters"].map(&:to_sym)).to eq(
described_class::TYPE_FILTERS.keys - [:my, :owner, :automatic, :non_automatic]
)
2016-12-14 04:26:16 -05:00
end
context 'viewing groups of another user' do
describe 'when an invalid username is given' do
it 'should return the right response' do
group
get "/groups.json", params: { username: 'asdasd' }
expect(response.status).to eq(404)
end
end
it 'should return the right response' do
u = Fabricate(:user)
m = Fabricate(:user)
o = Fabricate(:user)
levels = Group.visibility_levels.values
levels.product(levels).each { |group_level, members_level|
g = Fabricate(:group,
name: "#{group_level}_#{members_level}",
visibility_level: group_level,
members_visibility_level: members_level,
users: [u]
)
g.add(m) if group_level == Group.visibility_levels[:members] || members_level == Group.visibility_levels[:members]
g.add_owner(o) if group_level == Group.visibility_levels[:owners] || members_level == Group.visibility_levels[:owners]
}
# anonymous user
get "/groups.json", params: { username: u.username }
expect(response.status).to eq(200)
group_names = response.parsed_body["groups"].map { |g| g["name"] }
expect(group_names).to contain_exactly("0_0")
# logged in user
sign_in(user)
get "/groups.json", params: { username: u.username }
expect(response.status).to eq(200)
group_names = response.parsed_body["groups"].map { |g| g["name"] }
expect(group_names).to contain_exactly("0_0", "0_1", "1_0", "1_1")
# member of the group
sign_in(m)
get "/groups.json", params: { username: u.username }
expect(response.status).to eq(200)
group_names = response.parsed_body["groups"].map { |g| g["name"] }
expect(group_names).to contain_exactly("0_0", "0_1", "0_2", "1_0", "1_1", "1_2", "2_0", "2_1", "2_2")
# owner
sign_in(o)
get "/groups.json", params: { username: u.username }
expect(response.status).to eq(200)
group_names = response.parsed_body["groups"].map { |g| g["name"] }
expect(group_names).to contain_exactly("0_0", "0_1", "0_4", "1_0", "1_1", "1_4", "2_4", "3_4", "4_0", "4_1", "4_2", "4_3", "4_4")
# moderator
sign_in(moderator)
get "/groups.json", params: { username: u.username }
expect(response.status).to eq(200)
group_names = response.parsed_body["groups"].map { |g| g["name"] }
expect(group_names).to contain_exactly("0_0", "0_1", "0_2", "0_3", "1_0", "1_1", "1_2", "1_3", "2_0", "2_1", "2_2", "2_3", "3_0", "3_1", "3_2", "3_3")
# admin
sign_in(admin)
get "/groups.json", params: { username: u.username }
expect(response.status).to eq(200)
group_names = response.parsed_body["groups"].map { |g| g["name"] }
all_group_names = levels.product(levels).map { |a, b| "#{a}_#{b}" }
expect(group_names).to contain_exactly(*all_group_names)
end
end
context 'viewing as an admin' do
before do
2016-12-21 08:21:39 -05:00
sign_in(admin)
group.add(admin)
group.add_owner(admin)
end
it 'should return the right response' do
staff_group
get "/groups.json"
expect(response.status).to eq(200)
body = response.parsed_body
group_ids = body["groups"].map { |g| g["id"] }
group_body = body["groups"].find { |g| g["id"] == group.id }
expect(group_body["is_group_user"]).to eq(true)
expect(group_body["is_group_owner"]).to eq(true)
expect(group_ids).to include(group.id, staff_group.id)
expect(body["load_more_groups"]).to eq("/groups?page=1")
expect(body["total_rows_groups"]).to eq(10)
expect(body["extras"]["type_filters"].map(&:to_sym)).to eq(
described_class::TYPE_FILTERS.keys - [:non_automatic]
)
end
context 'filterable by type' do
def expect_type_to_return_right_groups(type, expected_group_ids)
get "/groups.json", params: { type: type }
expect(response.status).to eq(200)
body = response.parsed_body
group_ids = body["groups"].map { |g| g["id"] }
expect(body["total_rows_groups"]).to eq(expected_group_ids.count)
expect(group_ids).to contain_exactly(*expected_group_ids)
end
describe 'my groups' do
it 'should return the right response' do
expect_type_to_return_right_groups('my', [group.id])
end
end
describe 'owner groups' do
it 'should return the right response' do
group2 = Fabricate(:group)
_group3 = Fabricate(:group)
group2.add_owner(admin)
expect_type_to_return_right_groups('owner', [group.id, group2.id])
end
end
describe 'automatic groups' do
it 'should return the right response' do
expect_type_to_return_right_groups(
'automatic',
Group::AUTO_GROUP_IDS.keys - [0]
)
end
end
describe 'non automatic groups' do
it 'should return the right response' do
group2 = Fabricate(:group)
expect_type_to_return_right_groups(
'non_automatic',
[group.id, group2.id]
)
end
end
describe 'public groups' do
it 'should return the right response' do
group2 = Fabricate(:group, public_admission: true)
expect_type_to_return_right_groups('public', [group2.id])
end
end
describe 'close groups' do
it 'should return the right response' do
group2 = Fabricate(:group, public_admission: false)
_group3 = Fabricate(:group, public_admission: true)
expect_type_to_return_right_groups('close', [group.id, group2.id])
end
end
end
end
2016-12-14 04:26:16 -05:00
end
describe '#show' do
2018-03-29 02:57:10 -04:00
it "ensures the group can be seen" do
sign_in(user)
2018-03-29 02:57:10 -04:00
group.update!(visibility_level: Group.visibility_levels[:owners])
get "/groups/#{group.name}.json"
expect(response.status).to eq(404)
2018-03-29 02:57:10 -04:00
end
it "returns the right response" do
sign_in(user)
mod_group = Group.find(moderator_group_id)
2018-03-29 02:57:10 -04:00
get "/groups/#{group.name}.json"
expect(response.status).to eq(200)
body = response.parsed_body
2018-03-29 02:57:10 -04:00
expect(body['group']['id']).to eq(group.id)
expect(body['extras']["visible_group_names"]).to eq([mod_group.name, group.name])
expect(response.headers['X-Robots-Tag']).to eq('noindex')
2018-03-29 02:57:10 -04:00
end
it "returns the right response for 'messageable' field" do
sign_in(user)
group.update!(messageable_level: Group::ALIAS_LEVELS[:everyone])
get "/groups/#{group.name}.json"
expect(response.status).to eq(200)
expect(response.parsed_body['group']['messageable']).to eq(true)
SiteSetting.enable_personal_messages = false
get "/groups/#{group.name}.json"
expect(response.status).to eq(200)
expect(response.parsed_body['group']['messageable']).to eq(false)
end
2018-03-29 02:57:10 -04:00
context 'as an admin' do
it "returns the right response" do
sign_in(admin)
2018-03-29 02:57:10 -04:00
get "/groups/#{group.name}.json"
expect(response.status).to eq(200)
body = response.parsed_body
2018-03-29 02:57:10 -04:00
expect(body['group']['id']).to eq(group.id)
2018-03-29 02:57:10 -04:00
groups = Group::AUTO_GROUPS.keys
groups.delete(:everyone)
groups.push(group.name)
expect(body['extras']["visible_group_names"])
2018-03-29 02:57:10 -04:00
.to contain_exactly(*groups.map(&:to_s))
end
end
it 'should respond to HTML' do
group.update!(bio_raw: 'testing **group** bio')
get "/groups/#{group.name}.html"
expect(response.status).to eq(200)
expect(response.body).to have_tag "title", text: "#{group.name} - #{SiteSetting.title}"
expect(response.body).to have_tag(:meta, with: {
property: 'og:title', content: group.name
})
# note this uses an excerpt so it strips html
expect(response.body).to have_tag(:meta, with: {
property: 'og:description', content: 'testing group bio'
})
end
describe 'when viewing activity filters' do
it 'should return the right response' do
get "/groups/#{group.name}/activity/posts.json"
expect(response.status).to eq(200)
body = response.parsed_body['group']
expect(body["id"]).to eq(group.id)
end
end
end
2018-03-29 02:57:10 -04:00
describe "#posts" do
it "ensures the group can be seen" do
sign_in(user)
2018-03-29 02:57:10 -04:00
group.update!(visibility_level: Group.visibility_levels[:owners])
get "/groups/#{group.name}/posts.json"
expect(response.status).to eq(404)
2018-03-29 02:57:10 -04:00
end
it "ensures the group members can be seen" do
sign_in(user)
group.update!(members_visibility_level: Group.visibility_levels[:owners])
get "/groups/#{group.name}/posts.json"
expect(response.status).to eq(403)
end
2018-03-29 02:57:10 -04:00
it "calls `posts_for` and responds with JSON" do
sign_in(user)
post = Fabricate(:post, user: user)
get "/groups/#{group.name}/posts.json"
expect(response.status).to eq(200)
expect(response.parsed_body.first["id"]).to eq(post.id)
2018-03-29 02:57:10 -04:00
end
it "returns moderator actions" do
sign_in(user)
post = Fabricate(:post, user: user, post_type: Post.types[:moderator_action])
get "/groups/#{group.name}/posts.json"
expect(response.status).to eq(200)
expect(response.parsed_body.first["id"]).to eq(post.id)
end
2018-03-29 02:57:10 -04:00
end
describe "#members" do
it "returns correct error code with invalid params" do
sign_in(user)
get "/groups/#{group.name}/members.json?limit=-1"
expect(response.status).to eq(400)
get "/groups/#{group.name}/members.json?offset=-1"
expect(response.status).to eq(400)
get "/groups/trust_level_0/members.json?limit=2000"
expect(response.status).to eq(400)
end
2018-03-29 02:57:10 -04:00
it "ensures the group can be seen" do
sign_in(user)
2018-03-29 02:57:10 -04:00
group.update!(visibility_level: Group.visibility_levels[:owners])
get "/groups/#{group.name}/members.json"
expect(response.status).to eq(404)
2018-03-29 02:57:10 -04:00
end
it "ensures the group members can be seen" do
group.update!(members_visibility_level: Group.visibility_levels[:logged_on_users])
get "/groups/#{group.name}/members.json", params: { limit: 1 }
expect(response.status).to eq(403)
end
2018-03-29 02:57:10 -04:00
it "ensures that membership can be paginated" do
freeze_time
first_user = Fabricate(:user)
group.add(first_user)
freeze_time 1.day.from_now
4.times { group.add(Fabricate(:user)) }
2018-03-29 02:57:10 -04:00
usernames = group.users.map { |m| m.username }.sort
get "/groups/#{group.name}/members.json", params: { limit: 3, asc: true }
2018-03-29 02:57:10 -04:00
expect(response.status).to eq(200)
members = response.parsed_body["members"]
2018-03-29 02:57:10 -04:00
expect(members.map { |m| m['username'] }).to eq(usernames[0..2])
get "/groups/#{group.name}/members.json", params: { limit: 3, offset: 3, asc: true }
2018-03-29 02:57:10 -04:00
expect(response.status).to eq(200)
members = response.parsed_body["members"]
2018-03-29 02:57:10 -04:00
expect(members.map { |m| m['username'] }).to eq(usernames[3..5])
get "/groups/#{group.name}/members.json", params: { order: 'added_at' }
members = response.parsed_body["members"]
expect(members.last['added_at']).to eq(first_user.created_at.as_json)
2018-03-29 02:57:10 -04:00
end
it "can sort items" do
sign_in(user)
group.update!(visibility_level: Group.visibility_levels[:logged_on_users])
other_user = Fabricate(:user)
group.add_owner(other_user)
get "/groups/#{group.name}/members.json"
expect(response.parsed_body["members"].map { |u| u["id"] }).to eq([other_user.id, user.id])
expect(response.parsed_body["owners"].map { |u| u["id"] }).to eq([other_user.id])
get "/groups/#{group.name}/members.json?order=added_at&asc=1"
expect(response.parsed_body["members"].map { |u| u["id"] }).to eq([user.id, other_user.id])
expect(response.parsed_body["owners"].map { |u| u["id"] }).to eq([other_user.id])
end
2018-03-29 02:57:10 -04:00
end
describe '#posts_feed' do
it 'renders RSS' do
get "/groups/#{group.name}/posts.rss"
expect(response.status).to eq(200)
expect(response.media_type).to eq('application/rss+xml')
2018-03-29 02:57:10 -04:00
end
end
describe '#mentions_feed' do
it 'renders RSS' do
get "/groups/#{group.name}/mentions.rss"
expect(response.status).to eq(200)
expect(response.media_type).to eq('application/rss+xml')
2018-03-29 02:57:10 -04:00
end
it 'fails when disabled' do
SiteSetting.enable_mentions = false
get "/groups/#{group.name}/mentions.rss"
expect(response.status).to eq(404)
end
end
describe '#mentionable' do
it "should return the right response" do
sign_in(user)
group.update!(
mentionable_level: Group::ALIAS_LEVELS[:owners_mods_and_admins],
visibility_level: Group.visibility_levels[:logged_on_users]
)
get "/groups/#{group.name}/mentionable.json"
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["mentionable"]).to eq(false)
group.update!(
mentionable_level: Group::ALIAS_LEVELS[:everyone],
visibility_level: Group.visibility_levels[:staff]
)
get "/groups/#{group.name}/mentionable.json"
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["mentionable"]).to eq(true)
group.update!(
mentionable_level: Group::ALIAS_LEVELS[:nobody],
visibility_level: Group.visibility_levels[:public]
)
get "/groups/#{group.name}/mentionable.json"
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["mentionable"]).to eq(true)
end
end
describe '#messageable' do
it "should return the right response" do
sign_in(user)
get "/groups/#{group.name}/messageable.json"
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["messageable"]).to eq(false)
group.update!(
messageable_level: Group::ALIAS_LEVELS[:everyone],
visibility_level: Group.visibility_levels[:staff]
)
get "/groups/#{group.name}/messageable.json"
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["messageable"]).to eq(true)
SiteSetting.enable_personal_messages = false
get "/groups/#{group.name}/messageable.json"
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["messageable"]).to eq(false)
end
end
describe '#update' do
let!(:group) do
Fabricate(:group,
name: 'test',
users: [user],
public_admission: false,
public_exit: false
)
end
let(:category) { Fabricate(:category) }
let(:tag) { Fabricate(:tag) }
2016-12-06 23:06:56 -05:00
context "custom_fields" do
before do
user.update!(admin: true)
sign_in(user)
plugin = Plugin::Instance.new
plugin.register_editable_group_custom_field :test
@group = Fabricate(:group)
end
after do
DiscoursePluginRegistry.reset!
end
it "only updates allowed user fields" do
put "/groups/#{@group.id}.json", params: { group: { custom_fields: { test: :hello1, test2: :hello2 } } }
@group.reload
expect(response.status).to eq(200)
expect(@group.custom_fields['test']).to eq('hello1')
expect(@group.custom_fields['test2']).to be_blank
end
it "is secure when there are no registered editable fields" do
DiscoursePluginRegistry.reset!
put "/groups/#{@group.id}.json", params: { group: { custom_fields: { test: :hello1, test2: :hello2 } } }
@group.reload
expect(response.status).to eq(200)
expect(@group.custom_fields['test']).to be_blank
expect(@group.custom_fields['test2']).to be_blank
end
end
context "when user is group owner" do
before do
group.add_owner(user)
sign_in(user)
end
it "should be able update the group" do
group.update!(
allow_membership_requests: false,
visibility_level: 2,
mentionable_level: 2,
messageable_level: 2,
default_notification_level: 0,
grant_trust_level: 0
)
2016-12-11 10:36:15 -05:00
expect do
put "/groups/#{group.id}.json", params: {
group: {
mentionable_level: 1,
messageable_level: 1,
visibility_level: 1,
automatic_membership_email_domains: 'test.org',
title: 'haha',
primary_group: true,
grant_trust_level: 1,
incoming_email: 'test@mail.org',
flair_bg_color: 'FFF',
flair_color: 'BBB',
flair_icon: 'fa-adjust',
bio_raw: 'testing',
full_name: 'awesome team',
public_admission: true,
public_exit: true,
allow_membership_requests: true,
membership_request_template: 'testing',
default_notification_level: 1,
name: 'testing',
tracking_category_ids: [category.id],
tracking_tags: [tag.name]
},
update_existing_users: false
2016-12-11 10:36:15 -05:00
}
end.to change { GroupHistory.count }.by(13)
expect(response.status).to eq(200)
group.reload
expect(group.flair_bg_color).to eq('FFF')
expect(group.flair_color).to eq('BBB')
expect(group.flair_url).to eq('fa-adjust')
2016-12-05 03:18:24 -05:00
expect(group.bio_raw).to eq('testing')
2016-12-13 03:16:26 -05:00
expect(group.full_name).to eq('awesome team')
expect(group.public_admission).to eq(true)
expect(group.public_exit).to eq(true)
expect(group.allow_membership_requests).to eq(true)
expect(group.membership_request_template).to eq('testing')
expect(group.name).to eq('test')
expect(group.visibility_level).to eq(2)
expect(group.mentionable_level).to eq(1)
expect(group.messageable_level).to eq(1)
expect(group.default_notification_level).to eq(1)
expect(group.automatic_membership_email_domains).to eq(nil)
expect(group.title).to eq('haha')
expect(group.primary_group).to eq(false)
expect(group.incoming_email).to eq(nil)
expect(group.grant_trust_level).to eq(0)
expect(group.group_category_notification_defaults.first&.category).to eq(category)
expect(group.group_tag_notification_defaults.first&.tag).to eq(tag)
end
it 'should not be allowed to update automatic groups' do
group = Group.find(Group::AUTO_GROUPS[:admins])
put "/groups/#{group.id}.json", params: {
group: {
messageable_level: 1
}
}
expect(response.status).to eq(403)
end
end
context "when user is group admin" do
before do
user.update!(admin: true)
sign_in(user)
end
it 'should be able to update the group' do
group.update!(
visibility_level: 2,
members_visibility_level: 2,
grant_trust_level: 0
)
put "/groups/#{group.id}.json", params: {
group: {
flair_color: 'BBB',
name: 'testing',
incoming_email: 'test@mail.org',
primary_group: true,
automatic_membership_email_domains: 'test.org',
grant_trust_level: 2,
visibility_level: 1,
members_visibility_level: 3,
tracking_category_ids: [category.id],
tracking_tags: [tag.name]
},
update_existing_users: false
}
expect(response.status).to eq(200)
group.reload
expect(group.flair_color).to eq('BBB')
expect(group.name).to eq('testing')
expect(group.incoming_email).to eq("test@mail.org")
expect(group.primary_group).to eq(true)
expect(group.visibility_level).to eq(1)
expect(group.members_visibility_level).to eq(3)
expect(group.automatic_membership_email_domains).to eq('test.org')
expect(group.grant_trust_level).to eq(2)
expect(group.group_category_notification_defaults.first&.category).to eq(category)
expect(group.group_tag_notification_defaults.first&.tag).to eq(tag)
2018-04-06 05:11:00 -04:00
expect(Jobs::AutomaticGroupMembership.jobs.first["args"].first["group_id"])
.to eq(group.id)
end
it "should be able to update an automatic group" do
group = Group.find(Group::AUTO_GROUPS[:admins])
group.update!(
visibility_level: 2,
mentionable_level: 2,
messageable_level: 2,
default_notification_level: 2
)
put "/groups/#{group.id}.json", params: {
group: {
flair_bg_color: 'FFF',
flair_color: 'BBB',
flair_icon: 'fa-adjust',
name: 'testing',
visibility_level: 1,
mentionable_level: 1,
messageable_level: 1,
default_notification_level: 1,
tracking_category_ids: [category.id],
tracking_tags: [tag.name]
}
}
expect(response.status).to eq(200)
group.reload
expect(group.flair_bg_color).to eq('FFF')
expect(group.flair_color).to eq('BBB')
expect(group.flair_icon).to eq('fa-adjust')
expect(group.flair_url).to eq('fa-adjust')
expect(group.name).to eq('admins')
expect(group.visibility_level).to eq(1)
expect(group.mentionable_level).to eq(1)
expect(group.messageable_level).to eq(1)
expect(group.default_notification_level).to eq(1)
expect(group.group_category_notification_defaults.first&.category).to eq(category)
expect(group.group_tag_notification_defaults.first&.tag).to eq(tag)
end
it 'triggers a extensibility event' do
event = DiscourseEvent.track_events {
put "/groups/#{group.id}.json", params: { group: { flair_color: 'BBB' } }
}.last
expect(event[:event_name]).to eq(:group_updated)
expect(event[:params].first).to eq(group)
end
context "user default notifications" do
it "should update default notification preference for existing users" do
group.update!(default_notification_level: NotificationLevels.all[:watching])
user1 = Fabricate(:user)
group.add(user1)
group.add(user2)
group_user1 = user1.group_users.first
group_user2 = user2.group_users.first
put "/groups/#{group.id}.json", params: {
group: {
default_notification_level: NotificationLevels.all[:tracking]
}
}
expect(response.status).to eq(422)
expect(response.parsed_body["user_count"]).to eq(group.group_users.count)
expect(response.parsed_body["errors"].first).to include("update_existing_users")
expect(group_user1.reload.notification_level).to eq(NotificationLevels.all[:watching])
expect(group_user2.reload.notification_level).to eq(NotificationLevels.all[:watching])
group_user1.update!(notification_level: NotificationLevels.all[:regular])
put "/groups/#{group.id}.json", params: {
group: {
default_notification_level: NotificationLevels.all[:tracking]
}
}
expect(response.status).to eq(422)
expect(response.parsed_body["user_count"]).to eq(group.group_users.count - 1)
expect(group_user1.reload.notification_level).to eq(NotificationLevels.all[:regular])
expect(group_user2.reload.notification_level).to eq(NotificationLevels.all[:watching])
put "/groups/#{group.id}.json", params: {
group: {
default_notification_level: NotificationLevels.all[:tracking]
},
update_existing_users: true
}
expect(response.status).to eq(200)
expect(response.parsed_body["success"]).to eq("OK")
expect(group_user1.reload.notification_level).to eq(NotificationLevels.all[:regular])
expect(group_user2.reload.notification_level).to eq(NotificationLevels.all[:tracking])
put "/groups/#{group.id}.json", params: {
group: {
default_notification_level: NotificationLevels.all[:regular]
},
update_existing_users: false
}
expect(response.status).to eq(200)
expect(response.parsed_body["success"]).to eq("OK")
expect(group_user1.reload.notification_level).to eq(NotificationLevels.all[:regular])
expect(group_user2.reload.notification_level).to eq(NotificationLevels.all[:tracking])
end
it "should update category & tag notification preferences for existing users" do
user1 = Fabricate(:user)
CategoryUser.create!(user: user1, category: category, notification_level: 4)
TagUser.create!(user: user1, tag: tag, notification_level: 4)
TagUser.create!(user: user2, tag: tag, notification_level: 4)
group.add(user1)
group.add(user2)
put "/groups/#{group.id}.json", params: {
group: {
flair_color: 'BBB',
name: 'testing',
incoming_email: 'test@mail.org',
primary_group: true,
automatic_membership_email_domains: 'test.org',
grant_trust_level: 2,
visibility_level: 1,
members_visibility_level: 3,
tracking_category_ids: [category.id],
tracking_tags: [tag.name]
}
}
expect(response.status).to eq(422)
expect(response.parsed_body["user_count"]).to eq(group.group_users.count - 1)
put "/groups/#{group.id}.json", params: {
group: {
flair_color: 'BBB',
name: 'testing',
incoming_email: 'test@mail.org',
primary_group: true,
automatic_membership_email_domains: 'test.org',
grant_trust_level: 2,
visibility_level: 1,
members_visibility_level: 3,
tracking_category_ids: [category.id],
tracking_tags: [tag.name]
},
update_existing_users: true
}
expect(response.status).to eq(200)
expect(response.parsed_body["success"]).to eq("OK")
put "/groups/#{group.id}.json", params: {
group: {
flair_color: 'BBB',
name: 'testing',
incoming_email: 'test@mail.org',
primary_group: true,
automatic_membership_email_domains: 'test.org',
grant_trust_level: 2,
visibility_level: 1,
members_visibility_level: 3,
watching_category_ids: [category.id],
tracking_tags: [tag.name]
},
update_existing_users: true
}
expect(response.status).to eq(200)
expect(response.parsed_body["success"]).to eq("OK")
expect(CategoryUser.exists?(user: user2, category: category, notification_level: 3)).to be_truthy
end
end
end
context "when user is a site moderator" do
before do
SiteSetting.moderators_manage_categories_and_groups = true
sign_in(moderator)
end
it 'should not be able to update the group if the SiteSetting is false' do
SiteSetting.moderators_manage_categories_and_groups = false
put "/groups/#{group.id}.json", params: { group: { name: 'testing' } }
expect(response.status).to eq(403)
end
it 'should not be able to update a group it cannot see' do
group.update!(visibility_level: Group.visibility_levels[:owners])
put "/groups/#{group.id}.json", params: { group: { name: 'testing' } }
expect(response.status).to eq(403)
end
it 'should be able to update the group' do
put "/groups/#{group.id}.json", params: {
group: {
flair_color: 'BBB',
name: 'testing',
incoming_email: 'test@mail.org',
primary_group: true,
automatic_membership_email_domains: 'test.org',
grant_trust_level: 2,
visibility_level: 1,
members_visibility_level: 3,
tracking_category_ids: [category.id],
tracking_tags: [tag.name]
},
update_existing_users: false
}
expect(response.status).to eq(200)
group.reload
expect(group.flair_color).to eq('BBB')
expect(group.name).to eq('testing')
expect(group.incoming_email).to eq("test@mail.org")
expect(group.primary_group).to eq(true)
expect(group.visibility_level).to eq(1)
expect(group.members_visibility_level).to eq(3)
expect(group.automatic_membership_email_domains).to eq('test.org')
expect(group.grant_trust_level).to eq(2)
expect(group.group_category_notification_defaults.first&.category).to eq(category)
expect(group.group_tag_notification_defaults.first&.tag).to eq(tag)
expect(Jobs::AutomaticGroupMembership.jobs.first["args"].first["group_id"])
.to eq(group.id)
end
it "should be able to update an automatic group" do
group = Group.find(Group::AUTO_GROUPS[:trust_level_4])
group.update!(
mentionable_level: 2,
messageable_level: 2,
default_notification_level: 2
)
put "/groups/#{group.id}.json", params: {
group: {
flair_bg_color: 'FFF',
flair_color: 'BBB',
flair_icon: 'fa-adjust',
mentionable_level: 1,
messageable_level: 1,
default_notification_level: 1
}
}
expect(response.status).to eq(200)
group.reload
expect(group.flair_bg_color).to eq('FFF')
expect(group.flair_color).to eq('BBB')
expect(group.flair_icon).to eq('fa-adjust')
expect(group.flair_url).to eq('fa-adjust')
expect(group.name).to eq('trust_level_4')
expect(group.mentionable_level).to eq(1)
expect(group.messageable_level).to eq(1)
expect(group.default_notification_level).to eq(1)
end
it 'triggers a extensibility event' do
event = DiscourseEvent.track_events {
put "/groups/#{group.id}.json", params: { group: { flair_color: 'BBB' } }
}.last
expect(event[:event_name]).to eq(:group_updated)
expect(event[:params].first).to eq(group)
end
end
context "when user is not a group owner or admin" do
it 'should not be able to update the group' do
sign_in(user)
put "/groups/#{group.id}.json", params: { group: { name: 'testing' } }
expect(response.status).to eq(403)
end
end
end
describe '#members' do
let(:user1) do
Fabricate(:user,
last_seen_at: Time.zone.now,
last_posted_at: Time.zone.now - 1.day,
email: 'b@test.org'
)
end
let(:user2) do
Fabricate(:user,
last_seen_at: Time.zone.now - 1 .day,
last_posted_at: Time.zone.now,
email: 'a@test.org'
)
end
fab!(:user3) do
Fabricate(:user,
last_seen_at: nil,
last_posted_at: nil,
email: 'c@test.org'
)
end
fab!(:bot) { Fabricate(:user, id: -999) }
let(:group) { Fabricate(:group, users: [user1, user2, user3, bot]) }
it "should allow members to be sorted by" do
get "/groups/#{group.name}/members.json", params: {
order: 'last_seen_at'
}
expect(response.status).to eq(200)
members = response.parsed_body["members"]
expect(members.map { |m| m["id"] }).to eq([user1.id, user2.id, user3.id])
get "/groups/#{group.name}/members.json", params: { order: 'last_seen_at', asc: true }
expect(response.status).to eq(200)
members = response.parsed_body["members"]
expect(members.map { |m| m["id"] }).to eq([user2.id, user1.id, user3.id])
get "/groups/#{group.name}/members.json", params: {
order: 'last_posted_at'
}
expect(response.status).to eq(200)
members = response.parsed_body["members"]
expect(members.map { |m| m["id"] }).to eq([user2.id, user1.id, user3.id])
end
it "should not allow members to be sorted by columns that are not allowed" do
get "/groups/#{group.name}/members.json", params: { order: 'email' }
expect(response.status).to eq(200)
members = response.parsed_body["members"]
expect(members.map { |m| m["id"] })
.to contain_exactly(user1.id, user2.id, user3.id)
end
it "can show group requests" do
sign_in(admin)
user4 = Fabricate(:user)
request4 = Fabricate(:group_request, user: user4, group: group)
get "/groups/#{group.name}/members.json", params: { requesters: true }
members = response.parsed_body["members"]
expect(members.length).to eq(1)
expect(members.first["username"]).to eq(user4.username)
expect(members.first["reason"]).to eq(request4.reason)
end
describe 'filterable' do
describe 'as a normal user' do
it "should not allow members to be filterable by email" do
email = 'uniquetest@discourse.org'
user1.update!(email: email)
get "/groups/#{group.name}/members.json", params: { filter: email }
expect(response.status).to eq(200)
members = response.parsed_body["members"]
expect(members).to eq([])
end
end
describe 'as an admin' do
before do
sign_in(admin)
end
it "should allow members to be filterable by username" do
email = 'uniquetest@discourse.org'
user1.update!(email: email)
{
email.upcase => [user1.id],
'QUEtes' => [user1.id],
"#{user1.email},#{user2.email}" => [user1.id, user2.id]
}.each do |filter, ids|
get "/groups/#{group.name}/members.json", params: { filter: filter }
expect(response.status).to eq(200)
members = response.parsed_body["members"]
expect(members.map { |m| m["id"] }).to contain_exactly(*ids)
end
end
it "should allow members to be filterable by email" do
username = 'uniquetest'
user1.update!(username: username)
[username.upcase, 'QUEtes'].each do |filter|
get "/groups/#{group.name}/members.json", params: { filter: filter }
expect(response.status).to eq(200)
members = response.parsed_body["members"]
expect(members.map { |m| m["id"] }).to contain_exactly(user1.id)
end
end
end
end
end
2016-12-06 23:06:56 -05:00
describe "#edit" do
fab!(:group) { Fabricate(:group) }
2016-12-06 23:06:56 -05:00
context 'when user is not signed in' do
it 'should be forbidden' do
put "/groups/#{group.id}/members.json", params: { usernames: "bob" }
2016-12-06 23:06:56 -05:00
expect(response).to be_forbidden
delete "/groups/#{group.id}/members.json", params: { username: "bob" }
2016-12-06 23:06:56 -05:00
expect(response).to be_forbidden
end
context 'public group' do
it 'should be forbidden' do
group.update!(
public_admission: true,
public_exit: true
)
2016-12-06 23:06:56 -05:00
put "/groups/#{group.id}/members.json", params: { usernames: "bob" }
expect(response.status).to eq(403)
2016-12-06 23:06:56 -05:00
delete "/groups/#{group.id}/members.json", params: { username: "bob" }
expect(response.status).to eq(403)
2016-12-06 23:06:56 -05:00
end
end
end
context 'when user is not an owner of the group' do
before do
sign_in(user)
end
it "refuses membership changes to unauthorized users" do
put "/groups/#{group.id}/members.json", params: { usernames: "bob" }
2016-12-06 23:06:56 -05:00
expect(response).to be_forbidden
delete "/groups/#{group.id}/members.json", params: { username: "bob" }
2016-12-06 23:06:56 -05:00
expect(response).to be_forbidden
end
end
context 'when user is an admin' do
fab!(:group) { Fabricate(:group, users: [admin], automatic: true) }
2016-12-06 23:06:56 -05:00
before do
sign_in(admin)
2016-12-06 23:06:56 -05:00
end
it "cannot add members to automatic groups" do
put "/groups/#{group.id}/members.json", params: { usernames: "bob" }
2016-12-06 23:06:56 -05:00
expect(response).to be_forbidden
delete "/groups/#{group.id}/members.json", params: { username: "bob" }
2016-12-06 23:06:56 -05:00
expect(response).to be_forbidden
end
end
end
describe "membership edits" do
context '#add_members' do
before do
sign_in(admin)
end
2016-12-06 23:06:56 -05:00
it "can make incremental adds" do
2016-12-11 10:36:15 -05:00
expect do
put "/groups/#{group.id}/members.json", params: { usernames: user2.username }
2016-12-11 10:36:15 -05:00
end.to change { group.users.count }.by(1)
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(200)
2016-12-11 10:36:15 -05:00
group_history = GroupHistory.last
expect(group_history.action).to eq(GroupHistory.actions[:add_user_to_group])
expect(group_history.acting_user).to eq(admin)
expect(group_history.target_user).to eq(user2)
2016-12-06 23:06:56 -05:00
end
it "cannot add members to automatic groups" do
group.update!(automatic: true)
put "/groups/#{group.id}/members.json", params: { usernames: "l77t" }
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(403)
end
it "does not notify users when the param is not present" do
expect {
put "/groups/#{group.id}/members.json", params: { usernames: user2.username }
}.to change { Topic.where(archetype: "private_message").count }.by(0)
expect(response.status).to eq(200)
end
it "notifies users when the param is present" do
expect {
put "/groups/#{group.id}/members.json", params: { usernames: user2.username, notify_users: true }
}.to change { Topic.where(archetype: "private_message").count }.by(1)
expect(response.status).to eq(200)
expect(Topic.last.topic_users.map(&:user_id)).to include(Discourse::SYSTEM_USER_ID, user2.id)
end
it 'does not add users without sufficient permission' do
group.add_owner(user)
sign_in(user)
put "/groups/#{group.id}/members.json", params: { usernames: other_user.username }
expect(response.status).to eq(200)
end
it 'does not send invites if user cannot invite' do
group.add_owner(user)
sign_in(user)
put "/groups/#{group.id}/members.json", params: { emails: "test@example.com" }
expect(response.status).to eq(403)
end
2016-12-06 23:06:56 -05:00
context "is able to add several members to a group" do
fab!(:user1) { Fabricate(:user) }
fab!(:user2) { Fabricate(:user, username: "UsEr2") }
2016-12-06 23:06:56 -05:00
it "adds by username" do
expect do
put "/groups/#{group.id}/members.json",
params: { usernames: [user1.username, user2.username.upcase].join(",") }
end.to change { group.users.count }.by(2)
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(200)
2016-12-06 23:06:56 -05:00
end
it "adds by id" do
expect do
put "/groups/#{group.id}/members.json",
params: { user_ids: [user1.id, user2.id].join(",") }
end.to change { group.users.count }.by(2)
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(200)
2016-12-06 23:06:56 -05:00
end
it "adds by email" do
expect do
put "/groups/#{group.id}/members.json",
params: { user_emails: [user1.email, user2.email].join(",") }
end.to change { group.users.count }.by(2)
expect(response.status).to eq(200)
end
it 'adds missing users even if some exists' do
2018-03-27 05:14:06 -04:00
user2.update!(username: 'alice')
user3 = Fabricate(:user, username: 'bob')
[user2, user3].each { |user| group.add(user) }
expect do
put "/groups/#{group.id}/members.json",
params: { user_emails: [user1.email, user2.email, user3.email].join(",") }
end.to change { group.users.count }.by(1)
expect(response.status).to eq(200)
end
it 'sends invites to new users and ignores existing users' do
user1.update!(username: 'john')
user2.update!(username: 'alice')
[user1, user2].each { |user| group.add(user) }
emails = ["something@gmail.com", "anotherone@yahoo.com"]
put "/groups/#{group.id}/members.json",
params: { user_emails: [user1.email, user2.email].join(","), emails: emails.join(",") }
expect(response.status).to eq(200)
expect(response.parsed_body["emails"]).to eq(emails)
emails.each do |email|
invite = Invite.find_by(email: email)
expect(invite.groups).to eq([group])
end
end
it 'displays warning when all members already exists' do
user1.update!(username: 'john')
user2.update!(username: 'alice')
user3 = Fabricate(:user, username: 'bob')
[user1, user2, user3].each { |user| group.add(user) }
expect do
put "/groups/#{group.id}/members.json",
params: { user_emails: [user1.email, user2.email, user3.email].join(",") }
end.to change { group.users.count }.by(0)
expect(response.status).to eq(422)
expect(response.parsed_body["errors"]).to include(I18n.t(
"groups.errors.member_already_exist",
username: "alice, bob, john",
count: 3
))
end
it 'display error when try to add to many users at once' do
stub_const(GroupsController, "ADD_MEMBERS_LIMIT", 1) do
expect do
put "/groups/#{group.id}/members.json",
params: { user_emails: [user1.email, user2.email].join(",") }
end.to change { group.reload.users.count }.by(0)
expect(response.status).to eq(422)
expect(response.parsed_body["errors"]).to include(I18n.t(
"groups.errors.adding_too_many_users",
Fix i18n issues reported on Crowdin (#11747) * Pluralize `groups.errors.adding_too_many_users` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/248/en-ar#53882 * Pluralize `js.composer.error.title_too_short` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#41172 * Pluralize `js.composer.error.title_too_long` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#41174 * Pluralize `js.composer.error.post_length` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#41178 * Pluralize `js.topic.progress.jump_prompt_of` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#41958 * Use translations to join strings about posters This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/248/en-ar#49334 It also makes some changes to the crawler view: * Removes `poster.moreCount` which is only available on the client for PMs * CSS class names are actually stored in `poster.extras` instead of `poster.extraClasses` * Stop concatenating category stats This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#40740 * Pluralize `js.summary.description` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#40782 * Pluralize `js.summary.description_time_MF` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#40784 * Use translation to join list of tags This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#43372 * Pluralize `admin_js.admin.groups.manage.membership.automatic_membership_user_count` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#43720 * Pluralize `js.post.controls.delete_topic_confirm_modal` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#54804 * Stop concatenating `js.post.last_edited_on` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#42358 * Stop concatenating `js.post.wiki_last_edited_on` This fixes https://discourse.crowdin.com/translate/f3230e7607a36bb0a2f97fd90605a44e/246/en-ar#42356 It also fixes a regression because `js.post.wiki_last_edited_on` wasn't used anymore since 2017.
2021-02-02 04:50:04 -05:00
count: 1
))
end
end
2016-12-06 23:06:56 -05:00
end
it "returns 422 if member already exists" do
put "/groups/#{group.id}/members.json", params: { usernames: user.username }
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(422)
expect(response.parsed_body["errors"]).to include(I18n.t(
"groups.errors.member_already_exist",
username: user.username,
count: 1
))
2016-12-06 23:06:56 -05:00
end
it "returns 400 if member is not found" do
[
{ usernames: "some thing" },
{ user_ids: "-5,-6" },
{ user_emails: "some@test.org" }
].each do |params|
put "/groups/#{group.id}/members.json", params: params
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(400)
body = response.parsed_body
expect(body["error_type"]).to eq("invalid_parameters")
end
2016-12-06 23:06:56 -05:00
end
it "return a 400 if no user or emails are present" do
[
{ usernames: "nouserwiththisusername", emails: "" },
{ usernames: "", emails: "" }
].each do |params|
put "/groups/#{group.id}/members.json", params: params
expect(response.status).to eq(400)
body = response.parsed_body
expect(body["error_type"]).to eq("invalid_parameters")
end
end
it "will send invites to each email with group_id set" do
emails = ["something@gmail.com", "anotherone@yahoo.com"]
put "/groups/#{group.id}/members.json", params: { emails: emails.join(",") }
expect(response.status).to eq(200)
body = response.parsed_body
expect(body["emails"]).to eq(emails)
emails.each do |email|
invite = Invite.find_by(email: email)
expect(invite.groups).to eq([group])
end
end
it "adds known users by email when DiscourseConnect is enabled" do
SiteSetting.discourse_connect_url = "https://www.example.com/sso"
SiteSetting.enable_discourse_connect = true
expect do
put "/groups/#{group.id}/members.json", params: { emails: other_user.email }
end.to change { group.users.count }.by(1)
expect(response.status).to eq(200)
end
it "will find users by email, and invite the correct user" do
new_user = Fabricate(:user)
expect(new_user.group_ids.include?(group.id)).to eq(false)
put "/groups/#{group.id}/members.json", params: { emails: new_user.email }
expect(new_user.reload.group_ids.include?(group.id)).to eq(true)
end
it "will invite the user if their username and email are both invited" do
new_user = Fabricate(:user)
put "/groups/#{group.id}/members.json", params: { usernames: new_user.username, emails: new_user.email }
expect(response.status).to eq(200)
expect(new_user.reload.group_ids.include?(group.id)).to eq(true)
end
2016-12-06 23:06:56 -05:00
context 'public group' do
before do
group.update!(
public_admission: true,
public_exit: true
)
2016-12-06 23:06:56 -05:00
end
context 'admin' do
it "can make incremental adds" do
expect do
put "/groups/#{group.id}/members.json",
params: { usernames: other_user.username }
end.to change { group.users.count }.by(1)
expect(response.status).to eq(200)
group_history = GroupHistory.last
expect(group_history.action).to eq(GroupHistory.actions[:add_user_to_group])
expect(group_history.acting_user).to eq(admin)
expect(group_history.target_user).to eq(other_user)
end
end
end
end
context '#join' do
let(:public_group) { Fabricate(:public_group) }
2016-12-06 23:06:56 -05:00
it 'should allow a user to join a public group' do
sign_in(user)
2016-12-06 23:06:56 -05:00
expect do
put "/groups/#{public_group.id}/join.json"
end.to change { public_group.users.count }.by(1)
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(204)
end
it 'should not allow a user to join a nonpublic group' do
sign_in(user)
2016-12-06 23:06:56 -05:00
expect do
put "/groups/#{group.id}/join.json"
end.not_to change { group.users.count }
expect(response).to be_forbidden
end
it 'should not allow an anonymous user to call the join method' do
expect do
put "/groups/#{group.id}/join.json"
end.not_to change { group.users.count }
expect(response).to be_forbidden
end
it 'the join method is idempotent' do
sign_in(user)
expect do
put "/groups/#{public_group.id}/join.json"
end.to change { public_group.users.count }.by(1)
expect(response.status).to eq(204)
expect do
put "/groups/#{public_group.id}/join.json"
end.not_to change { public_group.users.count }
expect(response.status).to eq(204)
expect do
put "/groups/#{public_group.id}/join.json"
end.not_to change { public_group.users.count }
expect(response.status).to eq(204)
2016-12-06 23:06:56 -05:00
end
end
context '#remove_member' do
before do
sign_in(admin)
end
2016-12-06 23:06:56 -05:00
it "cannot remove members from automatic groups" do
group.update!(automatic: true)
delete "/groups/#{group.id}/members.json", params: { user_id: 42 }
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(403)
end
it "raises an error if user to be removed is not found" do
delete "/groups/#{group.id}/members.json", params: { user_id: -10 }
expect(response.status).to eq(400)
2016-12-06 23:06:56 -05:00
end
it "returns skipped_usernames response body when removing a valid user but is not a member of that group" do
delete "/groups/#{group.id}/members.json", params: { user_id: -1 }
response_body = response.parsed_body
expect(response.status).to eq(200)
expect(response_body["usernames"]).to eq([])
expect(response_body["skipped_usernames"].first).to eq("system")
end
2016-12-06 23:06:56 -05:00
context "is able to remove a member" do
it "removes by id" do
expect do
delete "/groups/#{group.id}/members.json", params: { user_id: user.id }
end.to change { group.users.count }.by(-1)
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(200)
2016-12-06 23:06:56 -05:00
end
it "removes by id with integer in json" do
expect do
headers = { "CONTENT_TYPE": "application/json" }
delete "/groups/#{group.id}/members.json", params: "{\"user_id\":#{user.id}}", headers: headers
end.to change { group.users.count }.by(-1)
expect(response.status).to eq(200)
end
2016-12-06 23:06:56 -05:00
it "removes by username" do
expect do
delete "/groups/#{group.id}/members.json", params: { username: user.username }
end.to change { group.users.count }.by(-1)
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(200)
2016-12-06 23:06:56 -05:00
end
it "removes user.primary_group_id when user is removed from group" do
user.update!(primary_group_id: group.id)
delete "/groups/#{group.id}/members.json", params: { user_id: user.id }
2016-12-06 23:06:56 -05:00
expect(user.reload.primary_group_id).to eq(nil)
end
it "removes by user_email" do
expect do
delete "/groups/#{group.id}/members.json",
params: { user_email: user.email }
end.to change { group.users.count }.by(-1)
2016-12-06 23:06:56 -05:00
expect(response.status).to eq(200)
2016-12-06 23:06:56 -05:00
end
context 'public group' do
let(:group) { Fabricate(:public_group, users: [other_user]) }
2016-12-06 23:06:56 -05:00
context "admin" do
it "removes by username" do
expect do
delete "/groups/#{group.id}/members.json",
params: { username: other_user.username }
end.to change { group.users.count }.by(-1)
expect(response.status).to eq(200)
end
end
it 'should not allow a underprivileged user to leave a group for another user' do
sign_in(user)
delete "/groups/#{group.id}/members.json",
params: { username: other_user.username }
2016-12-06 23:06:56 -05:00
expect(response).to be_forbidden
end
end
end
context '#remove_members' do
context "is able to remove several members from a group" do
fab!(:user1) { Fabricate(:user) }
fab!(:user2) { Fabricate(:user, username: "UsEr2") }
let(:group1) { Fabricate(:group, users: [user1, user2]) }
it "removes by username" do
expect do
delete "/groups/#{group1.id}/members.json",
params: { usernames: [user1.username, user2.username.upcase].join(",") }
end.to change { group1.users.count }.by(-2)
expect(response.status).to eq(200)
end
it "removes by id" do
expect do
delete "/groups/#{group1.id}/members.json",
params: { user_ids: [user1.id, user2.id].join(",") }
end.to change { group1.users.count }.by(-2)
expect(response.status).to eq(200)
end
it "removes by id with integer in json" do
expect do
headers = { "CONTENT_TYPE": "application/json" }
delete "/groups/#{group1.id}/members.json", params: "{\"user_ids\":#{user1.id}}", headers: headers
end.to change { group1.users.count }.by(-1)
expect(response.status).to eq(200)
end
it "removes by email" do
expect do
delete "/groups/#{group1.id}/members.json",
params: { user_emails: [user1.email, user2.email].join(",") }
end.to change { group1.users.count }.by(-2)
expect(response.status).to eq(200)
end
it "only removes users in that group" do
delete "/groups/#{group1.id}/members.json",
params: { usernames: [user.username, user2.username].join(",") }
response_body = response.parsed_body
expect(response.status).to eq(200)
expect(response_body["usernames"].first).to eq(user2.username)
expect(response_body["skipped_usernames"].first).to eq(user.username)
end
end
end
2016-12-06 23:06:56 -05:00
end
context '#leave' do
let(:group_with_public_exit) { Fabricate(:group, public_exit: true, users: [user]) }
it 'should allow a user to leave a group with public exit' do
sign_in(user)
expect do
delete "/groups/#{group_with_public_exit.id}/leave.json"
end.to change { group_with_public_exit.users.count }.by(-1)
expect(response.status).to eq(204)
end
it 'should not allow a user to leave a group without public exit' do
sign_in(user)
expect do
delete "/groups/#{group.id}/leave.json"
end.not_to change { group.users.count }
expect(response).to be_forbidden
end
it 'should not allow an anonymous user to call the leave method' do
expect do
delete "/groups/#{group_with_public_exit.id}/leave.json"
end.not_to change { group_with_public_exit.users.count }
expect(response).to be_forbidden
end
it 'the leave method is idempotent' do
sign_in(user)
expect do
delete "/groups/#{group_with_public_exit.id}/leave.json"
end.to change { group_with_public_exit.users.count }.by(-1)
expect(response.status).to eq(204)
expect do
delete "/groups/#{group_with_public_exit.id}/leave.json"
end.not_to change { group_with_public_exit.users.count }
expect(response.status).to eq(204)
expect do
delete "/groups/#{group_with_public_exit.id}/leave.json"
end.not_to change { group_with_public_exit.users.count }
expect(response.status).to eq(204)
end
end
2016-12-06 23:06:56 -05:00
end
2016-12-11 10:36:15 -05:00
describe "#handle_membership_request" do
before do
group.add_owner(user)
sign_in(user)
end
it "sends a private message when accepted" do
GroupRequest.create!(group: group, user: other_user)
expect { put "/groups/#{group.id}/handle_membership_request.json", params: { user_id: other_user.id, accept: true } }
.to change { Topic.count }.by(1)
.and change { Post.count }.by(1)
topic = Topic.last
expect(topic.archetype).to eq(Archetype.private_message)
expect(topic.title).to eq(I18n.t('groups.request_accepted_pm.title', group_name: group.name))
expect(topic.first_post.raw).to eq(I18n.t('groups.request_accepted_pm.body', group_name: group.name).strip)
end
end
describe "#histories" do
2016-12-11 10:36:15 -05:00
context 'when user is not signed in' do
it 'should raise the right error' do
get "/groups/#{group.name}/logs.json"
expect(response.status).to eq(403)
2016-12-11 10:36:15 -05:00
end
end
context 'when user is not a group owner' do
before do
sign_in(user)
end
it 'should be forbidden' do
get "/groups/#{group.name}/logs.json"
2016-12-11 10:36:15 -05:00
expect(response).to be_forbidden
end
end
describe 'when user is a group owner' do
before do
group.add_owner(user)
sign_in(user)
end
describe 'when viewing a public group' do
before do
group.update!(
public_admission: true,
public_exit: true
)
2016-12-11 10:36:15 -05:00
GroupActionLogger.new(user, group).log_change_group_settings
end
it 'should allow group owner to view history' do
get "/groups/#{group.name}/logs.json"
2016-12-11 10:36:15 -05:00
expect(response.status).to eq(200)
2016-12-11 10:36:15 -05:00
result = response.parsed_body["logs"].find { |entry| entry["subject"] == "public_exit" }
2016-12-11 10:36:15 -05:00
expect(result["action"]).to eq(GroupHistory.actions[1].to_s)
expect(result["subject"]).to eq('public_exit')
2016-12-11 10:36:15 -05:00
expect(result["prev_value"]).to eq('f')
expect(result["new_value"]).to eq('t')
end
end
it 'should not be allowed to view history of an automatic group' do
group = Group.find_by(id: Group::AUTO_GROUPS[:admins])
2016-12-11 10:36:15 -05:00
get "/groups/#{group.name}/logs.json"
2016-12-11 10:36:15 -05:00
expect(response.status).to eq(403)
end
end
2016-12-11 10:36:15 -05:00
context 'when user is an admin' do
before do
sign_in(admin)
end
2016-12-11 10:36:15 -05:00
it 'should be able to view history' do
GroupActionLogger.new(admin, group).log_remove_user_from_group(user)
2016-12-11 10:36:15 -05:00
get "/groups/#{group.name}/logs.json"
2016-12-11 10:36:15 -05:00
expect(response.status).to eq(200)
2016-12-11 10:36:15 -05:00
result = response.parsed_body["logs"].first
2016-12-11 10:36:15 -05:00
expect(result["action"]).to eq(GroupHistory.actions[3].to_s)
end
2016-12-11 10:36:15 -05:00
it 'should be able to view history of automatic groups' do
group = Group.find_by(id: Group::AUTO_GROUPS[:admins])
2016-12-11 10:36:15 -05:00
get "/groups/#{group.name}/logs.json"
expect(response.status).to eq(200)
end
it 'should be able to filter through the history' do
GroupActionLogger.new(admin, group).log_add_user_to_group(user)
GroupActionLogger.new(admin, group).log_remove_user_from_group(user)
get "/groups/#{group.name}/logs.json", params: {
filters: { "action" => "add_user_to_group" }
}
expect(response.status).to eq(200)
logs = response.parsed_body["logs"]
expect(logs.count).to eq(1)
expect(logs.first["action"]).to eq(GroupHistory.actions[2].to_s)
2016-12-11 10:36:15 -05:00
end
end
end
describe '#request_membership' do
fab!(:new_user) { Fabricate(:user) }
it 'requires the user to log in' do
post "/groups/#{group.name}/request_membership.json"
expect(response.status).to eq(403)
end
it 'requires a reason' do
sign_in(user)
post "/groups/#{group.name}/request_membership.json"
expect(response.status).to eq(400)
end
it 'checks for duplicates' do
sign_in(user)
post "/groups/#{group.name}/request_membership.json",
params: { reason: 'Please add me in' }
expect(response.status).to eq(200)
post "/groups/#{group.name}/request_membership.json",
params: { reason: 'Please add me in' }
expect(response.status).to eq(409)
end
it 'should create the right PM' do
owner1 = Fabricate(:user, last_seen_at: Time.zone.now)
owner2 = Fabricate(:user, last_seen_at: Time.zone.now - 1 .day)
[owner1, owner2].each { |owner| group.add_owner(owner) }
sign_in(user)
post "/groups/#{group.name}/request_membership.json",
params: { reason: 'Please add me in' }
expect(response.status).to eq(200)
post = Post.last
topic = post.topic
body = response.parsed_body
expect(body['relative_url']).to eq(topic.relative_url)
expect(post.topic.custom_fields['requested_group_id'].to_i).to eq(group.id)
expect(post.user).to eq(user)
expect(topic.title).to eq(I18n.t('groups.request_membership_pm.title',
group_name: group.name
))
expect(post.raw).to start_with('Please add me in')
expect(topic.archetype).to eq(Archetype.private_message)
expect(topic.allowed_users).to contain_exactly(user, owner1, owner2)
expect(topic.allowed_groups).to eq([])
end
end
describe '#search ' do
fab!(:hidden_group) do
Fabricate(:group,
visibility_level: Group.visibility_levels[:owners],
name: 'KingOfTheNorth'
)
end
before do
group.update!(
name: 'GOT',
full_name: 'Daenerys Targaryen',
visibility_level: Group.visibility_levels[:logged_on_users]
)
hidden_group
end
context 'as an anon user' do
it "returns the right response" do
get '/groups/search.json'
expect(response.status).to eq(403)
end
end
context 'as a normal user' do
it "returns the right response" do
sign_in(user)
get '/groups/search.json'
expect(response.status).to eq(200)
groups = response.parsed_body
expected_ids = Group::AUTO_GROUPS.map { |name, id| id }
expected_ids.delete(Group::AUTO_GROUPS[:everyone])
expected_ids << group.id
expect(groups.map { |group| group["id"] }).to contain_exactly(*expected_ids)
['GO', 'nerys'].each do |term|
get "/groups/search.json?term=#{term}"
expect(response.status).to eq(200)
groups = response.parsed_body
expect(groups.length).to eq(1)
expect(groups.first['id']).to eq(group.id)
end
get "/groups/search.json?term=KingOfTheNorth"
expect(response.status).to eq(200)
groups = response.parsed_body
expect(groups).to eq([])
end
end
context 'as a group owner' do
before do
hidden_group.add_owner(user)
end
it "returns the right response" do
sign_in(user)
get "/groups/search.json?term=north"
expect(response.status).to eq(200)
groups = response.parsed_body
expect(groups.length).to eq(1)
expect(groups.first['id']).to eq(hidden_group.id)
end
end
context 'as an admin' do
it "returns the right response" do
sign_in(admin)
get '/groups/search.json?ignore_automatic=true'
expect(response.status).to eq(200)
groups = response.parsed_body
expect(groups.length).to eq(2)
expect(groups.map { |group| group['id'] })
.to contain_exactly(group.id, hidden_group.id)
end
end
end
describe '#new' do
describe 'for an anon user' do
it 'should return 404' do
get '/groups/custom/new'
expect(response.status).to eq(404)
end
end
describe 'for a normal user' do
before { sign_in(user) }
it 'should return 404' do
get '/groups/custom/new'
expect(response.status).to eq(404)
end
end
describe 'for an admin user' do
before { sign_in(admin) }
it 'should return 200' do
get '/groups/custom/new'
expect(response.status).to eq(200)
end
end
end
describe '#check_name' do
describe 'for an anon user' do
it 'should return the right response' do
get "/groups/check-name.json", params: { group_name: 'test' }
expect(response.status).to eq(403)
end
end
it 'should return the right response' do
sign_in(Fabricate(:user))
SiteSetting.reserved_usernames = 'test|donkey'
get "/groups/check-name.json", params: { group_name: 'test' }
expect(response.status).to eq(200)
expect(response.parsed_body["available"]).to eq(true)
end
end
describe "#permissions" do
before do
sign_in(other_user)
end
it "ensures the group can be seen" do
group.update!(visibility_level: Group.visibility_levels[:owners])
get "/groups/#{group.name}/permissions.json"
expect(response.status).to eq(404)
end
describe "with varying category permissions" do
fab!(:category) { Fabricate(:category) }
before do
category.set_permissions("#{group.name}": :full)
category.save!
end
it "does not return categories the user cannot see" do
get "/groups/#{group.name}/permissions.json"
expect(response.status).to eq(200)
expect(response.parsed_body).to eq([])
end
it "returns categories the user can see" do
group.add(other_user)
get "/groups/#{group.name}/permissions.json"
expect(response.status).to eq(200)
expect(response.parsed_body.count).to eq(1)
expect(response.parsed_body.first["category"]["id"]).to eq(category.id)
end
end
it "returns categories alphabetically" do
sign_in(user)
["Three", "New Cat", "Abc", "Hello"].each do |name|
category = Fabricate(:category, name: name)
category.set_permissions("#{group.name}": :full)
category.save!
end
get "/groups/#{group.name}/permissions.json"
expect(response.status).to eq(200)
expect(response.parsed_body.map { |permission| permission["category"]["name"] }).to eq(
["Abc", "Hello", "New Cat", "Three"]
)
end
end
FEATURE: Improve group email settings UI (#13083) This overhauls the user interface for the group email settings management, aiming to make it a lot easier to test the settings entered and confirm they are correct before proceeding. We do this by forcing the user to test the settings before they can be saved to the database. It also includes some quality of life improvements around setting up IMAP and SMTP for our first supported provider, GMail. This PR does not remove the old group email config, that will come in a subsequent PR. This is related to https://meta.discourse.org/t/imap-support-for-group-inboxes/160588 so read that if you would like more backstory. ### UI Both site settings of `enable_imap` and `enable_smtp` must be true to test this. You must enable SMTP first to enable IMAP. You can prefill the SMTP settings with GMail configuration. To proceed with saving these settings you must test them, which is handled by the EmailSettingsValidator. If there is an issue with the configuration or credentials a meaningful error message should be shown. IMAP settings must also be validated when IMAP is enabled, before saving. When saving IMAP, we fetch the mailboxes for that account and populate them. This mailbox must be selected and saved for IMAP to work (the feature acts as though it is disabled until the mailbox is selected and saved): ### Database & Backend This adds several columns to the Groups table. The purpose of this change is to make it much more explicit that SMTP/IMAP is enabled for a group, rather than relying on settings not being null. Also included is an UPDATE query to backfill these columns. These columns are automatically filled when updating the group. For GMail, we now filter the mailboxes returned. This is so users cannot use a mailbox like Sent or Trash for syncing, which would generally be disastrous. There is a new group endpoint for testing email settings. This may be useful in the future for other places in our UI, at which point it can be extracted to a more generic endpoint or module to be included.
2021-05-27 19:28:18 -04:00
describe "#test_email_settings" do
let(:params) do
{
protocol: protocol,
ssl: ssl,
port: port,
host: host,
username: username,
password: password
}
end
before do
sign_in(user)
group.group_users.where(user: user).last.update(owner: user)
end
context "validating smtp" do
let(:protocol) { "smtp" }
let(:username) { "test@gmail.com" }
let(:password) { "password" }
let(:domain) { nil }
let(:ssl) { true }
let(:host) { "smtp.somemailsite.com" }
let(:port) { 587 }
context "when an error is raised" do
before do
EmailSettingsValidator.expects(:validate_smtp).raises(Net::SMTPAuthenticationError, "Invalid credentials")
end
it "uses the friendly error message functionality to return the message to the user" do
post "/groups/#{group.id}/test_email_settings.json", params: params
expect(response.status).to eq(422)
expect(response.parsed_body["errors"]).to include(I18n.t("email_settings.smtp_authentication_error"))
end
end
end
context "validating imap" do
let(:protocol) { "imap" }
let(:username) { "test@gmail.com" }
let(:password) { "password" }
let(:domain) { nil }
let(:ssl) { true }
let(:host) { "imap.somemailsite.com" }
let(:port) { 993 }
it "validates with the correct TLS settings" do
EmailSettingsValidator.expects(:validate_imap).with(
has_entry(ssl: true)
)
post "/groups/#{group.id}/test_email_settings.json", params: params
expect(response.status).to eq(200)
end
context "when an error is raised" do
before do
EmailSettingsValidator.expects(:validate_imap).raises(
Net::IMAP::NoResponseError, stub(data: stub(text: "Invalid credentials"))
)
end
it "uses the friendly error message functionality to return the message to the user" do
post "/groups/#{group.id}/test_email_settings.json", params: params
expect(response.status).to eq(422)
expect(response.parsed_body["errors"]).to include(I18n.t("email_settings.imap_authentication_error"))
end
end
end
describe "global param validation and rate limit" do
let(:protocol) { "smtp" }
let(:host) { "smtp.gmail.com" }
let(:port) { 587 }
let(:username) { "test@gmail.com" }
let(:password) { "password" }
let(:ssl) { true }
context "when the protocol is not accepted" do
let(:protocol) { "sigma" }
it "raises an invalid params error" do
post "/groups/#{group.id}/test_email_settings.json", params: params
expect(response.status).to eq(400)
expect(response.parsed_body["errors"].first).to match(/Valid protocols to test are smtp and imap/)
end
end
context "user does not have access to the group" do
before do
group.group_users.destroy_all
end
it "errors if the user does not have access to the group" do
post "/groups/#{group.id}/test_email_settings.json", params: params
expect(response.status).to eq(403)
end
end
context "rate limited" do
it "rate limits anon searches per user" do
RateLimiter.enable
RateLimiter.clear_all!
5.times do
post "/groups/#{group.id}/test_email_settings.json", params: params
end
post "/groups/#{group.id}/test_email_settings.json", params: params
expect(response.status).to eq(429)
end
end
end
end
end