diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index a492e666..54c69138 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -1,5 +1,5 @@ class Admin::GroupsController < AdminController - before_filter :group, only: [:edit, :show, :update, :destroy, :project_update] + before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :project_teams_update] def index @groups = Group.order('name ASC') @@ -12,6 +12,8 @@ class Admin::GroupsController < AdminController @projects = @projects.not_in_group(@group) if @group.projects.present? @projects = @projects.all @projects.reject!(&:empty_repo?) + + @users = User.active end def new @@ -65,6 +67,11 @@ class Admin::GroupsController < AdminController redirect_to :back, notice: 'Group was successfully updated.' end + def project_teams_update + @group.add_users_to_project_teams(params[:user_ids], params[:project_access]) + redirect_to [:admin, @group], notice: 'Users was successfully added.' + end + def destroy @group.destroy diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index c82edb4c..6646b10c 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -53,9 +53,16 @@ class GroupsController < ApplicationController if @project @team_member = @project.users_projects.new + else + @team_member = UsersProject.new end end + def team_members + @group.add_users_to_project_teams(params[:user_ids], params[:project_access]) + redirect_to people_group_path(@group), notice: 'Users was successfully added.' + end + protected def group diff --git a/app/models/group.rb b/app/models/group.rb index b668f556..5022fcf4 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -12,6 +12,12 @@ # class Group < Namespace + def add_users_to_project_teams(user_ids, project_access) + projects.each do |project| + project.add_users_ids_to_team(user_ids, project_access) + end + end + def users users = User.joins(:users_projects).where(users_projects: {project_id: project_ids}) users = users << owner diff --git a/app/models/project.rb b/app/models/project.rb index c2986707..bfab009e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -64,7 +64,9 @@ class Project < ActiveRecord::Base # Validations validates :owner, presence: true validates :description, length: { within: 0..2000 } - validates :name, presence: true, length: { within: 0..255 } + validates :name, presence: true, length: { within: 0..255 }, + format: { with: Gitlab::Regex.project_name_regex, + message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } validates :path, presence: true, length: { within: 0..255 }, format: { with: Gitlab::Regex.path_regex, message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } @@ -80,6 +82,7 @@ class Project < ActiveRecord::Base scope :public_only, where(private_flag: false) scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.projects.map(&:id) ) } scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) } + scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) } scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") } scope :personal, ->(user) { where(namespace_id: user.namespace_id) } scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 3d76a4df..34377aa5 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -33,6 +33,8 @@ class UsersProject < ActiveRecord::Base delegate :name, :email, to: :user, prefix: true + scope :in_project, ->(project) { where(project_id: project.id) } + class << self def import_team(source_project, target_project) UsersProject.without_repository_callback do diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 41f6d9b3..d289d9d5 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -44,25 +44,56 @@ %div = f.submit 'Change Owner', class: "btn danger" = link_to "Cancel", "#", class: "btn change-owner-cancel-link" -%fieldset - %legend Projects (#{@group.projects.count}) - %table - %thead - %tr - %th Project name - %th Path - %th Users - %th.cred Danger Zone! - - @group.projects.each do |project| - %tr - %td - = link_to project.name_with_namespace, [:admin, project] - %td - %span.monospace= project.path_with_namespace + ".git" - %td= project.users.count - %td.bgred - = link_to 'Transfer project to global namespace', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Remove project from group and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" +- if @group.projects.any? + %fieldset + %legend Projects (#{@group.projects.count}) + %table + %thead + %tr + %th Project name + %th Path + %th Users + %th.cred Danger Zone! + - @group.projects.each do |project| + %tr + %td + = link_to project.name_with_namespace, [:admin, project] + %td + %span.monospace= project.path_with_namespace + ".git" + %td= project.users.count + %td.bgred + = link_to 'Transfer project to global namespace', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Remove project from group and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + + = form_tag project_teams_update_admin_group_path(@group), id: "new_team_member", class: "bulk_import", method: :put do + %table.zebra-striped + %thead + %tr + %th Users + %th Project Access: + + - @group.users.each do |u| + %tr{class: "user_#{u.id}"} + %td.name= link_to u.name, admin_user_path(u) + %td.projects_access + - u.projects.in_namespace(@group).each do |project| + - u_p = u.users_projects.in_project(project).first + %span + = project.name + = link_to "(#{ u_p.project_access_human })", edit_admin_team_member_path(u_p) + %tr + %td.input= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' + %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"} + + %tr + %td= submit_tag 'Add user to projects in group', class: "btn primary" + %td + Read more about project permissions + %strong= link_to "here", help_permissions_path, class: "vlink" + +- else + %fieldset + %legend Group is empty = form_tag project_update_admin_group_path(@group), class: "bulk_import", method: :put do %fieldset diff --git a/app/views/groups/_new_group_member.html.haml b/app/views/groups/_new_group_member.html.haml new file mode 100644 index 00000000..75023057 --- /dev/null +++ b/app/views/groups/_new_group_member.html.haml @@ -0,0 +1,18 @@ += form_for @team_member, as: :team_member, url: team_members_group_path(@group) do |f| + %fieldset + %legend= "New Team member(s) for projects in #{@group.name}" + + %h6 1. Choose people you want in the team + .clearfix + = f.label :user_ids, "People" + .input= select_tag(:user_ids, options_from_collection_for_select(User.active, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) + + %h6 2. Set access level for them + .clearfix + = f.label :project_access, "Project Access" + .input= select_tag :project_access, options_for_select(Project.access_options, @team_member.project_access), class: "project-access-select chosen" + + .form-actions + = hidden_field_tag :redirect_to, people_group_path(@group) + = f.submit 'Add', class: "btn save-btn" + diff --git a/app/views/groups/people.html.haml b/app/views/groups/people.html.haml index be3dd7a4..091f6875 100644 --- a/app/views/groups/people.html.haml +++ b/app/views/groups/people.html.haml @@ -2,8 +2,8 @@ .span3 = render 'people_filter' .span9 - - if @project && can?(current_user, :manage_group, @group) - = render "new_member" + - if can?(current_user, :manage_group, @group) + = render (@project ? "new_member" : "new_group_member") .ui-box %h5 Team diff --git a/config/routes.rb b/config/routes.rb index 4317962f..4a02bd9f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -47,6 +47,7 @@ Gitlab::Application.routes.draw do resources :groups, constraints: { id: /[^\/]+/ } do member do put :project_update + put :project_teams_update delete :remove_project end end @@ -102,6 +103,7 @@ Gitlab::Application.routes.draw do get :merge_requests get :search get :people + post :team_members end end diff --git a/features/admin/groups.feature b/features/admin/groups.feature index e5eab8e6..28f35e3a 100644 --- a/features/admin/groups.feature +++ b/features/admin/groups.feature @@ -1,6 +1,8 @@ Feature: Admin Groups Background: Given I sign in as an admin + And I have group with projects + And Create gitlab user "John" And I visit admin groups page Scenario: Create a group @@ -8,3 +10,8 @@ Feature: Admin Groups And submit form with new group info Then I should be redirected to group page And I should see newly created group + + Scenario: Add user into projects in group + When I visit admin group page + When I select user "John" from user list as "Reporter" + Then I should see "John" in team list in every project as "Reporter" diff --git a/features/group/group.feature b/features/group/group.feature index 07308112..580f7e44 100644 --- a/features/group/group.feature +++ b/features/group/group.feature @@ -17,3 +17,9 @@ Feature: Groups Given project from group has merge requests assigned to me When I visit group merge requests page Then I should see merge requests from this group assigned to me + + Scenario: I should add user to projects in Group + Given I have new user "John" + When I visit group people page + And I select user "John" from list with role "Reporter" + Then I should see user "John" in team list diff --git a/features/steps/admin/admin_groups.rb b/features/steps/admin/admin_groups.rb index 5386f473..0271348e 100644 --- a/features/steps/admin/admin_groups.rb +++ b/features/steps/admin/admin_groups.rb @@ -3,10 +3,26 @@ class AdminGroups < Spinach::FeatureSteps include SharedPaths include SharedActiveTab + When 'I visit admin group page' do + visit admin_group_path(current_group) + end + When 'I click new group link' do click_link "New Group" end + And 'I have group with projects' do + @group = create(:group) + @project = create(:project, group: @group) + @event = create(:closed_issue_event, project: @project) + + @project.add_access current_user, :admin + end + + And 'Create gitlab user "John"' do + create(:user, :name => "John") + end + And 'submit form with new group info' do fill_in 'group_name', :with => 'gitlab' click_button "Create group" @@ -19,5 +35,27 @@ class AdminGroups < Spinach::FeatureSteps Then 'I should be redirected to group page' do current_path.should == admin_group_path(Group.last) end + + When 'I select user "John" from user list as "Reporter"' do + user = User.find_by_name("John") + within "#new_team_member" do + select user.name, :from => "user_ids" + select "Reporter", :from => "project_access" + end + click_button "Add user to projects in group" + end + + Then 'I should see "John" in team list in every project as "Reporter"' do + user = User.find_by_name("John") + projects_with_access = find(".user_#{user.id} .projects_access") + projects_with_access.should have_link("Reporter") + end + + protected + + def current_group + @group ||= Group.first + end + end diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index 4de260ec..02a1dd13 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -9,7 +9,7 @@ class Groups < Spinach::FeatureSteps end And 'I have group with projects' do - @group = create(:group) + @group = create(:group, owner: current_user) @project = create(:project, group: @group) @event = create(:closed_issue_event, project: @project) @@ -32,6 +32,24 @@ class Groups < Spinach::FeatureSteps end end + Given 'I have new user "John"' do + create(:user, name: "John") + end + + And 'I select user "John" from list with role "Reporter"' do + user = User.find_by_name("John") + within "#new_team_member" do + select user.name, :from => "user_ids" + select "Reporter", :from => "project_access" + end + click_button "Add" + end + + Then 'I should see user "John" in team list' do + projects_with_access = find(".ui-box .well-list") + projects_with_access.should have_content("John") + end + Given 'project from group has issues assigned to me' do create :issue, project: project, diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index a1257628..bd43ba6b 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -21,6 +21,10 @@ module SharedPaths visit merge_requests_group_path(current_group) end + When 'I visit group people page' do + visit people_group_path(current_group) + end + # ---------------------------------------- # Dashboard # ---------------------------------------- diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index a3f38b1c..e0fb47da 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -6,6 +6,10 @@ module Gitlab default_regex end + def project_name_regex + default_regex + end + def path_regex default_regex end