BigW Consortium Gitlab

Commit 30d2d238 by Dmitriy Zaporozhets

Merge branch 'feature/users_groups' into 6-0-dev

parents cc5440e8 60bb3516
...@@ -32,6 +32,8 @@ class Dispatcher ...@@ -32,6 +32,8 @@ class Dispatcher
new Wall(project_id) new Wall(project_id)
when 'teams:members:index' when 'teams:members:index'
new TeamMembers() new TeamMembers()
when 'groups:people'
new GroupMembers()
switch path.first() switch path.first()
when 'admin' then new Admin() when 'admin' then new Admin()
......
class GroupMembers
constructor: ->
$('li.users_group').bind 'ajax:success', ->
$(this).fadeOut()
@GroupMembers = GroupMembers
...@@ -16,6 +16,12 @@ ...@@ -16,6 +16,12 @@
color: #888; color: #888;
} }
&.unstyled {
&:hover {
background: none;
}
}
&.smoke { background-color: #f5f5f5; } &.smoke { background-color: #f5f5f5; }
&:hover { &:hover {
......
...@@ -66,14 +66,12 @@ class Admin::GroupsController < Admin::ApplicationController ...@@ -66,14 +66,12 @@ class Admin::GroupsController < Admin::ApplicationController
end end
def project_teams_update def project_teams_update
@group.add_users_to_project_teams(params[:user_ids].split(','), params[:project_access]) @group.add_users(params[:user_ids].split(','), params[:group_access])
redirect_to [:admin, @group], notice: 'Users were successfully added.' redirect_to [:admin, @group], notice: 'Users were successfully added.'
end end
def destroy def destroy
@group.truncate_teams
@group.destroy @group.destroy
redirect_to admin_groups_path, notice: 'Group was successfully deleted.' redirect_to admin_groups_path, notice: 'Group was successfully deleted.'
......
...@@ -34,11 +34,12 @@ class DashboardController < ApplicationController ...@@ -34,11 +34,12 @@ class DashboardController < ApplicationController
@projects @projects
end end
@projects = @projects.tagged_with(params[:label]) if params[:label].present?
@projects = @projects.search(params[:search]) if params[:search].present? @projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.page(params[:page]).per(30)
@labels = Project.where(id: @projects.map(&:id)).tags_on(:labels) @labels = Project.where(id: @projects.map(&:id)).tags_on(:labels)
@projects = @projects.tagged_with(params[:label]) if params[:label].present?
@projects = @projects.page(params[:page]).per(30)
end end
# Get authored or assigned open merge requests # Get authored or assigned open merge requests
......
...@@ -10,7 +10,7 @@ class GraphsController < ProjectResourceController ...@@ -10,7 +10,7 @@ class GraphsController < ProjectResourceController
format.js do format.js do
@repo = @project.repository @repo = @project.repository
@stats = Gitlab::Git::GitStats.new(@repo.raw, @repo.root_ref) @stats = Gitlab::Git::GitStats.new(@repo.raw, @repo.root_ref)
@log = @stats.parsed_log.to_json @log = @stats.parsed_log.to_json rescue []
end end
end end
end end
......
class GroupsController < ApplicationController class GroupsController < ApplicationController
respond_to :html respond_to :html
before_filter :group, except: [:new, :create] before_filter :group, except: [:new, :create, :people]
# Authorize # Authorize
before_filter :authorize_read_group!, except: [:new, :create] before_filter :authorize_read_group!, except: [:new, :create]
...@@ -63,19 +63,8 @@ class GroupsController < ApplicationController ...@@ -63,19 +63,8 @@ class GroupsController < ApplicationController
def people def people
@project = group.projects.find(params[:project_id]) if params[:project_id] @project = group.projects.find(params[:project_id]) if params[:project_id]
@users = @project ? @project.users : group.users @members = group.users_groups.order('group_access DESC')
@users.sort_by!(&:name) @users_group = UsersGroup.new
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].split(','), params[:project_access])
redirect_to people_group_path(@group), notice: 'Users were successfully added.'
end end
def edit def edit
...@@ -83,7 +72,7 @@ class GroupsController < ApplicationController ...@@ -83,7 +72,7 @@ class GroupsController < ApplicationController
def update def update
group_params = params[:group].dup group_params = params[:group].dup
owner_id =group_params.delete(:owner_id) owner_id = group_params.delete(:owner_id)
if owner_id if owner_id
@group.owner = User.find(owner_id) @group.owner = User.find(owner_id)
......
...@@ -23,7 +23,7 @@ class IssuesController < ProjectResourceController ...@@ -23,7 +23,7 @@ class IssuesController < ProjectResourceController
assignee_id, milestone_id = params[:assignee_id], params[:milestone_id] assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
@assignee = @project.users.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero? @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
@milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
respond_to do |format| respond_to do |format|
......
...@@ -4,10 +4,8 @@ class TeamMembersController < ProjectResourceController ...@@ -4,10 +4,8 @@ class TeamMembersController < ProjectResourceController
before_filter :authorize_admin_project!, except: [:index, :show] before_filter :authorize_admin_project!, except: [:index, :show]
def index def index
@team = @project.users_projects.scoped @group = @project.group
@team = @team.send(params[:type]) if %w(masters developers reporters guests).include?(params[:type]) @users_projects = @project.users_projects.order('project_access DESC')
@team = @team.sort_by(&:project_access).reverse.group_by(&:project_access)
@assigned_teams = @project.user_team_project_relationships @assigned_teams = @project.user_team_project_relationships
end end
......
...@@ -3,7 +3,7 @@ class UsersController < ApplicationController ...@@ -3,7 +3,7 @@ class UsersController < ApplicationController
def show def show
@user = User.find_by_username!(params[:username]) @user = User.find_by_username!(params[:username])
@projects = @user.authorized_projects.where('projects.id in (?)', current_user.authorized_projects.map(&:id)) @projects = @user.authorized_projects.where('projects.id in (?)', current_user.authorized_projects.map(&:id)).order('namespace_id DESC')
@events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20) @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20)
@title = @user.name @title = @user.name
......
class UsersGroupsController < ApplicationController
before_filter :group
# Authorize
before_filter :authorize_admin_group!
layout 'group'
def create
@group.add_users(params[:user_ids].split(','), params[:group_access])
redirect_to people_group_path(@group), notice: 'Users were successfully added.'
end
def update
# TODO: implement
end
def destroy
@users_group = @group.users_groups.find(params[:id])
@users_group.destroy
respond_to do |format|
format.html { redirect_to people_group_path(@group), notice: 'User was successfully removed from group.' }
format.js { render nothing: true }
end
end
protected
def group
@group ||= Group.find_by_path(params[:group_id])
end
def authorize_admin_group!
unless can?(current_user, :manage_group, group)
return render_404
end
end
end
...@@ -14,4 +14,8 @@ module GroupsHelper ...@@ -14,4 +14,8 @@ module GroupsHelper
merge_requests_group_path(@group, options) merge_requests_group_path(@group, options)
end end
end end
def remove_user_from_group_message(group, user)
"You are going to remove #{user.name} from #{group.name} Group. Are you sure?"
end
end end
...@@ -50,6 +50,10 @@ class Ability ...@@ -50,6 +50,10 @@ class Ability
rules << project_admin_rules rules << project_admin_rules
end end
if project.group && project.group.owners.include?(user)
rules << project_admin_rules
end
rules.flatten rules.flatten
end end
...@@ -132,7 +136,7 @@ class Ability ...@@ -132,7 +136,7 @@ class Ability
rules = [] rules = []
# Only group owner and administrators can manage group # Only group owner and administrators can manage group
if group.owner == user || user.admin? if group.owners.include?(user) || user.admin?
rules << [ rules << [
:manage_group, :manage_group,
:manage_namespace :manage_namespace
......
...@@ -13,26 +13,28 @@ ...@@ -13,26 +13,28 @@
# #
class Group < Namespace class Group < Namespace
has_many :users_groups, dependent: :destroy
has_many :users, through: :users_groups
def add_users_to_project_teams(user_ids, project_access) after_create :add_owner
UsersProject.add_users_into_projects(
projects.map(&:id), def human_name
user_ids, name
project_access
)
end end
def users def owners
users = User.joins(:users_projects).where(users_projects: {project_id: project_ids}) @owners ||= (users_groups.owners.map(&:user) << owner)
users = users << owner
users.uniq
end end
def human_name def add_users(user_ids, group_access)
name user_ids.compact.each do |user_id|
self.users_groups.create(user_id: user_id, group_access: group_access)
end
end end
def truncate_teams private
UsersProject.truncate_teams(project_ids)
def add_owner
self.add_users([owner.id], UsersGroup::OWNER)
end end
end end
...@@ -21,6 +21,16 @@ class ProjectTeam ...@@ -21,6 +21,16 @@ class ProjectTeam
end end
end end
def find user_id
user = project.users.find_by_id(user_id)
if group
user ||= group.users.find_by_id(user_id)
end
user
end
def get_tm user_id def get_tm user_id
project.users_projects.find_by_user_id(user_id) project.users_projects.find_by_user_id(user_id)
end end
...@@ -47,23 +57,23 @@ class ProjectTeam ...@@ -47,23 +57,23 @@ class ProjectTeam
end end
def members def members
project.users_projects fetch_members
end end
def guests def guests
members.guests.map(&:user) @guests ||= fetch_members(:guests)
end end
def reporters def reporters
members.reporters.map(&:user) @reporters ||= fetch_members(:reporters)
end end
def developers def developers
members.developers.map(&:user) @developers ||= fetch_members(:developers)
end end
def masters def masters
members.masters.map(&:user) @masters ||= fetch_members(:masters)
end end
def import(source_project) def import(source_project)
...@@ -96,4 +106,22 @@ class ProjectTeam ...@@ -96,4 +106,22 @@ class ProjectTeam
rescue rescue
false false
end end
private
def fetch_members(level = nil)
project_members = project.users_projects
group_members = group ? group.users_groups : []
if level
project_members = project_members.send(level)
group_members = group_members.send(level) if group
end
(project_members + group_members).map(&:user).uniq
end
def group
project.group
end
end end
...@@ -71,7 +71,9 @@ class User < ActiveRecord::Base ...@@ -71,7 +71,9 @@ class User < ActiveRecord::Base
has_many :keys, dependent: :destroy has_many :keys, dependent: :destroy
# Groups # Groups
has_many :groups, class_name: "Group", foreign_key: :owner_id has_many :own_groups, class_name: "Group", foreign_key: :owner_id
has_many :users_groups, dependent: :destroy
has_many :groups, through: :users_groups
# Teams # Teams
has_many :own_teams, dependent: :destroy, class_name: "UserTeam", foreign_key: :owner_id has_many :own_teams, dependent: :destroy, class_name: "UserTeam", foreign_key: :owner_id
...@@ -230,7 +232,7 @@ class User < ActiveRecord::Base ...@@ -230,7 +232,7 @@ class User < ActiveRecord::Base
# Groups where user is an owner # Groups where user is an owner
def owned_groups def owned_groups
groups own_groups
end end
def owned_teams def owned_teams
...@@ -239,14 +241,14 @@ class User < ActiveRecord::Base ...@@ -239,14 +241,14 @@ class User < ActiveRecord::Base
# Groups user has access to # Groups user has access to
def authorized_groups def authorized_groups
@group_ids ||= (groups.pluck(:id) + authorized_projects.pluck(:namespace_id)) @group_ids ||= (groups.pluck(:id) + own_groups.pluck(:id) + authorized_projects.pluck(:namespace_id))
Group.where(id: @group_ids) Group.where(id: @group_ids)
end end
# Projects user has access to # Projects user has access to
def authorized_projects def authorized_projects
@project_ids ||= (owned_projects.pluck(:id) + projects.pluck(:id)).uniq @project_ids ||= (owned_projects.pluck(:id) + groups.map(&:projects).flatten.map(&:id) + projects.pluck(:id)).uniq
Project.where(id: @project_ids) Project.where(id: @project_ids)
end end
......
class UsersGroup < ActiveRecord::Base
GUEST = 10
REPORTER = 20
DEVELOPER = 30
MASTER = 40
OWNER = 50
def self.group_access_roles
{
"Guest" => GUEST,
"Reporter" => REPORTER,
"Developer" => DEVELOPER,
"Master" => MASTER,
"Owner" => OWNER
}
end
attr_accessible :group_access, :user_id
belongs_to :user
belongs_to :group
scope :guests, -> { where(group_access: GUEST) }
scope :reporters, -> { where(group_access: REPORTER) }
scope :developers, -> { where(group_access: DEVELOPER) }
scope :masters, -> { where(group_access: MASTER) }
scope :owners, -> { where(group_access: OWNER) }
scope :with_group, ->(group) { where(group_id: group.id) }
scope :with_user, ->(user) { where(user_id: user.id) }
validates :group_access, inclusion: { in: UsersGroup.group_access_roles.values }, presence: true
validates :user_id, presence: true
validates :group_id, presence: true
validates :user_id, uniqueness: { scope: [:group_id], message: "already exists in group" }
delegate :name, :username, :email, to: :user, prefix: true
def human_access
UsersGroup.group_access_roles.key(self.group_access)
end
end
...@@ -129,9 +129,7 @@ class UsersProject < ActiveRecord::Base ...@@ -129,9 +129,7 @@ class UsersProject < ActiveRecord::Base
Project.access_options.key(self.project_access) Project.access_options.key(self.project_access)
end end
def repo_access_human alias_method :human_access, :project_access_human
self.class.access_roles.invert[self.project_access]
end
def skip_git? def skip_git?
!!@skip_git !!@skip_git
......
...@@ -43,7 +43,7 @@ class SystemHooksService ...@@ -43,7 +43,7 @@ class SystemHooksService
project_id: model.project_id, project_id: model.project_id,
user_name: model.user.name, user_name: model.user.name,
user_email: model.user.email, user_email: model.user.email,
project_access: model.repo_access_human project_access: model.project_access_human
}) })
end end
end end
......
...@@ -49,10 +49,23 @@ ...@@ -49,10 +49,23 @@
%strong %strong
= @group.created_at.stamp("March 1, 1999") = @group.created_at.stamp("March 1, 1999")
.ui-box
%h5.title
Projects
%small
(#{@group.projects.count})
%ul.well-list
- @group.projects.sort_by(&:name).each do |project|
%li
%strong
= link_to project.name_with_namespace, [:admin, project]
%span.pull-right.light
%span.monospace= project.path_with_namespace + ".git"
.span6
.ui-box .ui-box
%h5.title %h5.title
Add user to Group projects: Add user(s):
.ui-box-body.form-holder .ui-box-body.form-holder
%p.light %p.light
Read more about project permissions Read more about project permissions
...@@ -64,30 +77,18 @@ ...@@ -64,30 +77,18 @@
%div.prepend-top-10 %div.prepend-top-10
= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span2"} = select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span2"}
%hr %hr
= submit_tag 'Add user to projects in group', class: "btn btn-create" = submit_tag 'Add users into group', class: "btn btn-create"
.ui-box .ui-box
%h5.title %h5.title
Users from Group projects Users from #{@group.name} Group
%small %small
(#{@group.users.count}) (#{@group.users_groups.count})
%ul.well-list %ul.well-list
- @group.users.sort_by(&:name).each do |user| - @group.users_groups.order('group_access DESC').each do |member|
- user = member.user
%li{class: dom_class(user)} %li{class: dom_class(user)}
%strong %strong
= link_to user.name, admin_user_path(user) = link_to user.name, admin_user_path(user)
%span.pull-right.light %span.pull-right.light
= pluralize user.authorized_projects.in_namespace(@group).count, 'project' = member.human_access
.span6
.ui-box
%h5.title
Projects
%small
(#{@group.projects.count})
%ul.well-list
- @group.projects.sort_by(&:name).each do |project|
%li
%strong
= link_to project.name_with_namespace, [:admin, project]
%span.pull-right.light
%span.monospace= project.path_with_namespace + ".git"
= form_for @team_member, as: :team_member, url: team_members_group_path(@group) do |f| = form_for @users_group, url: group_users_groups_path(@group) do |f|
%fieldset %fieldset
%legend= "New Team member(s) for projects in #{@group.name}" %legend= "New Group member(s) for #{@group.name}"
%h6 1. Choose people you want in the team %h6 1. Choose people you want in the group
.clearfix .clearfix
= f.label :user_ids, "People" = f.label :user_ids, "People"
.input= users_select_tag(:user_ids, multiple: true) .input= users_select_tag(:user_ids, multiple: true, class: 'input-large')
%h6 2. Set access level for them %h6 2. Set access level for them
.clearfix .clearfix
= f.label :project_access, "Project Access" = f.label :group_access, "Group Access"
.input= select_tag :project_access, options_for_select(Project.access_options, @team_member.project_access), class: "project-access-select chosen" .input= select_tag :group_access, options_for_select(UsersGroup.group_access_roles, @users_group.group_access), class: "project-access-select chosen"
.form-actions .form-actions
= hidden_field_tag :redirect_to, people_group_path(@group) = hidden_field_tag :redirect_to, people_group_path(@group)
= f.submit 'Add', class: "btn btn-save" = f.submit 'Add users into group', class: "btn btn-create"
= form_for @team_member, as: :team_member, url: project_team_members_path(@project, @team_member) do |f|
%fieldset
%legend= "New Team member(s) for #{@project.name}"
%h6 1. Choose people you want in the team
.clearfix
= f.label :user_ids, "People"
.input= users_select_tag(:user_ids, 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, project_id: @project.id)
= f.submit 'Add', class: "btn btn-save"
= form_tag people_group_path(@group), method: 'get' do
%fieldset
%legend Projects:
%ul.nav.nav-pills.nav-stacked
- @projects.each do |project|
%li{class: ("active" if params[:project_id] == project.id.to_s)}
= link_to people_group_path(@group, project_id: project.id) do
= project.name_with_namespace
%small.pull-right= project.users.count
- if @projects.blank?
%p.nothing_here_message This group has no projects yet
%fieldset
%hr
= link_to "Reset", people_group_path(@group), class: 'btn pull-right'
- can_manage_group = current_user.can? :manage_group, @group
.row .row
.span3 .span6
= render 'people_filter' - if can_manage_group
.span9 = render "new_group_member"
- if can?(current_user, :manage_group, @group) - else
= render (@project ? "new_member" : "new_group_member") .light-well
%h4.nothing_here_message
Only group owners can manage group members
.span6
.ui-box .ui-box
%h5.title %h5.title
Team #{@group.name} Group Members
%small %small
(#{@users.size}) (#{@members.count})
%ul.well-list %ul.well-list
- @users.each do |user| - @members.each do |member|
%li = render 'users_groups/users_group', member: member, show_controls: can_manage_group
= image_tag gravatar_icon(user.email, 16), class: "avatar s16" %p.light
%strong= user.name Group members get access to all projects in this group
%span.cgray= user.email
- if @group.owner == user
%span.btn.btn-small.disabled.pull-right Group Owner
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
Assign to Assign to
.input .input
.pull-left .pull-left
= f.select(:assignee_id, @project.users.alphabetically.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'}) = f.select(:assignee_id, @project.team.members.sort_by(&:name).map {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'})
.pull-right .pull-right
&nbsp; &nbsp;
= link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link' = link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
%span.update_issues_text Update selected issues with &nbsp; %span.update_issues_text Update selected issues with &nbsp;
.left .left
= select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
= select_tag('update[assignee_id]', options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee") = select_tag('update[assignee_id]', options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]), prompt: "Assignee")
= select_tag('update[milestone_id]', options_from_collection_for_select(issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone") = select_tag('update[milestone_id]', options_from_collection_for_select(issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone")
= hidden_field_tag 'update[issues_ids]', [] = hidden_field_tag 'update[issues_ids]', []
= hidden_field_tag :status, params[:status] = hidden_field_tag :status, params[:status]
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
Any Any
= link_to project_issues_with_filter_path(@project, assignee_id: 0) do = link_to project_issues_with_filter_path(@project, assignee_id: 0) do
Unassigned Unassigned
- @project.users.sort_by(&:name).each do |user| - @project.team.members.sort_by(&:name).each do |user|
%li %li
= link_to project_issues_with_filter_path(@project, assignee_id: user.id) do = link_to project_issues_with_filter_path(@project, assignee_id: user.id) do
= image_tag gravatar_icon(user.email), class: "avatar s16" = image_tag gravatar_icon(user.email), class: "avatar s16"
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
= nav_link(controller: [:team_members, :teams]) do = nav_link(controller: [:team_members, :teams]) do
= link_to project_team_index_path(@project), class: "team-tab tab" do = link_to project_team_index_path(@project), class: "team-tab tab" do
%i.icon-group %i.icon-group
Project Members Members
= nav_link(controller: :deploy_keys) do = nav_link(controller: :deploy_keys) do
= link_to project_deploy_keys_path(@project) do = link_to project_deploy_keys_path(@project) do
%span %span
......
.ui-box
%h5.title
%strong #{@group.name} Group
members (#{@group.users_groups.count})
.pull-right
= link_to people_group_path(@group), class: 'btn btn-small' do
%i.icon-edit
%ul.well-list
- @group.users_groups.order('group_access DESC').each do |member|
= render 'users_groups/users_group', member: member, show_controls: false
- can_admin_project = (can? current_user, :admin_project, @project) .team-table
- team.each do |access, members| - can_admin_project = (can? current_user, :admin_project, @project)
- role = Project.access_options.key(access).pluralize .ui-box
.ui-box{class: role.downcase}
%h5.title %h5.title
= role %strong #{@project.name} Project
%span.light (#{members.size}) members (#{members.count})
%ul.well-list %ul.well-list
- members.sort_by(&:user_name).each do |team_member| - members.each do |team_member|
= render 'team_members/team_member', member: team_member, current_user_can_admin_project: can_admin_project = render 'team_members/team_member', member: team_member, current_user_can_admin_project: can_admin_project
- user = member.user - user = member.user
- allow_admin = current_user_can_admin_project - allow_admin = current_user_can_admin_project
%li{id: dom_id(user), class: "team_member_row user_#{user.id}"} %li{id: dom_id(user), class: "team_member_row user_#{user.id}"}
.row .pull-right
.span4 - if allow_admin
= link_to user, title: user.name, class: "dark" do .pull-left
= image_tag gravatar_icon(user.email, 32), class: "avatar s32" = form_for(member, as: :team_member, url: project_team_member_path(@project, member.user)) do |f|
%strong= truncate(user.name, lenght: 40) = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2 trigger-submit"
%br &nbsp;
%small.cgray= user.username = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do
%i.icon-minus.icon-white
= image_tag gravatar_icon(user.email, 32), class: "avatar s32"
%p
%strong= user.name
%span.cgray= user.username
.span4.pull-right
- if allow_admin
.left
= form_for(member, as: :team_member, url: project_team_member_path(@project, member.user)) do |f|
= f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2 trigger-submit"
.pull-right
- if current_user == user
%span.label.label-success This is you!
- if @project.namespace_owner == user
%span.label.label-info Owner
- elsif user.blocked?
%span.label.label-error Blocked
- elsif allow_admin
= link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do
%i.icon-minus.icon-white
= render "projects/settings_nav" = render "projects/settings_nav"
%h3.page_title %h3.page_title
Project Members Users with access to this project
(#{@project.users.count})
%small
Read more about project permissions
%strong= link_to "here", help_permissions_path, class: "vlink"
- if can? current_user, :admin_team_member, @project - if can? current_user, :admin_team_member, @project
%span.pull-right %span.pull-right
...@@ -15,42 +11,25 @@ ...@@ -15,42 +11,25 @@
= link_to new_project_team_member_path(@project), class: "btn btn-primary small grouped", title: "New Team Member" do = link_to new_project_team_member_path(@project), class: "btn btn-primary small grouped", title: "New Team Member" do
New Team Member New Team Member
%hr %p.light
Read more about project permissions
%strong= link_to "here", help_permissions_path, class: "vlink"
.clearfix .clearfix
.row
.span3
%ul.nav.nav-pills.nav-stacked
%li{class: ("active" if !params[:type])}
= link_to project_team_index_path(type: nil) do
All
%li{class: ("active" if params[:type] == 'masters')}
= link_to project_team_index_path(type: 'masters') do
Masters
%span.pull-right= @project.users_projects.masters.count
%li{class: ("active" if params[:type] == 'developers')}
= link_to project_team_index_path(type: 'developers') do
Developers
%span.pull-right= @project.users_projects.developers.count
%li{class: ("active" if params[:type] == 'reporters')}
= link_to project_team_index_path(type: 'reporters') do
Reporters
%span.pull-right= @project.users_projects.reporters.count
%li{class: ("active" if params[:type] == 'guests')}
= link_to project_team_index_path(type: 'guests') do
Guests
%span.pull-right= @project.users_projects.guests.count
- if @assigned_teams.present?
%h5
Assigned teams
(#{@project.user_teams.count})
%div
= render "team_members/assigned_teams", assigned_teams: @assigned_teams
.span9
%div.team-table
= render "team_members/team", team: @team
- if @group
.row
.span6
= render "team_members/group_members"
.span6
= render "team_members/team", members: @users_projects
- else
= render "team_members/team", members: @users_projects
- if @assigned_teams.present?
%h5
Assigned teams
(#{@project.user_teams.count})
%div
= render "team_members/assigned_teams", assigned_teams: @assigned_teams
- user = member.user
- return unless user
%li{class: dom_class(member)}
= image_tag gravatar_icon(user.email, 16), class: "avatar s16"
%strong= user.name
%span.cgray= user.username
%span.pull-right
- if @group.owners.include?(user)
%span.label.label-info Group Owner
- else
= member.human_access
- if show_controls && user != current_user
= link_to group_users_group_path(@group, member), confirm: remove_user_from_group_message(@group, user), method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
%i.icon-minus.icon-white
...@@ -149,10 +149,10 @@ Gitlab::Application.routes.draw do ...@@ -149,10 +149,10 @@ Gitlab::Application.routes.draw do
member do member do
get :issues get :issues
get :merge_requests get :merge_requests
get :search
get :people get :people
post :team_members
end end
resources :users_groups, only: [:create, :update, :destroy]
end end
# #
......
class CreateUsersGroups < ActiveRecord::Migration
def change
create_table :users_groups do |t|
t.integer :group_access, null: false
t.integer :group_id, null: false
t.integer :user_id, null: false
t.timestamps
end
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130614132337) do ActiveRecord::Schema.define(:version => 20130617095603) do
create_table "deploy_keys_projects", :force => true do |t| create_table "deploy_keys_projects", :force => true do |t|
t.integer "deploy_key_id", :null => false t.integer "deploy_key_id", :null => false
...@@ -53,8 +53,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do ...@@ -53,8 +53,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do
t.integer "assignee_id" t.integer "assignee_id"
t.integer "author_id" t.integer "author_id"
t.integer "project_id" t.integer "project_id"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.integer "position", :default => 0 t.integer "position", :default => 0
t.string "branch_name" t.string "branch_name"
t.text "description" t.text "description"
...@@ -71,8 +71,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do ...@@ -71,8 +71,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do
create_table "keys", :force => true do |t| create_table "keys", :force => true do |t|
t.integer "user_id" t.integer "user_id"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.text "key" t.text "key"
t.string "title" t.string "title"
t.string "identifier" t.string "identifier"
...@@ -89,8 +89,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do ...@@ -89,8 +89,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do
t.integer "author_id" t.integer "author_id"
t.integer "assignee_id" t.integer "assignee_id"
t.string "title" t.string "title"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.text "st_commits", :limit => 2147483647 t.text "st_commits", :limit => 2147483647
t.text "st_diffs", :limit => 2147483647 t.text "st_diffs", :limit => 2147483647
t.integer "milestone_id" t.integer "milestone_id"
...@@ -139,8 +139,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do ...@@ -139,8 +139,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do
t.text "note" t.text "note"
t.string "noteable_type" t.string "noteable_type"
t.integer "author_id" t.integer "author_id"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.integer "project_id" t.integer "project_id"
t.string "attachment" t.string "attachment"
t.string "line_code" t.string "line_code"
...@@ -158,8 +158,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do ...@@ -158,8 +158,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do
t.string "name" t.string "name"
t.string "path" t.string "path"
t.text "description" t.text "description"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.integer "creator_id" t.integer "creator_id"
t.string "default_branch" t.string "default_branch"
t.boolean "issues_enabled", :default => true, :null => false t.boolean "issues_enabled", :default => true, :null => false
...@@ -206,8 +206,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do ...@@ -206,8 +206,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do
t.text "content" t.text "content"
t.integer "author_id", :null => false t.integer "author_id", :null => false
t.integer "project_id" t.integer "project_id"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.string "file_name" t.string "file_name"
t.datetime "expires_at" t.datetime "expires_at"
t.boolean "private", :default => true, :null => false t.boolean "private", :default => true, :null => false
...@@ -228,9 +228,6 @@ ActiveRecord::Schema.define(:version => 20130614132337) do ...@@ -228,9 +228,6 @@ ActiveRecord::Schema.define(:version => 20130614132337) do
t.datetime "created_at" t.datetime "created_at"
end end
add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id"
add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context"
create_table "tags", :force => true do |t| create_table "tags", :force => true do |t|
t.string "name" t.string "name"
end end
...@@ -262,53 +259,60 @@ ActiveRecord::Schema.define(:version => 20130614132337) do ...@@ -262,53 +259,60 @@ ActiveRecord::Schema.define(:version => 20130614132337) do
end end
create_table "users", :force => true do |t| create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "reset_password_token" t.string "reset_password_token"
t.datetime "reset_password_sent_at" t.datetime "reset_password_sent_at"
t.datetime "remember_created_at" t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0 t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at" t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at" t.datetime "last_sign_in_at"
t.string "current_sign_in_ip" t.string "current_sign_in_ip"
t.string "last_sign_in_ip" t.string "last_sign_in_ip"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.string "name" t.string "name"
t.boolean "admin", :default => false, :null => false t.boolean "admin", :default => false, :null => false
t.integer "projects_limit", :default => 10 t.integer "projects_limit", :default => 10
t.string "skype", :default => "", :null => false t.string "skype", :default => "", :null => false
t.string "linkedin", :default => "", :null => false t.string "linkedin", :default => "", :null => false
t.string "twitter", :default => "", :null => false t.string "twitter", :default => "", :null => false
t.string "authentication_token" t.string "authentication_token"
t.integer "theme_id", :default => 1, :null => false t.integer "theme_id", :default => 1, :null => false
t.string "bio" t.string "bio"
t.integer "failed_attempts", :default => 0 t.integer "failed_attempts", :default => 0
t.datetime "locked_at" t.datetime "locked_at"
t.string "extern_uid" t.string "extern_uid"
t.string "provider" t.string "provider"
t.string "username" t.string "username"
t.boolean "can_create_group", :default => true, :null => false t.boolean "can_create_group", :default => true, :null => false
t.boolean "can_create_team", :default => true, :null => false t.boolean "can_create_team", :default => true, :null => false
t.string "state" t.string "state"
t.integer "color_scheme_id", :default => 1, :null => false t.integer "color_scheme_id", :default => 1, :null => false
t.integer "notification_level", :default => 1, :null => false t.integer "notification_level", :default => 1, :null => false
t.datetime "password_expires_at" t.datetime "password_expires_at"
t.integer "created_by_id" t.integer "created_by_id"
end end
add_index "users", ["admin"], :name => "index_users_on_admin" add_index "users", ["admin"], :name => "index_users_on_admin"
add_index "users", ["email"], :name => "index_users_on_email", :unique => true add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["extern_uid", "provider"], :name => "index_users_on_extern_uid_and_provider", :unique => true
add_index "users", ["name"], :name => "index_users_on_name" add_index "users", ["name"], :name => "index_users_on_name"
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
add_index "users", ["username"], :name => "index_users_on_username" add_index "users", ["username"], :name => "index_users_on_username"
create_table "users_groups", :force => true do |t|
t.integer "group_access", :null => false
t.integer "group_id", :null => false
t.integer "user_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users_projects", :force => true do |t| create_table "users_projects", :force => true do |t|
t.integer "user_id", :null => false t.integer "user_id", :null => false
t.integer "project_id", :null => false t.integer "project_id", :null => false
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.integer "project_access", :default => 0, :null => false t.integer "project_access", :default => 0, :null => false
t.integer "notification_level", :default => 3, :null => false t.integer "notification_level", :default => 3, :null => false
end end
...@@ -320,8 +324,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do ...@@ -320,8 +324,8 @@ ActiveRecord::Schema.define(:version => 20130614132337) do
create_table "web_hooks", :force => true do |t| create_table "web_hooks", :force => true do |t|
t.string "url" t.string "url"
t.integer "project_id" t.integer "project_id"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.string "type", :default => "ProjectHook" t.string "type", :default => "ProjectHook"
t.integer "service_id" t.integer "service_id"
end end
......
...@@ -45,7 +45,7 @@ class AdminGroups < Spinach::FeatureSteps ...@@ -45,7 +45,7 @@ class AdminGroups < Spinach::FeatureSteps
within "#new_team_member" do within "#new_team_member" do
select "Reporter", from: "project_access" select "Reporter", from: "project_access"
end end
click_button "Add user to projects in group" click_button "Add users into group"
end end
Then 'I should see "John" in team list in every project as "Reporter"' do Then 'I should see "John" in team list in every project as "Reporter"' do
......
...@@ -39,11 +39,11 @@ class Groups < Spinach::FeatureSteps ...@@ -39,11 +39,11 @@ class Groups < Spinach::FeatureSteps
And 'I select user "John" from list with role "Reporter"' do And 'I select user "John" from list with role "Reporter"' do
user = User.find_by_name("John") user = User.find_by_name("John")
within "#new_team_member" do within ".new_users_group" do
select2(user.id, from: "#user_ids", multiple: true) select2(user.id, from: "#user_ids", multiple: true)
select "Reporter", from: "project_access" select "Reporter", from: "group_access"
end end
click_button "Add" click_button "Add users into group"
end end
Then 'I should see user "John" in team list' do Then 'I should see user "John" in team list' do
......
...@@ -45,7 +45,7 @@ class ProjectActiveTab < Spinach::FeatureSteps ...@@ -45,7 +45,7 @@ class ProjectActiveTab < Spinach::FeatureSteps
# Sub Tabs: Home # Sub Tabs: Home
Given 'I click the "Team" tab' do Given 'I click the "Team" tab' do
click_link('Project Members') click_link('Members')
end end
Given 'I click the "Attachments" tab' do Given 'I click the "Attachments" tab' do
...@@ -73,7 +73,7 @@ class ProjectActiveTab < Spinach::FeatureSteps ...@@ -73,7 +73,7 @@ class ProjectActiveTab < Spinach::FeatureSteps
end end
Then 'the active sub tab should be Team' do Then 'the active sub tab should be Team' do
ensure_active_sub_tab('Project Members') ensure_active_sub_tab('Members')
end end
Then 'the active sub tab should be Attachments' do Then 'the active sub tab should be Attachments' do
......
...@@ -30,14 +30,20 @@ class ProjectTeamManagement < Spinach::FeatureSteps ...@@ -30,14 +30,20 @@ class ProjectTeamManagement < Spinach::FeatureSteps
end end
Then 'I should see "Mike" in team list as "Reporter"' do Then 'I should see "Mike" in team list as "Reporter"' do
within '.reporters' do user = User.find_by_name("Mike")
within "#user_#{user.id}" do
page.should have_content('Mike') page.should have_content('Mike')
page.find('#team_member_project_access').value.should == access_value(:reporter)
end end
end end
Given 'I should see "Sam" in team list as "Developer"' do Given 'I should see "Sam" in team list as "Developer"' do
within '.developers' do user = User.find_by_name("Sam")
within "#user_#{user.id}" do
page.should have_content('Sam') page.should have_content('Sam')
page.find('#team_member_project_access').value.should == access_value(:developer)
end end
end end
...@@ -49,8 +55,10 @@ class ProjectTeamManagement < Spinach::FeatureSteps ...@@ -49,8 +55,10 @@ class ProjectTeamManagement < Spinach::FeatureSteps
end end
And 'I should see "Sam" in team list as "Reporter"' do And 'I should see "Sam" in team list as "Reporter"' do
within '.reporters' do user = User.find_by_name("Sam")
within ".user_#{user.id}" do
page.should have_content('Sam') page.should have_content('Sam')
page.find('#team_member_project_access').value.should == access_value(:reporter)
end end
end end
...@@ -103,4 +111,10 @@ class ProjectTeamManagement < Spinach::FeatureSteps ...@@ -103,4 +111,10 @@ class ProjectTeamManagement < Spinach::FeatureSteps
click_link('Remove user from team') click_link('Remove user from team')
end end
end end
private
def access_value(key)
UsersProject.roles_hash[key].to_s
end
end end
FactoryGirl.define do
factory :users_group do
group_access { UsersGroup::OWNER }
group
user
end
end
require 'spec_helper'
describe UsersGroup do
describe "Associations" do
it { should belong_to(:group) }
it { should belong_to(:user) }
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:group_id) }
end
describe "Validation" do
let!(:users_group) { create(:users_group) }
it { should validate_presence_of(:user_id) }
it { should validate_uniqueness_of(:user_id).scoped_to(:group_id).with_message(/already exists/) }
it { should validate_presence_of(:group_id) }
it { should ensure_inclusion_of(:group_access).in_array(UsersGroup.group_access_roles.values) }
end
describe "Delegate methods" do
it { should respond_to(:user_name) }
it { should respond_to(:user_email) }
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment