Commit 439a61783d0b61bbcc8f3c9e5b828b2270a679aa
1 parent
c86553cd
Exists in
spb-stable
and in
3 other branches
User can leave group from group page.
Showing
23 changed files
with
430 additions
and
151 deletions
Show diff stats
app/controllers/application_controller.rb
@@ -135,12 +135,12 @@ class ApplicationController < ActionController::Base | @@ -135,12 +135,12 @@ class ApplicationController < ActionController::Base | ||
135 | end | 135 | end |
136 | end | 136 | end |
137 | 137 | ||
138 | - def render_404 | ||
139 | - render file: Rails.root.join("public", "404"), layout: false, status: "404" | 138 | + def render_403 |
139 | + head :forbidden | ||
140 | end | 140 | end |
141 | 141 | ||
142 | - def render_403 | ||
143 | - render file: Rails.root.join("public", "403"), layout: false, status: "403" | 142 | + def render_404 |
143 | + render file: Rails.root.join("public", "404"), layout: false, status: "404" | ||
144 | end | 144 | end |
145 | 145 | ||
146 | def require_non_empty_project | 146 | def require_non_empty_project |
app/controllers/profiles/groups_controller.rb
@@ -7,12 +7,11 @@ class Profiles::GroupsController < ApplicationController | @@ -7,12 +7,11 @@ class Profiles::GroupsController < ApplicationController | ||
7 | 7 | ||
8 | def leave | 8 | def leave |
9 | @users_group = group.users_groups.where(user_id: current_user.id).first | 9 | @users_group = group.users_groups.where(user_id: current_user.id).first |
10 | - | ||
11 | - if group.last_owner?(current_user) | ||
12 | - redirect_to(profile_groups_path, alert: "You can't leave group. You must add at least one more owner to it.") | ||
13 | - else | 10 | + if can?(current_user, :destroy, @users_group) |
14 | @users_group.destroy | 11 | @users_group.destroy |
15 | redirect_to(profile_groups_path, info: "You left #{group.name} group.") | 12 | redirect_to(profile_groups_path, info: "You left #{group.name} group.") |
13 | + else | ||
14 | + return render_403 | ||
16 | end | 15 | end |
17 | end | 16 | end |
18 | 17 |
app/controllers/users_groups_controller.rb
@@ -19,11 +19,14 @@ class UsersGroupsController < ApplicationController | @@ -19,11 +19,14 @@ class UsersGroupsController < ApplicationController | ||
19 | 19 | ||
20 | def destroy | 20 | def destroy |
21 | @users_group = @group.users_groups.find(params[:id]) | 21 | @users_group = @group.users_groups.find(params[:id]) |
22 | - @users_group.destroy | ||
23 | - | ||
24 | - respond_to do |format| | ||
25 | - format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' } | ||
26 | - format.js { render nothing: true } | 22 | + if can?(current_user, :destroy, @users_group) # May fail if last owner. |
23 | + @users_group.destroy | ||
24 | + respond_to do |format| | ||
25 | + format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' } | ||
26 | + format.js { render nothing: true } | ||
27 | + end | ||
28 | + else | ||
29 | + return render_403 | ||
27 | end | 30 | end |
28 | end | 31 | end |
29 | 32 |
app/helpers/groups_helper.rb
1 | module GroupsHelper | 1 | module GroupsHelper |
2 | def remove_user_from_group_message(group, user) | 2 | def remove_user_from_group_message(group, user) |
3 | - "You are going to remove #{user.name} from #{group.name} Group. Are you sure?" | 3 | + "Are you sure you want to remove \"#{user.name}\" from \"#{group.name}\"?" |
4 | + end | ||
5 | + | ||
6 | + def leave_group_message(group) | ||
7 | + "Are you sure you want to leave \"#{group}\" group?" | ||
4 | end | 8 | end |
5 | 9 | ||
6 | def group_head_title | 10 | def group_head_title |
app/models/ability.rb
@@ -14,6 +14,7 @@ class Ability | @@ -14,6 +14,7 @@ class Ability | ||
14 | when "MergeRequest" then merge_request_abilities(user, subject) | 14 | when "MergeRequest" then merge_request_abilities(user, subject) |
15 | when "Group" then group_abilities(user, subject) | 15 | when "Group" then group_abilities(user, subject) |
16 | when "Namespace" then namespace_abilities(user, subject) | 16 | when "Namespace" then namespace_abilities(user, subject) |
17 | + when "UsersGroup" then users_group_abilities(user, subject) | ||
17 | else [] | 18 | else [] |
18 | end.concat(global_abilities(user)) | 19 | end.concat(global_abilities(user)) |
19 | end | 20 | end |
@@ -219,5 +220,19 @@ class Ability | @@ -219,5 +220,19 @@ class Ability | ||
219 | end | 220 | end |
220 | end | 221 | end |
221 | end | 222 | end |
223 | + | ||
224 | + def users_group_abilities(user, subject) | ||
225 | + rules = [] | ||
226 | + target_user = subject.user | ||
227 | + group = subject.group | ||
228 | + can_manage = group_abilities(user, group).include?(:manage_group) | ||
229 | + if can_manage && (user != target_user) | ||
230 | + rules << :modify | ||
231 | + end | ||
232 | + if !group.last_owner?(user) && (can_manage || (user == target_user)) | ||
233 | + rules << :destroy | ||
234 | + end | ||
235 | + rules | ||
236 | + end | ||
222 | end | 237 | end |
223 | end | 238 | end |
app/views/groups/members.html.haml
@@ -6,7 +6,6 @@ | @@ -6,7 +6,6 @@ | ||
6 | %strong= link_to "here", help_permissions_path, class: "vlink" | 6 | %strong= link_to "here", help_permissions_path, class: "vlink" |
7 | 7 | ||
8 | %hr | 8 | %hr |
9 | -- can_manage_group = current_user.can? :manage_group, @group | ||
10 | .ui-box | 9 | .ui-box |
11 | .title | 10 | .title |
12 | %strong #{@group.name} | 11 | %strong #{@group.name} |
@@ -15,6 +14,6 @@ | @@ -15,6 +14,6 @@ | ||
15 | (#{@members.count}) | 14 | (#{@members.count}) |
16 | %ul.well-list | 15 | %ul.well-list |
17 | - @members.each do |member| | 16 | - @members.each do |member| |
18 | - = render 'users_groups/users_group', member: member, show_controls: can_manage_group | ||
19 | -- if can_manage_group | 17 | + = render 'users_groups/users_group', member: member, show_controls: true |
18 | +- if current_user.can? :manage_group, @group | ||
20 | = render "new_group_member" | 19 | = render "new_group_member" |
app/views/help/permissions.html.haml
app/views/profiles/groups/index.html.haml
@@ -22,9 +22,10 @@ | @@ -22,9 +22,10 @@ | ||
22 | %i.icon-cogs | 22 | %i.icon-cogs |
23 | Settings | 23 | Settings |
24 | 24 | ||
25 | - = link_to leave_profile_group_path(group), data: { confirm: "Are you sure you want to leave #{group.name} group?"}, method: :delete, class: "btn-small btn grouped", title: 'Remove user from group' do | ||
26 | - %i.icon-signout | ||
27 | - Leave | 25 | + - if can?(current_user, :destroy, user_group) |
26 | + = link_to leave_profile_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-small btn grouped", title: 'Remove user from group' do | ||
27 | + %i.icon-signout | ||
28 | + Leave | ||
28 | 29 | ||
29 | = link_to group, class: 'group-name' do | 30 | = link_to group, class: 'group-name' do |
30 | %strong= group.name | 31 | %strong= group.name |
app/views/users_groups/_users_group.html.haml
@@ -9,12 +9,17 @@ | @@ -9,12 +9,17 @@ | ||
9 | 9 | ||
10 | %span.pull-right | 10 | %span.pull-right |
11 | %strong= member.human_access | 11 | %strong= member.human_access |
12 | - | ||
13 | - - if show_controls && can?(current_user, :manage_group, @group) && current_user != user | ||
14 | - = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do | ||
15 | - %i.icon-edit | ||
16 | - = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do | ||
17 | - %i.icon-minus.icon-white | 12 | + - if show_controls |
13 | + - if can?(current_user, :modify, member) | ||
14 | + = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do | ||
15 | + %i.icon-edit | ||
16 | + - if can?(current_user, :destroy, member) | ||
17 | + - if current_user == member.user | ||
18 | + = link_to leave_profile_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do | ||
19 | + %i.icon-minus.icon-white | ||
20 | + - else | ||
21 | + = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do | ||
22 | + %i.icon-minus.icon-white | ||
18 | 23 | ||
19 | .edit-member.hide.js-toggle-content | 24 | .edit-member.hide.js-toggle-content |
20 | = form_for [@group, member], remote: true do |f| | 25 | = form_for [@group, member], remote: true do |f| |
features/admin/groups.feature
@@ -2,7 +2,7 @@ Feature: Admin Groups | @@ -2,7 +2,7 @@ Feature: Admin Groups | ||
2 | Background: | 2 | Background: |
3 | Given I sign in as an admin | 3 | Given I sign in as an admin |
4 | And I have group with projects | 4 | And I have group with projects |
5 | - And Create user "John Doe" | 5 | + And User "John Doe" exists |
6 | And I visit admin groups page | 6 | And I visit admin groups page |
7 | 7 | ||
8 | Scenario: See group list | 8 | Scenario: See group list |
@@ -0,0 +1,116 @@ | @@ -0,0 +1,116 @@ | ||
1 | +Feature: Groups | ||
2 | + Background: | ||
3 | + Given I sign in as "John Doe" | ||
4 | + And "John Doe" is owner of group "Owned" | ||
5 | + And "John Doe" is guest of group "Guest" | ||
6 | + | ||
7 | + @javascript | ||
8 | + Scenario: I should see group "Owned" dashboard list | ||
9 | + When I visit group "Owned" page | ||
10 | + Then I should see group "Owned" projects list | ||
11 | + And I should see projects activity feed | ||
12 | + | ||
13 | + Scenario: Create a group from dasboard | ||
14 | + When I visit group "Owned" page | ||
15 | + And I visit dashboard page | ||
16 | + And I click new group link | ||
17 | + And submit form with new group "Samurai" info | ||
18 | + Then I should be redirected to group "Samurai" page | ||
19 | + And I should see newly created group "Samurai" | ||
20 | + | ||
21 | + Scenario: I should see group "Owned" issues list | ||
22 | + Given project from group "Owned" has issues assigned to me | ||
23 | + When I visit group "Owned" issues page | ||
24 | + Then I should see issues from group "Owned" assigned to me | ||
25 | + | ||
26 | + Scenario: I should see group "Owned" merge requests list | ||
27 | + Given project from group "Owned" has merge requests assigned to me | ||
28 | + When I visit group "Owned" merge requests page | ||
29 | + Then I should see merge requests from group "Owned" assigned to me | ||
30 | + | ||
31 | + @javascript | ||
32 | + Scenario: I should add user to projects in group "Owned" | ||
33 | + Given User "Mary Jane" exists | ||
34 | + When I visit group "Owned" members page | ||
35 | + And I select user "Mary Jane" from list with role "Reporter" | ||
36 | + Then I should see user "Mary Jane" in team list | ||
37 | + | ||
38 | + Scenario: I should see edit group "Owned" page | ||
39 | + When I visit group "Owned" settings page | ||
40 | + And I change group "Owned" name to "new-name" | ||
41 | + Then I should see new group "Owned" name | ||
42 | + | ||
43 | + Scenario: I edit group "Owned" avatar | ||
44 | + When I visit group "Owned" settings page | ||
45 | + And I change group "Owned" avatar | ||
46 | + And I visit group "Owned" settings page | ||
47 | + Then I should see new group "Owned" avatar | ||
48 | + And I should see the "Remove avatar" button | ||
49 | + | ||
50 | + Scenario: I remove group "Owned" avatar | ||
51 | + When I visit group "Owned" settings page | ||
52 | + And I have group "Owned" avatar | ||
53 | + And I visit group "Owned" settings page | ||
54 | + And I remove group "Owned" avatar | ||
55 | + Then I should not see group "Owned" avatar | ||
56 | + And I should not see the "Remove avatar" button | ||
57 | + | ||
58 | + # Leave | ||
59 | + | ||
60 | + @javascript | ||
61 | + Scenario: Owner should be able to remove himself from group if he is not the last owner | ||
62 | + Given "Mary Jane" is owner of group "Owned" | ||
63 | + When I visit group "Owned" members page | ||
64 | + Then I should see user "John Doe" in team list | ||
65 | + Then I should see user "Mary Jane" in team list | ||
66 | + When I click on the "Remove User From Group" button for "John Doe" | ||
67 | + And I visit group "Owned" members page | ||
68 | + Then I should not see user "John Doe" in team list | ||
69 | + Then I should see user "Mary Jane" in team list | ||
70 | + | ||
71 | + @javascript | ||
72 | + Scenario: Owner should not be able to remove himself from group if he is the last owner | ||
73 | + Given "Mary Jane" is guest of group "Owned" | ||
74 | + When I visit group "Owned" members page | ||
75 | + Then I should see user "John Doe" in team list | ||
76 | + Then I should see user "Mary Jane" in team list | ||
77 | + Then I should not see the "Remove User From Group" button for "Mary Jane" | ||
78 | + | ||
79 | + @javascript | ||
80 | + Scenario: Guest should be able to remove himself from group | ||
81 | + Given "Mary Jane" is guest of group "Guest" | ||
82 | + When I visit group "Guest" members page | ||
83 | + Then I should see user "John Doe" in team list | ||
84 | + Then I should see user "Mary Jane" in team list | ||
85 | + When I click on the "Remove User From Group" button for "John Doe" | ||
86 | + When I visit group "Guest" members page | ||
87 | + Then I should not see user "John Doe" in team list | ||
88 | + Then I should see user "Mary Jane" in team list | ||
89 | + | ||
90 | + @javascript | ||
91 | + Scenario: Guest should be able to remove himself from group even if he is the only user in the group | ||
92 | + When I visit group "Guest" members page | ||
93 | + Then I should see user "John Doe" in team list | ||
94 | + When I click on the "Remove User From Group" button for "John Doe" | ||
95 | + When I visit group "Guest" members page | ||
96 | + Then I should not see user "John Doe" in team list | ||
97 | + | ||
98 | + # Remove others | ||
99 | + | ||
100 | + @javascript | ||
101 | + Scenario: Owner should be able to remove other users from group | ||
102 | + Given "Mary Jane" is owner of group "Owned" | ||
103 | + When I visit group "Owned" members page | ||
104 | + Then I should see user "John Doe" in team list | ||
105 | + Then I should see user "Mary Jane" in team list | ||
106 | + When I click on the "Remove User From Group" button for "Mary Jane" | ||
107 | + When I visit group "Owned" members page | ||
108 | + Then I should see user "John Doe" in team list | ||
109 | + Then I should not see user "Mary Jane" in team list | ||
110 | + | ||
111 | + Scenario: Guest should not be able to remove other users from group | ||
112 | + Given "Mary Jane" is guest of group "Guest" | ||
113 | + When I visit group "Guest" members page | ||
114 | + Then I should see user "John Doe" in team list | ||
115 | + Then I should see user "Mary Jane" in team list | ||
116 | + Then I should not see the "Remove User From Group" button for "Mary Jane" |
features/group/create_group.feature
@@ -1,11 +0,0 @@ | @@ -1,11 +0,0 @@ | ||
1 | -Feature: Groups | ||
2 | - Background: | ||
3 | - Given I sign in as a user | ||
4 | - | ||
5 | - Scenario: Create a group from dasboard | ||
6 | - Given I have group with projects | ||
7 | - And I visit dashboard page | ||
8 | - When I click new group link | ||
9 | - And submit form with new group info | ||
10 | - Then I should be redirected to group page | ||
11 | - And I should see newly created group |
features/group/group.feature
@@ -1,47 +0,0 @@ | @@ -1,47 +0,0 @@ | ||
1 | -Feature: Groups | ||
2 | - Background: | ||
3 | - Given I sign in as a user | ||
4 | - And I have group with projects | ||
5 | - | ||
6 | - @javascript | ||
7 | - Scenario: I should see group dashboard list | ||
8 | - When I visit group page | ||
9 | - Then I should see projects list | ||
10 | - And I should see projects activity feed | ||
11 | - | ||
12 | - Scenario: I should see group issues list | ||
13 | - Given project from group has issues assigned to me | ||
14 | - When I visit group issues page | ||
15 | - Then I should see issues from this group assigned to me | ||
16 | - | ||
17 | - Scenario: I should see group merge requests list | ||
18 | - Given project from group has merge requests assigned to me | ||
19 | - When I visit group merge requests page | ||
20 | - Then I should see merge requests from this group assigned to me | ||
21 | - | ||
22 | - @javascript | ||
23 | - Scenario: I should add user to projects in Group | ||
24 | - Given Create user "John Doe" | ||
25 | - When I visit group members page | ||
26 | - And I select user "John Doe" from list with role "Reporter" | ||
27 | - Then I should see user "John Doe" in team list | ||
28 | - | ||
29 | - Scenario: I should see edit group page | ||
30 | - When I visit group settings page | ||
31 | - And I change group name | ||
32 | - Then I should see new group name | ||
33 | - | ||
34 | - Scenario: I edit my group avatar | ||
35 | - When I visit group settings page | ||
36 | - And I change my group avatar | ||
37 | - And I visit group settings page | ||
38 | - Then I should see new group avatar | ||
39 | - And I should see the "Remove avatar" button | ||
40 | - | ||
41 | - Scenario: I remove my group avatar | ||
42 | - When I visit group settings page | ||
43 | - And I have an group avatar | ||
44 | - And I visit group settings page | ||
45 | - And I remove my group avatar | ||
46 | - Then I should not see my group avatar | ||
47 | - And I should not see the "Remove avatar" button |
@@ -0,0 +1,47 @@ | @@ -0,0 +1,47 @@ | ||
1 | +Feature: Profile Group | ||
2 | + Background: | ||
3 | + Given I sign in as "John Doe" | ||
4 | + And "John Doe" is owner of group "Owned" | ||
5 | + And "John Doe" is guest of group "Guest" | ||
6 | + | ||
7 | + # Leave groups | ||
8 | + | ||
9 | + @javascript | ||
10 | + Scenario: Owner should be able to leave from group if he is not the last owner | ||
11 | + Given "Mary Jane" is owner of group "Owned" | ||
12 | + When I visit profile groups page | ||
13 | + Then I should see group "Owned" in group list | ||
14 | + Then I should see group "Guest" in group list | ||
15 | + When I click on the "Leave" button for group "Owned" | ||
16 | + And I visit profile groups page | ||
17 | + Then I should not see group "Owned" in group list | ||
18 | + Then I should see group "Guest" in group list | ||
19 | + | ||
20 | + @javascript | ||
21 | + Scenario: Owner should not be able to leave from group if he is the last owner | ||
22 | + Given "Mary Jane" is guest of group "Owned" | ||
23 | + When I visit profile groups page | ||
24 | + Then I should see group "Owned" in group list | ||
25 | + Then I should see group "Guest" in group list | ||
26 | + Then I should not see the "Leave" button for group "Owned" | ||
27 | + | ||
28 | + @javascript | ||
29 | + Scenario: Guest should be able to leave from group | ||
30 | + Given "Mary Jane" is guest of group "Guest" | ||
31 | + When I visit profile groups page | ||
32 | + Then I should see group "Owned" in group list | ||
33 | + Then I should see group "Guest" in group list | ||
34 | + When I click on the "Leave" button for group "Guest" | ||
35 | + When I visit profile groups page | ||
36 | + Then I should see group "Owned" in group list | ||
37 | + Then I should not see group "Guest" in group list | ||
38 | + | ||
39 | + @javascript | ||
40 | + Scenario: Guest should be able to leave from group even if he is the only user in the group | ||
41 | + When I visit profile groups page | ||
42 | + Then I should see group "Owned" in group list | ||
43 | + Then I should see group "Guest" in group list | ||
44 | + When I click on the "Leave" button for group "Guest" | ||
45 | + When I visit profile groups page | ||
46 | + Then I should see group "Owned" in group list | ||
47 | + Then I should not see group "Guest" in group list |
features/steps/group/group.rb
1 | class Groups < Spinach::FeatureSteps | 1 | class Groups < Spinach::FeatureSteps |
2 | include SharedAuthentication | 2 | include SharedAuthentication |
3 | include SharedPaths | 3 | include SharedPaths |
4 | + include SharedGroup | ||
4 | include SharedUser | 5 | include SharedUser |
5 | include Select2Helper | 6 | include Select2Helper |
6 | 7 | ||
7 | - Then 'I should see projects list' do | ||
8 | - current_user.authorized_projects.each do |project| | 8 | + Then 'I should see group "Owned" projects list' do |
9 | + Group.find_by(name: "Owned").projects.each do |project| | ||
9 | page.should have_link project.name | 10 | page.should have_link project.name |
10 | end | 11 | end |
11 | end | 12 | end |
12 | 13 | ||
13 | - And 'I have group with projects' do | ||
14 | - @group = create(:group) | ||
15 | - @group.add_owner(current_user) | ||
16 | - @project = create(:project, namespace: @group) | ||
17 | - @event = create(:closed_issue_event, project: @project) | ||
18 | - | ||
19 | - @project.team << [current_user, :master] | ||
20 | - end | ||
21 | - | ||
22 | And 'I should see projects activity feed' do | 14 | And 'I should see projects activity feed' do |
23 | page.should have_content 'closed issue' | 15 | page.should have_content 'closed issue' |
24 | end | 16 | end |
25 | 17 | ||
26 | - Then 'I should see issues from this group assigned to me' do | 18 | + Then 'I should see issues from group "Owned" assigned to me' do |
27 | assigned_to_me(:issues).each do |issue| | 19 | assigned_to_me(:issues).each do |issue| |
28 | page.should have_content issue.title | 20 | page.should have_content issue.title |
29 | end | 21 | end |
30 | end | 22 | end |
31 | 23 | ||
32 | - Then 'I should see merge requests from this group assigned to me' do | 24 | + Then 'I should see merge requests from group "Owned" assigned to me' do |
33 | assigned_to_me(:merge_requests).each do |issue| | 25 | assigned_to_me(:merge_requests).each do |issue| |
34 | page.should have_content issue.title[0..80] | 26 | page.should have_content issue.title[0..80] |
35 | end | 27 | end |
36 | end | 28 | end |
37 | 29 | ||
38 | - And 'I select user "John Doe" from list with role "Reporter"' do | ||
39 | - user = User.find_by(name: "John Doe") | 30 | + And 'I select user "Mary Jane" from list with role "Reporter"' do |
31 | + user = User.find_by(name: "Mary Jane") || create(:user, name: "Mary Jane") | ||
40 | within ".users-group-form" do | 32 | within ".users-group-form" do |
41 | select2(user.id, from: "#user_ids", multiple: true) | 33 | select2(user.id, from: "#user_ids", multiple: true) |
42 | select "Reporter", from: "group_access" | 34 | select "Reporter", from: "group_access" |
@@ -49,14 +41,29 @@ class Groups < Spinach::FeatureSteps | @@ -49,14 +41,29 @@ class Groups < Spinach::FeatureSteps | ||
49 | projects_with_access.should have_content("John Doe") | 41 | projects_with_access.should have_content("John Doe") |
50 | end | 42 | end |
51 | 43 | ||
52 | - Given 'project from group has issues assigned to me' do | 44 | + Then 'I should not see user "John Doe" in team list' do |
45 | + projects_with_access = find(".ui-box .well-list") | ||
46 | + projects_with_access.should_not have_content("John Doe") | ||
47 | + end | ||
48 | + | ||
49 | + Then 'I should see user "Mary Jane" in team list' do | ||
50 | + projects_with_access = find(".ui-box .well-list") | ||
51 | + projects_with_access.should have_content("Mary Jane") | ||
52 | + end | ||
53 | + | ||
54 | + Then 'I should not see user "Mary Jane" in team list' do | ||
55 | + projects_with_access = find(".ui-box .well-list") | ||
56 | + projects_with_access.should_not have_content("Mary Jane") | ||
57 | + end | ||
58 | + | ||
59 | + Given 'project from group "Owned" has issues assigned to me' do | ||
53 | create :issue, | 60 | create :issue, |
54 | project: project, | 61 | project: project, |
55 | assignee: current_user, | 62 | assignee: current_user, |
56 | author: current_user | 63 | author: current_user |
57 | end | 64 | end |
58 | 65 | ||
59 | - Given 'project from group has merge requests assigned to me' do | 66 | + Given 'project from group "Owned" has merge requests assigned to me' do |
60 | create :merge_request, | 67 | create :merge_request, |
61 | source_project: project, | 68 | source_project: project, |
62 | target_project: project, | 69 | target_project: project, |
@@ -68,78 +75,94 @@ class Groups < Spinach::FeatureSteps | @@ -68,78 +75,94 @@ class Groups < Spinach::FeatureSteps | ||
68 | click_link "New group" | 75 | click_link "New group" |
69 | end | 76 | end |
70 | 77 | ||
71 | - And 'submit form with new group info' do | 78 | + And 'submit form with new group "Samurai" info' do |
72 | fill_in 'group_name', with: 'Samurai' | 79 | fill_in 'group_name', with: 'Samurai' |
73 | fill_in 'group_description', with: 'Tokugawa Shogunate' | 80 | fill_in 'group_description', with: 'Tokugawa Shogunate' |
74 | click_button "Create group" | 81 | click_button "Create group" |
75 | end | 82 | end |
76 | 83 | ||
77 | - Then 'I should see newly created group' do | 84 | + Then 'I should be redirected to group "Samurai" page' do |
85 | + current_path.should == group_path(Group.last) | ||
86 | + end | ||
87 | + | ||
88 | + Then 'I should see newly created group "Samurai"' do | ||
78 | page.should have_content "Samurai" | 89 | page.should have_content "Samurai" |
79 | page.should have_content "Tokugawa Shogunate" | 90 | page.should have_content "Tokugawa Shogunate" |
80 | page.should have_content "You will only see events from projects in this group" | 91 | page.should have_content "You will only see events from projects in this group" |
81 | end | 92 | end |
82 | 93 | ||
83 | - Then 'I should be redirected to group page' do | ||
84 | - current_path.should == group_path(Group.last) | ||
85 | - end | ||
86 | - | ||
87 | - And 'I change group name' do | 94 | + And 'I change group "Owned" name to "new-name"' do |
88 | fill_in 'group_name', with: 'new-name' | 95 | fill_in 'group_name', with: 'new-name' |
89 | click_button "Save group" | 96 | click_button "Save group" |
90 | end | 97 | end |
91 | 98 | ||
92 | - Then 'I should see new group name' do | 99 | + Then 'I should see new group "Owned" name' do |
93 | within ".navbar-gitlab" do | 100 | within ".navbar-gitlab" do |
94 | page.should have_content "group: new-name" | 101 | page.should have_content "group: new-name" |
95 | end | 102 | end |
96 | end | 103 | end |
97 | 104 | ||
98 | - step 'I change my group avatar' do | 105 | + step 'I change group "Owned" avatar' do |
99 | attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) | 106 | attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) |
100 | click_button "Save group" | 107 | click_button "Save group" |
101 | - @group.reload | 108 | + Group.find_by(name: "Owned").reload |
102 | end | 109 | end |
103 | 110 | ||
104 | - step 'I should see new group avatar' do | ||
105 | - @group.avatar.should be_instance_of AttachmentUploader | ||
106 | - @group.avatar.url.should == "/uploads/group/avatar/#{ @group.id }/gitlab_logo.png" | 111 | + step 'I should see new group "Owned" avatar' do |
112 | + Group.find_by(name: "Owned").avatar.should be_instance_of AttachmentUploader | ||
113 | + Group.find_by(name: "Owned").avatar.url.should == "/uploads/group/avatar/#{ Group.find_by(name:"Owned").id }/gitlab_logo.png" | ||
107 | end | 114 | end |
108 | 115 | ||
109 | step 'I should see the "Remove avatar" button' do | 116 | step 'I should see the "Remove avatar" button' do |
110 | page.should have_link("Remove avatar") | 117 | page.should have_link("Remove avatar") |
111 | end | 118 | end |
112 | 119 | ||
113 | - step 'I have an group avatar' do | 120 | + step 'I have group "Owned" avatar' do |
114 | attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) | 121 | attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) |
115 | click_button "Save group" | 122 | click_button "Save group" |
116 | - @group.reload | 123 | + Group.find_by(name: "Owned").reload |
117 | end | 124 | end |
118 | 125 | ||
119 | - step 'I remove my group avatar' do | 126 | + step 'I remove group "Owned" avatar' do |
120 | click_link "Remove avatar" | 127 | click_link "Remove avatar" |
121 | - @group.reload | 128 | + Group.find_by(name: "Owned").reload |
122 | end | 129 | end |
123 | 130 | ||
124 | - step 'I should not see my group avatar' do | ||
125 | - @group.avatar?.should be_false | 131 | + step 'I should not see group "Owned" avatar' do |
132 | + Group.find_by(name: "Owned").avatar?.should be_false | ||
126 | end | 133 | end |
127 | 134 | ||
128 | step 'I should not see the "Remove avatar" button' do | 135 | step 'I should not see the "Remove avatar" button' do |
129 | page.should_not have_link("Remove avatar") | 136 | page.should_not have_link("Remove avatar") |
130 | end | 137 | end |
131 | 138 | ||
132 | - protected | 139 | + step 'I click on the "Remove User From Group" button for "John Doe"' do |
140 | + find(:css, 'li', text: "John Doe").find(:css, 'a.btn-remove').click | ||
141 | + # poltergeist always confirms popups. | ||
142 | + end | ||
133 | 143 | ||
134 | - def current_group | ||
135 | - @group ||= Group.first | 144 | + step 'I click on the "Remove User From Group" button for "Mary Jane"' do |
145 | + find(:css, 'li', text: "Mary Jane").find(:css, 'a.btn-remove').click | ||
146 | + # poltergeist always confirms popups. | ||
136 | end | 147 | end |
137 | 148 | ||
138 | - def project | ||
139 | - current_group.projects.first | 149 | + step 'I should not see the "Remove User From Group" button for "John Doe"' do |
150 | + find(:css, 'li', text: "John Doe").should_not have_selector(:css, 'a.btn-remove') | ||
151 | + # poltergeist always confirms popups. | ||
140 | end | 152 | end |
141 | 153 | ||
154 | + step 'I should not see the "Remove User From Group" button for "Mary Jane"' do | ||
155 | + find(:css, 'li', text: "Mary Jane").should_not have_selector(:css, 'a.btn-remove') | ||
156 | + # poltergeist always confirms popups. | ||
157 | + end | ||
158 | + | ||
159 | + protected | ||
160 | + | ||
142 | def assigned_to_me key | 161 | def assigned_to_me key |
143 | project.send(key).where(assignee_id: current_user.id) | 162 | project.send(key).where(assignee_id: current_user.id) |
144 | end | 163 | end |
164 | + | ||
165 | + def project | ||
166 | + Group.find_by(name: "Owned").projects.first | ||
167 | + end | ||
145 | end | 168 | end |
@@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
1 | +class ProfileGroup < Spinach::FeatureSteps | ||
2 | + include SharedAuthentication | ||
3 | + include SharedGroup | ||
4 | + include SharedPaths | ||
5 | + include SharedUser | ||
6 | + | ||
7 | + # Leave | ||
8 | + | ||
9 | + step 'I click on the "Leave" button for group "Owned"' do | ||
10 | + find(:css, 'li', text: "Owner").find(:css, 'i.icon-signout').click | ||
11 | + # poltergeist always confirms popups. | ||
12 | + end | ||
13 | + | ||
14 | + step 'I click on the "Leave" button for group "Guest"' do | ||
15 | + find(:css, 'li', text: "Guest").find(:css, 'i.icon-signout').click | ||
16 | + # poltergeist always confirms popups. | ||
17 | + end | ||
18 | + | ||
19 | + step 'I should not see the "Leave" button for group "Owned"' do | ||
20 | + find(:css, 'li', text: "Owner").should_not have_selector(:css, 'i.icon-signout') | ||
21 | + # poltergeist always confirms popups. | ||
22 | + end | ||
23 | + | ||
24 | + step 'I should not see the "Leave" button for groupr "Guest"' do | ||
25 | + find(:css, 'li', text: "Guest").should_not have_selector(:css, 'i.icon-signout') | ||
26 | + # poltergeist always confirms popups. | ||
27 | + end | ||
28 | + | ||
29 | + step 'I should see group "Owned" in group list' do | ||
30 | + page.should have_content("Owned") | ||
31 | + end | ||
32 | + | ||
33 | + step 'I should not see group "Owned" in group list' do | ||
34 | + page.should_not have_content("Owned") | ||
35 | + end | ||
36 | + | ||
37 | + step 'I should see group "Guest" in group list' do | ||
38 | + page.should have_content("Guest") | ||
39 | + end | ||
40 | + | ||
41 | + step 'I should not see group "Guest" in group list' do | ||
42 | + page.should_not have_content("Guest") | ||
43 | + end | ||
44 | +end |
features/steps/project/project_network_graph.rb
1 | class ProjectNetworkGraph < Spinach::FeatureSteps | 1 | class ProjectNetworkGraph < Spinach::FeatureSteps |
2 | include SharedAuthentication | 2 | include SharedAuthentication |
3 | + include SharedPaths | ||
3 | include SharedProject | 4 | include SharedProject |
4 | 5 | ||
5 | Then 'page should have network graph' do | 6 | Then 'page should have network graph' do |
features/steps/shared/authentication.rb
@@ -12,6 +12,14 @@ module SharedAuthentication | @@ -12,6 +12,14 @@ module SharedAuthentication | ||
12 | login_as :admin | 12 | login_as :admin |
13 | end | 13 | end |
14 | 14 | ||
15 | + step 'I sign in as "John Doe"' do | ||
16 | + login_with(user_exists("John Doe")) | ||
17 | + end | ||
18 | + | ||
19 | + step 'I sign in as "Mary Jane"' do | ||
20 | + login_with(user_exists("Mary Jane")) | ||
21 | + end | ||
22 | + | ||
15 | step 'I should be redirected to sign in page' do | 23 | step 'I should be redirected to sign in page' do |
16 | current_path.should == new_user_session_path | 24 | current_path.should == new_user_session_path |
17 | end | 25 | end |
@@ -0,0 +1,36 @@ | @@ -0,0 +1,36 @@ | ||
1 | +module SharedGroup | ||
2 | + include Spinach::DSL | ||
3 | + | ||
4 | + step '"John Doe" is owner of group "Owned"' do | ||
5 | + is_member_of("John Doe", "Owned", Gitlab::Access::OWNER) | ||
6 | + end | ||
7 | + | ||
8 | + step '"John Doe" is guest of group "Guest"' do | ||
9 | + is_member_of("John Doe", "Guest", Gitlab::Access::GUEST) | ||
10 | + end | ||
11 | + | ||
12 | + step '"Mary Jane" is owner of group "Owned"' do | ||
13 | + is_member_of("Mary Jane", "Owned", Gitlab::Access::OWNER) | ||
14 | + end | ||
15 | + | ||
16 | + step '"Mary Jane" is guest of group "Owned"' do | ||
17 | + is_member_of("Mary Jane", "Owned", Gitlab::Access::GUEST) | ||
18 | + end | ||
19 | + | ||
20 | + step '"Mary Jane" is guest of group "Guest"' do | ||
21 | + is_member_of("Mary Jane", "Guest", Gitlab::Access::GUEST) | ||
22 | + end | ||
23 | + | ||
24 | + protected | ||
25 | + | ||
26 | + def is_member_of(username, groupname, role) | ||
27 | + @project_count ||= 0 | ||
28 | + user = User.find_by(name: username) || create(:user, name: username) | ||
29 | + group = Group.find_by(name: groupname) || create(:group, name: groupname) | ||
30 | + group.add_user(user, role) | ||
31 | + project ||= create(:project, namespace: group, path: "project#{@project_count}") | ||
32 | + event ||= create(:closed_issue_event, project: project) | ||
33 | + project.team << [user, :master] | ||
34 | + @project_count += 1 | ||
35 | + end | ||
36 | +end |
features/steps/shared/paths.rb
@@ -17,24 +17,44 @@ module SharedPaths | @@ -17,24 +17,44 @@ module SharedPaths | ||
17 | # Group | 17 | # Group |
18 | # ---------------------------------------- | 18 | # ---------------------------------------- |
19 | 19 | ||
20 | - step 'I visit group page' do | ||
21 | - visit group_path(current_group) | 20 | + step 'I visit group "Owned" page' do |
21 | + visit group_path(Group.find_by(name:"Owned")) | ||
22 | end | 22 | end |
23 | 23 | ||
24 | - step 'I visit group issues page' do | ||
25 | - visit issues_group_path(current_group) | 24 | + step 'I visit group "Owned" issues page' do |
25 | + visit issues_group_path(Group.find_by(name:"Owned")) | ||
26 | end | 26 | end |
27 | 27 | ||
28 | - step 'I visit group merge requests page' do | ||
29 | - visit merge_requests_group_path(current_group) | 28 | + step 'I visit group "Owned" merge requests page' do |
29 | + visit merge_requests_group_path(Group.find_by(name:"Owned")) | ||
30 | end | 30 | end |
31 | 31 | ||
32 | - step 'I visit group members page' do | ||
33 | - visit members_group_path(current_group) | 32 | + step 'I visit group "Owned" members page' do |
33 | + visit members_group_path(Group.find_by(name:"Owned")) | ||
34 | end | 34 | end |
35 | 35 | ||
36 | - step 'I visit group settings page' do | ||
37 | - visit edit_group_path(current_group) | 36 | + step 'I visit group "Owned" settings page' do |
37 | + visit edit_group_path(Group.find_by(name:"Owned")) | ||
38 | + end | ||
39 | + | ||
40 | + step 'I visit group "Guest" page' do | ||
41 | + visit group_path(Group.find_by(name:"Guest")) | ||
42 | + end | ||
43 | + | ||
44 | + step 'I visit group "Guest" issues page' do | ||
45 | + visit issues_group_path(Group.find_by(name:"Guest")) | ||
46 | + end | ||
47 | + | ||
48 | + step 'I visit group "Guest" merge requests page' do | ||
49 | + visit merge_requests_group_path(Group.find_by(name:"Guest")) | ||
50 | + end | ||
51 | + | ||
52 | + step 'I visit group "Guest" members page' do | ||
53 | + visit members_group_path(Group.find_by(name:"Guest")) | ||
54 | + end | ||
55 | + | ||
56 | + step 'I visit group "Guest" settings page' do | ||
57 | + visit edit_group_path(Group.find_by(name:"Guest")) | ||
38 | end | 58 | end |
39 | 59 | ||
40 | # ---------------------------------------- | 60 | # ---------------------------------------- |
@@ -93,6 +113,14 @@ module SharedPaths | @@ -93,6 +113,14 @@ module SharedPaths | ||
93 | visit history_profile_path | 113 | visit history_profile_path |
94 | end | 114 | end |
95 | 115 | ||
116 | + step 'I visit profile groups page' do | ||
117 | + visit profile_groups_path | ||
118 | + end | ||
119 | + | ||
120 | + step 'I should be redirected to the profile groups page' do | ||
121 | + current_path.should == profile_groups_path | ||
122 | + end | ||
123 | + | ||
96 | # ---------------------------------------- | 124 | # ---------------------------------------- |
97 | # Admin | 125 | # Admin |
98 | # ---------------------------------------- | 126 | # ---------------------------------------- |
@@ -326,4 +354,12 @@ module SharedPaths | @@ -326,4 +354,12 @@ module SharedPaths | ||
326 | def project | 354 | def project |
327 | project = Project.find_by!(name: "Shop") | 355 | project = Project.find_by!(name: "Shop") |
328 | end | 356 | end |
357 | + | ||
358 | + # ---------------------------------------- | ||
359 | + # Errors | ||
360 | + # ---------------------------------------- | ||
361 | + | ||
362 | + Then 'page status code should be 404' do | ||
363 | + page.status_code.should == 404 | ||
364 | + end | ||
329 | end | 365 | end |
features/steps/shared/project.rb
@@ -58,10 +58,6 @@ module SharedProject | @@ -58,10 +58,6 @@ module SharedProject | ||
58 | page.should have_content("Features:") | 58 | page.should have_content("Features:") |
59 | end | 59 | end |
60 | 60 | ||
61 | - Then 'page status code should be 404' do | ||
62 | - page.status_code.should == 404 | ||
63 | - end | ||
64 | - | ||
65 | def current_project | 61 | def current_project |
66 | @project ||= Project.first | 62 | @project ||= Project.first |
67 | end | 63 | end |
@@ -107,24 +103,21 @@ module SharedProject | @@ -107,24 +103,21 @@ module SharedProject | ||
107 | end | 103 | end |
108 | 104 | ||
109 | step '"John Doe" is authorized to private project "Enterprise"' do | 105 | step '"John Doe" is authorized to private project "Enterprise"' do |
110 | - user = User.find_by(name: "John Doe") | ||
111 | - user ||= create(:user, name: "John Doe", username: "john_doe") | 106 | + user = user_exists("John Doe", username: "john_doe") |
112 | project = Project.find_by(name: "Enterprise") | 107 | project = Project.find_by(name: "Enterprise") |
113 | project ||= create(:project, name: "Enterprise", namespace: user.namespace) | 108 | project ||= create(:project, name: "Enterprise", namespace: user.namespace) |
114 | project.team << [user, :master] | 109 | project.team << [user, :master] |
115 | end | 110 | end |
116 | 111 | ||
117 | step '"John Doe" is authorized to internal project "Internal"' do | 112 | step '"John Doe" is authorized to internal project "Internal"' do |
118 | - user = User.find_by(name: "John Doe") | ||
119 | - user ||= create(:user, name: "John Doe", username: "john_doe") | 113 | + user = user_exists("John Doe", username: "john_doe") |
120 | project = Project.find_by(name: "Internal") | 114 | project = Project.find_by(name: "Internal") |
121 | project ||= create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL | 115 | project ||= create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL |
122 | project.team << [user, :master] | 116 | project.team << [user, :master] |
123 | end | 117 | end |
124 | 118 | ||
125 | step '"John Doe" is authorized to public project "Community"' do | 119 | step '"John Doe" is authorized to public project "Community"' do |
126 | - user = User.find_by(name: "John Doe") | ||
127 | - user ||= create(:user, name: "John Doe", username: "john_doe") | 120 | + user = user_exists("John Doe", username: "john_doe") |
128 | project = Project.find_by(name: "Community") | 121 | project = Project.find_by(name: "Community") |
129 | project ||= create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC | 122 | project ||= create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC |
130 | project.team << [user, :master] | 123 | project.team << [user, :master] |
features/steps/shared/user.rb
1 | module SharedUser | 1 | module SharedUser |
2 | include Spinach::DSL | 2 | include Spinach::DSL |
3 | 3 | ||
4 | - step 'Create user "John Doe"' do | ||
5 | - create(:user, name: "John Doe", username: "john_doe") | 4 | + step 'User "John Doe" exists' do |
5 | + user_exists("John Doe", {username: "john_doe"}) | ||
6 | end | 6 | end |
7 | 7 | ||
8 | - step 'I sign in as "John Doe"' do | ||
9 | - login_with(User.find_by(name: "John Doe")) | 8 | + step 'User "Mary Jane" exists' do |
9 | + user_exists("Mary Jane", {username: "mary_jane"}) | ||
10 | + end | ||
11 | + | ||
12 | + protected | ||
13 | + | ||
14 | + def user_exists(name, options = {}) | ||
15 | + User.find_by(name: name) || create(:user, {name: name, admin: false}.merge(options)) | ||
10 | end | 16 | end |
11 | end | 17 | end |
features/user.feature