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 | 135 | end |
| 136 | 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 | 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 | 144 | end |
| 145 | 145 | |
| 146 | 146 | def require_non_empty_project | ... | ... |
app/controllers/profiles/groups_controller.rb
| ... | ... | @@ -7,12 +7,11 @@ class Profiles::GroupsController < ApplicationController |
| 7 | 7 | |
| 8 | 8 | def leave |
| 9 | 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 | 11 | @users_group.destroy |
| 15 | 12 | redirect_to(profile_groups_path, info: "You left #{group.name} group.") |
| 13 | + else | |
| 14 | + return render_403 | |
| 16 | 15 | end |
| 17 | 16 | end |
| 18 | 17 | ... | ... |
app/controllers/users_groups_controller.rb
| ... | ... | @@ -19,11 +19,14 @@ class UsersGroupsController < ApplicationController |
| 19 | 19 | |
| 20 | 20 | def destroy |
| 21 | 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 | 30 | end |
| 28 | 31 | end |
| 29 | 32 | ... | ... |
app/helpers/groups_helper.rb
| 1 | 1 | module GroupsHelper |
| 2 | 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 | 8 | end |
| 5 | 9 | |
| 6 | 10 | def group_head_title | ... | ... |
app/models/ability.rb
| ... | ... | @@ -14,6 +14,7 @@ class Ability |
| 14 | 14 | when "MergeRequest" then merge_request_abilities(user, subject) |
| 15 | 15 | when "Group" then group_abilities(user, subject) |
| 16 | 16 | when "Namespace" then namespace_abilities(user, subject) |
| 17 | + when "UsersGroup" then users_group_abilities(user, subject) | |
| 17 | 18 | else [] |
| 18 | 19 | end.concat(global_abilities(user)) |
| 19 | 20 | end |
| ... | ... | @@ -219,5 +220,19 @@ class Ability |
| 219 | 220 | end |
| 220 | 221 | end |
| 221 | 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 | 237 | end |
| 223 | 238 | end | ... | ... |
app/views/groups/members.html.haml
| ... | ... | @@ -6,7 +6,6 @@ |
| 6 | 6 | %strong= link_to "here", help_permissions_path, class: "vlink" |
| 7 | 7 | |
| 8 | 8 | %hr |
| 9 | -- can_manage_group = current_user.can? :manage_group, @group | |
| 10 | 9 | .ui-box |
| 11 | 10 | .title |
| 12 | 11 | %strong #{@group.name} |
| ... | ... | @@ -15,6 +14,6 @@ |
| 15 | 14 | (#{@members.count}) |
| 16 | 15 | %ul.well-list |
| 17 | 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 | 19 | = render "new_group_member" | ... | ... |
app/views/help/permissions.html.haml
app/views/profiles/groups/index.html.haml
| ... | ... | @@ -22,9 +22,10 @@ |
| 22 | 22 | %i.icon-cogs |
| 23 | 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 | 30 | = link_to group, class: 'group-name' do |
| 30 | 31 | %strong= group.name | ... | ... |
app/views/users_groups/_users_group.html.haml
| ... | ... | @@ -9,12 +9,17 @@ |
| 9 | 9 | |
| 10 | 10 | %span.pull-right |
| 11 | 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 | 24 | .edit-member.hide.js-toggle-content |
| 20 | 25 | = form_for [@group, member], remote: true do |f| | ... | ... |
features/admin/groups.feature
| ... | ... | @@ -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 | -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 | -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 @@ |
| 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 | 1 | class Groups < Spinach::FeatureSteps |
| 2 | 2 | include SharedAuthentication |
| 3 | 3 | include SharedPaths |
| 4 | + include SharedGroup | |
| 4 | 5 | include SharedUser |
| 5 | 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 | 10 | page.should have_link project.name |
| 10 | 11 | end |
| 11 | 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 | 14 | And 'I should see projects activity feed' do |
| 23 | 15 | page.should have_content 'closed issue' |
| 24 | 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 | 19 | assigned_to_me(:issues).each do |issue| |
| 28 | 20 | page.should have_content issue.title |
| 29 | 21 | end |
| 30 | 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 | 25 | assigned_to_me(:merge_requests).each do |issue| |
| 34 | 26 | page.should have_content issue.title[0..80] |
| 35 | 27 | end |
| 36 | 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 | 32 | within ".users-group-form" do |
| 41 | 33 | select2(user.id, from: "#user_ids", multiple: true) |
| 42 | 34 | select "Reporter", from: "group_access" |
| ... | ... | @@ -49,14 +41,29 @@ class Groups < Spinach::FeatureSteps |
| 49 | 41 | projects_with_access.should have_content("John Doe") |
| 50 | 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 | 60 | create :issue, |
| 54 | 61 | project: project, |
| 55 | 62 | assignee: current_user, |
| 56 | 63 | author: current_user |
| 57 | 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 | 67 | create :merge_request, |
| 61 | 68 | source_project: project, |
| 62 | 69 | target_project: project, |
| ... | ... | @@ -68,78 +75,94 @@ class Groups < Spinach::FeatureSteps |
| 68 | 75 | click_link "New group" |
| 69 | 76 | end |
| 70 | 77 | |
| 71 | - And 'submit form with new group info' do | |
| 78 | + And 'submit form with new group "Samurai" info' do | |
| 72 | 79 | fill_in 'group_name', with: 'Samurai' |
| 73 | 80 | fill_in 'group_description', with: 'Tokugawa Shogunate' |
| 74 | 81 | click_button "Create group" |
| 75 | 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 | 89 | page.should have_content "Samurai" |
| 79 | 90 | page.should have_content "Tokugawa Shogunate" |
| 80 | 91 | page.should have_content "You will only see events from projects in this group" |
| 81 | 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 | 95 | fill_in 'group_name', with: 'new-name' |
| 89 | 96 | click_button "Save group" |
| 90 | 97 | end |
| 91 | 98 | |
| 92 | - Then 'I should see new group name' do | |
| 99 | + Then 'I should see new group "Owned" name' do | |
| 93 | 100 | within ".navbar-gitlab" do |
| 94 | 101 | page.should have_content "group: new-name" |
| 95 | 102 | end |
| 96 | 103 | end |
| 97 | 104 | |
| 98 | - step 'I change my group avatar' do | |
| 105 | + step 'I change group "Owned" avatar' do | |
| 99 | 106 | attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) |
| 100 | 107 | click_button "Save group" |
| 101 | - @group.reload | |
| 108 | + Group.find_by(name: "Owned").reload | |
| 102 | 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 | 114 | end |
| 108 | 115 | |
| 109 | 116 | step 'I should see the "Remove avatar" button' do |
| 110 | 117 | page.should have_link("Remove avatar") |
| 111 | 118 | end |
| 112 | 119 | |
| 113 | - step 'I have an group avatar' do | |
| 120 | + step 'I have group "Owned" avatar' do | |
| 114 | 121 | attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) |
| 115 | 122 | click_button "Save group" |
| 116 | - @group.reload | |
| 123 | + Group.find_by(name: "Owned").reload | |
| 117 | 124 | end |
| 118 | 125 | |
| 119 | - step 'I remove my group avatar' do | |
| 126 | + step 'I remove group "Owned" avatar' do | |
| 120 | 127 | click_link "Remove avatar" |
| 121 | - @group.reload | |
| 128 | + Group.find_by(name: "Owned").reload | |
| 122 | 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 | 133 | end |
| 127 | 134 | |
| 128 | 135 | step 'I should not see the "Remove avatar" button' do |
| 129 | 136 | page.should_not have_link("Remove avatar") |
| 130 | 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 | 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 | 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 | 161 | def assigned_to_me key |
| 143 | 162 | project.send(key).where(assignee_id: current_user.id) |
| 144 | 163 | end |
| 164 | + | |
| 165 | + def project | |
| 166 | + Group.find_by(name: "Owned").projects.first | |
| 167 | + end | |
| 145 | 168 | end | ... | ... |
| ... | ... | @@ -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
features/steps/shared/authentication.rb
| ... | ... | @@ -12,6 +12,14 @@ module SharedAuthentication |
| 12 | 12 | login_as :admin |
| 13 | 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 | 23 | step 'I should be redirected to sign in page' do |
| 16 | 24 | current_path.should == new_user_session_path |
| 17 | 25 | end | ... | ... |
| ... | ... | @@ -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 | 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 | 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 | 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 | 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 | 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 | 58 | end |
| 39 | 59 | |
| 40 | 60 | # ---------------------------------------- |
| ... | ... | @@ -93,6 +113,14 @@ module SharedPaths |
| 93 | 113 | visit history_profile_path |
| 94 | 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 | 125 | # Admin |
| 98 | 126 | # ---------------------------------------- |
| ... | ... | @@ -326,4 +354,12 @@ module SharedPaths |
| 326 | 354 | def project |
| 327 | 355 | project = Project.find_by!(name: "Shop") |
| 328 | 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 | 365 | end | ... | ... |
features/steps/shared/project.rb
| ... | ... | @@ -58,10 +58,6 @@ module SharedProject |
| 58 | 58 | page.should have_content("Features:") |
| 59 | 59 | end |
| 60 | 60 | |
| 61 | - Then 'page status code should be 404' do | |
| 62 | - page.status_code.should == 404 | |
| 63 | - end | |
| 64 | - | |
| 65 | 61 | def current_project |
| 66 | 62 | @project ||= Project.first |
| 67 | 63 | end |
| ... | ... | @@ -107,24 +103,21 @@ module SharedProject |
| 107 | 103 | end |
| 108 | 104 | |
| 109 | 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 | 107 | project = Project.find_by(name: "Enterprise") |
| 113 | 108 | project ||= create(:project, name: "Enterprise", namespace: user.namespace) |
| 114 | 109 | project.team << [user, :master] |
| 115 | 110 | end |
| 116 | 111 | |
| 117 | 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 | 114 | project = Project.find_by(name: "Internal") |
| 121 | 115 | project ||= create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL |
| 122 | 116 | project.team << [user, :master] |
| 123 | 117 | end |
| 124 | 118 | |
| 125 | 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 | 121 | project = Project.find_by(name: "Community") |
| 129 | 122 | project ||= create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC |
| 130 | 123 | project.team << [user, :master] | ... | ... |
features/steps/shared/user.rb
| 1 | 1 | module SharedUser |
| 2 | 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 | 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 | 16 | end |
| 11 | 17 | end | ... | ... |