Commit aad3cbee authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'team-members' into 'master'

Use same layout and interactivity for project members as group members and make code more consistent.

It's probably easiest to review the commits one by one, but keep in mind that later commits sometimes touch the same place as earlier ones, so look at the complete diff to add comments.

The project members page and group members page now look and work the same, with an inline "Add members" form, member search and editing of access levels and deleting without page refresh.

Before:

![Screen_Shot_2015-03-13_at_16.50.39](https://dev.gitlab.org/gitlab/gitlabhq/uploads/2cd023c48de0a643ce04df965f39e1f5/Screen_Shot_2015-03-13_at_16.50.39.png)

After:

![Screen_Shot_2015-03-13_at_16.50.02](https://dev.gitlab.org/gitlab/gitlabhq/uploads/fdef480daf2859ed74f5641af1f337b3/Screen_Shot_2015-03-13_at_16.50.02.png)

See merge request !1695
parents 60df262c 584580e5
......@@ -68,6 +68,7 @@ v 7.9.0 (unreleased)
- Execute hooks and services when branch or tag is created or deleted through web interface.
- Block and unblock user if he/she was blocked/unblocked in Active Directory
- Raise recommended number of unicorn workers from 2 to 3
- Use same layout and interactivity for project members as group members.
v 7.8.4
- Fix issue_tracker_id substitution in custom issue trackers
......
......@@ -73,9 +73,12 @@ class Dispatcher
new Activities()
shortcut_handler = new ShortcutsNavigation()
new ProjectsList()
when 'groups:members'
when 'groups:group_members:index'
new GroupMembers()
new UsersSelect()
when 'projects:project_members:index'
new ProjectMembers()
new UsersSelect()
when 'groups:new', 'groups:edit', 'admin:groups:edit'
new GroupAvatar()
when 'projects:tree:show'
......@@ -127,9 +130,8 @@ class Dispatcher
new DropzoneInput($('.wiki-form'))
when 'snippets', 'labels', 'graphs'
shortcut_handler = new ShortcutsNavigation()
when 'team_members', 'deploy_keys', 'hooks', 'services', 'protected_branches'
when 'project_members', 'deploy_keys', 'hooks', 'services', 'protected_branches'
shortcut_handler = new ShortcutsNavigation()
new UsersSelect()
# If we haven't installed a custom shortcut handler, install the default one
......
class @ProjectMembers
constructor: ->
$('li.project_member').bind 'ajax:success', ->
$(this).fadeOut()
......@@ -167,7 +167,7 @@ li.note {
background-color: inherit;
}
.team_member_show {
.project_member_show {
td:first-child {
color: #aaa;
}
......
......@@ -156,7 +156,7 @@ ul.nav.nav-projects-tabs {
}
}
.team_member_row form {
.project_member_row form {
margin: 0px;
}
......
class Admin::GroupsController < Admin::ApplicationController
before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :project_teams_update]
before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :members_update]
def index
@groups = Group.all
......@@ -40,7 +40,7 @@ class Admin::GroupsController < Admin::ApplicationController
end
end
def project_teams_update
def members_update
@group.add_users(params[:user_ids].split(','), params[:access_level])
redirect_to [:admin, @group], notice: 'Users were successfully added.'
......
class Dashboard::GroupsController < ApplicationController
def index
@user_groups = current_user.group_members.page(params[:page]).per(PER_PAGE)
end
def leave
@users_group = group.group_members.where(user_id: current_user.id).first
if can?(current_user, :destroy, @users_group)
@users_group.destroy
redirect_to(dashboard_groups_path, info: "You left #{group.name} group.")
else
return render_403
end
end
private
def group
@group ||= Group.find_by(path: params[:id])
@group_members = current_user.group_members.page(params[:page]).per(PER_PAGE)
end
end
......@@ -2,9 +2,27 @@ class Groups::ApplicationController < ApplicationController
private
def authorize_read_group!
unless @group and can?(current_user, :read_group, @group)
if current_user.nil?
return authenticate_user!
else
return render_404
end
end
end
def authorize_admin_group!
unless can?(current_user, :manage_group, group)
return render_404
end
end
def determine_layout
if current_user
'group'
else
'public_group'
end
end
end
class Groups::GroupMembersController < Groups::ApplicationController
skip_before_filter :authenticate_user!, only: [:index]
before_filter :group
# Authorize
before_filter :authorize_admin_group!
before_filter :authorize_read_group!
before_filter :authorize_admin_group!, except: [:index, :leave]
layout 'group'
layout :determine_layout
def index
@project = @group.projects.find(params[:project_id]) if params[:project_id]
@members = @group.group_members
if params[:search].present?
users = @group.users.search(params[:search]).to_a
@members = @members.where(user_id: users)
end
@members = @members.order('access_level DESC').page(params[:page]).per(50)
@group_member = GroupMember.new
end
def create
@group.add_users(params[:user_ids].split(','), params[:access_level])
redirect_to members_group_path(@group), notice: 'Users were successfully added.'
redirect_to group_group_members_path(@group), notice: 'Users were successfully added.'
end
def update
......@@ -18,12 +33,12 @@ class Groups::GroupMembersController < Groups::ApplicationController
end
def destroy
@users_group = @group.group_members.find(params[:id])
@group_member = @group.group_members.find(params[:id])
if can?(current_user, :destroy, @users_group) # May fail if last owner.
@users_group.destroy
if can?(current_user, :destroy_group_member, @group_member) # May fail if last owner.
@group_member.destroy
respond_to do |format|
format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
format.js { render nothing: true }
end
else
......@@ -31,6 +46,17 @@ class Groups::GroupMembersController < Groups::ApplicationController
end
end
def leave
@group_member = @group.group_members.where(user_id: current_user.id).first
if can?(current_user, :destroy_group_member, @group_member)
@group_member.destroy
redirect_to(dashboard_groups_path, info: "You left #{group.name} group.")
else
return render_403
end
end
protected
def group
......
class GroupsController < Groups::ApplicationController
skip_before_filter :authenticate_user!, only: [:show, :issues, :members, :merge_requests]
skip_before_filter :authenticate_user!, only: [:show, :issues, :merge_requests]
respond_to :html
before_filter :group, except: [:new, :create]
......@@ -67,19 +67,6 @@ class GroupsController < Groups::ApplicationController
end
end
def members
@project = group.projects.find(params[:project_id]) if params[:project_id]
@members = group.group_members
if params[:search].present?
users = group.users.search(params[:search]).to_a
@members = @members.where(user_id: users)
end
@members = @members.order('access_level DESC').page(params[:page]).per(50)
@users_group = GroupMember.new
end
def edit
end
......
......@@ -14,9 +14,9 @@ class Profiles::NotificationsController < ApplicationController
@saved = if type == 'global'
current_user.update_attributes(user_params)
elsif type == 'group'
users_group = current_user.group_members.find(params[:notification_id])
users_group.notification_level = params[:notification_level]
users_group.save
group_member = current_user.group_members.find(params[:notification_id])
group_member.notification_level = params[:notification_level]
group_member.save
else
project_member = current_user.project_members.find(params[:notification_id])
project_member.notification_level = params[:notification_level]
......
class Projects::TeamMembersController < Projects::ApplicationController
class Projects::ProjectMembersController < Projects::ApplicationController
# Authorize
before_filter :authorize_admin_project!, except: :leave
layout "project_settings"
def index
@project_members = @project.project_members
if params[:search].present?
users = @project.users.search(params[:search]).to_a
@project_members = @project_members.where(user_id: users)
end
@project_members = @project_members.order('access_level DESC')
@group = @project.group
@project_members = @project.project_members.order('access_level DESC')
if @group
@group_members = @group.group_members
if params[:search].present?
users = @group.users.search(params[:search]).to_a
@group_members = @group_members.where(user_id: users)
end
@group_members = @group_members.order('access_level DESC').limit(20)
end
@project_member = @project.project_members.new
end
def new
@user_project_relation = @project.project_members.new
@project_member = @project.project_members.new
end
def create
users = User.where(id: params[:user_ids].split(','))
@project.team << [users, params[:access_level]]
redirect_to namespace_project_team_index_path(@project.namespace, @project)
redirect_to namespace_project_project_members_path(@project.namespace, @project)
end
def update
@user_project_relation = @project.project_members.find_by(user_id: member)
@user_project_relation.update_attributes(member_params)
unless @user_project_relation.valid?
flash[:alert] = "User should have at least one role"
end
redirect_to namespace_project_team_index_path(@project.namespace, @project)
@project_member = @project.project_members.find_by(user_id: member)
@project_member.update_attributes(member_params)
end
def destroy
@user_project_relation = @project.project_members.find_by(user_id: member)
@user_project_relation.destroy
@project_member = @project.project_members.find_by(user_id: member)
@project_member.destroy
respond_to do |format|
format.html do
redirect_to namespace_project_team_index_path(@project.namespace,
redirect_to namespace_project_project_members_path(@project.namespace,
@project)
end
format.js { render nothing: true }
......@@ -57,7 +72,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
status = @project.team.import(giver)
notice = status ? "Successfully imported" : "Import failed"
redirect_to(namespace_project_team_index_path(project.namespace, project),
redirect_to(namespace_project_project_members_path(project.namespace, project),
notice: notice)
end
......
......@@ -60,7 +60,7 @@ module SearchHelper
{ label: "#{prefix} - Merge Requests", url: namespace_project_merge_requests_path(@project.namespace, @project) },
{ label: "#{prefix} - Milestones", url: namespace_project_milestones_path(@project.namespace, @project) },
{ label: "#{prefix} - Snippets", url: namespace_project_snippets_path(@project.namespace, @project) },
{ label: "#{prefix} - Team", url: namespace_project_team_index_path(@project.namespace, @project) },
{ label: "#{prefix} - Members", url: namespace_project_project_members_path(@project.namespace, @project) },
{ label: "#{prefix} - Wiki", url: namespace_project_wikis_path(@project.namespace, @project) },
]
else
......
......@@ -89,7 +89,7 @@ module TabHelper
def project_tab_class
return "active" if current_page?(controller: "/projects", action: :edit, id: @project)
if ['services', 'hooks', 'deploy_keys', 'team_members', 'protected_branches'].include? controller.controller_name
if ['services', 'hooks', 'deploy_keys', 'project_members', 'protected_branches'].include? controller.controller_name
"active"
end
end
......
module Emails
module Groups
def group_access_granted_email(user_group_id)
@membership = GroupMember.find(user_group_id)
@group = @membership.group
def group_access_granted_email(group_member_id)
@group_member = GroupMember.find(group_member_id)
@group = @group_member.group
@target_url = group_url(@group)
mail(to: @membership.user.email,
mail(to: @group_member.user.email,
subject: subject("Access to group was granted"))
end
end
......
......@@ -14,7 +14,7 @@ class Ability
when "MergeRequest" then merge_request_abilities(user, subject)
when "Group" then group_abilities(user, subject)
when "Namespace" then namespace_abilities(user, subject)
when "GroupMember" then users_group_abilities(user, subject)
when "GroupMember" then group_member_abilities(user, subject)
else []
end.concat(global_abilities(user))
end
......@@ -37,7 +37,7 @@ class Ability
:read_issue,
:read_milestone,
:read_project_snippet,
:read_team_member,
:read_project_member,
:read_merge_request,
:read_note,
:download_code
......@@ -119,7 +119,7 @@ class Ability
:read_issue,
:read_milestone,
:read_project_snippet,
:read_team_member,
:read_project_member,
:read_merge_request,
:read_note,
:write_project,
......@@ -166,7 +166,7 @@ class Ability
:admin_issue,
:admin_milestone,
:admin_project_snippet,
:admin_team_member,
:admin_project_member,
:admin_merge_request,
:admin_note,
:admin_wiki,
......@@ -248,17 +248,17 @@ class Ability
end
end
def users_group_abilities(user, subject)
def group_member_abilities(user, subject)
rules = []
target_user = subject.user
group = subject.group
can_manage = group_abilities(user, group).include?(:manage_group)
if can_manage && (user != target_user)
rules << :modify
rules << :destroy
rules << :modify_group_member
rules << :destroy_group_member
end
if !group.last_owner?(user) && (can_manage || (user == target_user))
rules << :destroy
rules << :destroy_group_member
end
rules
end
......
......@@ -32,7 +32,6 @@ class Issue < ActiveRecord::Base
validates :project, presence: true
scope :of_group, ->(group) { where(project_id: group.project_ids) }
scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) }
scope :cared, ->(user) { where(assignee_id: user) }
scope :open_for, ->(user) { opened.assigned_to(user) }
......
......@@ -116,14 +116,14 @@ class ProjectMember < Member
def post_create_hook
unless owner?
event_service.join_project(self.project, self.user)
notification_service.new_team_member(self)
notification_service.new_project_member(self)
end
system_hook_service.execute_hooks_for(self, :create)
end
def post_update_hook
notification_service.update_team_member(self) if self.access_level_changed?
notification_service.update_project_member(self) if self.access_level_changed?
end
def post_destroy_hook
......
......@@ -115,7 +115,6 @@ class MergeRequest < ActiveRecord::Base
validate :validate_fork
scope :of_group, ->(group) { where("source_project_id in (:group_project_ids) OR target_project_id in (:group_project_ids)", group_project_ids: group.project_ids) }
scope :of_user_team, ->(team) { where("(source_project_id in (:team_project_ids) OR target_project_id in (:team_project_ids) AND assignee_id in (:team_member_ids))", team_project_ids: team.project_ids, team_member_ids: team.member_ids) }
scope :merged, -> { with_state(:merged) }
scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) }
scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) }
......
......@@ -157,7 +157,6 @@ class Project < ActiveRecord::Base
scope :without_user, ->(user) { where('projects.id NOT IN (:ids)', ids: user.authorized_projects.map(&:id) ) }
scope :without_team, ->(team) { team.projects.present? ? where('projects.id NOT IN (:ids)', ids: team.projects.map(&:id)) : scoped }
scope :not_in_group, ->(group) { where('projects.id NOT IN (:ids)', ids: group.project_ids ) }
scope :in_team, ->(team) { where('projects.id IN (:ids)', ids: team.projects.map(&:id)) }
scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) }
scope :in_group_namespace, -> { joins(:group) }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
......@@ -445,13 +444,13 @@ class Project < ActiveRecord::Base
end
end
def team_member_by_name_or_email(name = nil, email = nil)
def project_member_by_name_or_email(name = nil, email = nil)
user = users.where('name like ? or email like ?', name, email).first
project_members.where(user: user) if user
end
# Get Team Member record by user id
def team_member_by_id(user_id)
def project_member_by_id(user_id)
project_members.find_by(user_id: user_id)
end
......
......@@ -31,16 +31,16 @@ class ProjectTeam
user
end
def find_tm(user_id)
tm = project.project_members.find_by(user_id: user_id)
def find_member(user_id)
member = project.project_members.find_by(user_id: user_id)
# If user is not in project members
# we should check for group membership
if group && !tm
tm = group.group_members.find_by(user_id: user_id)
if group && !member
member = group.group_members.find_by(user_id: user_id)
end
tm
member
end
def add_user(user, access)
......@@ -91,24 +91,24 @@ class ProjectTeam
def import(source_project)
target_project = project
source_team = source_project.project_members.to_a
source_members = source_project.project_members.to_a
target_user_ids = target_project.project_members.pluck(:user_id)
source_team.reject! do |tm|
source_members.reject! do |member|
# Skip if user already present in team
target_user_ids.include?(tm.user_id)
target_user_ids.include?(member.user_id)
end
source_team.map! do |tm|
new_tm = tm.dup
new_tm.id = nil
new_tm.source = target_project
new_tm
source_members.map! do |member|
new_member = member.dup
new_member.id = nil
new_member.source = target_project
new_member
end
ProjectMember.transaction do
source_team.each do |tm|
tm.save
source_members.each do |member|
member.save
end
end
......@@ -118,26 +118,26 @@ class ProjectTeam
end
def guest?(user)
max_tm_access(user.id) == Gitlab::Access::GUEST
max_member_access(user.id) == Gitlab::Access::GUEST
end
def reporter?(user)
max_tm_access(user.id) == Gitlab::Access::REPORTER
max_member_access(user.id) == Gitlab::Access::REPORTER
end
def developer?(user)
max_tm_access(user.id) == Gitlab::Access::DEVELOPER
max_member_access(user.id) == Gitlab::Access::DEVELOPER
end
def master?(user)
max_tm_access(user.id) == Gitlab::Access::MASTER
max_member_access(user.id) == Gitlab::Access::MASTER
end
def member?(user_id)
!!find_tm(user_id)
!!find_member(user_id)
end
def max_tm_access(user_id)
def max_member_access(user_id)
access = []
access << project.project_members.find_by(user_id: user_id).try(:access_field)
......
......@@ -169,11 +169,8 @@ class User < ActiveRecord::Base
scope :admins, -> { where(admin: true) }
scope :blocked, -> { with_state(:blocked) }
scope :active, -> { with_state(:active) }
scope :in_team, ->(team){ where(id: team.member_ids) }
scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) }
scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') }
scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active }
#
# Class methods
......@@ -407,7 +404,7 @@ class User < ActiveRecord::Base
end
def tm_of(project)
project.team_member_by_id(self.id)
project.project_member_by_id(self.id)
end
def already_forked?(project)
......
......@@ -162,20 +162,20 @@ class NotificationService
end
end
def new_team_member(project_member)
def new_project_member(project_member)
mailer.project_access_granted_email(project_member.id)
end
def update_team_member(project_member)
def update_project_member(project_member)
mailer.project_access_granted_email(project_member.id)
end
def new_group_member(users_group)
mailer.group_access_granted_email(users_group.id)
def new_group_member(group_member)
mailer.group_access_granted_email(group_member.id)
end
def update_group_member(users_group)
mailer.group_access_granted_email(users_group.id)
def update_group_member(group_member)
mailer.group_access_granted_email(group_member.id)
end
def project_was_moved(project)
......@@ -194,11 +194,11 @@ class NotificationService
project_members = project_member_notification(project)
users_with_project_level_global = project_member_notification(project, Notification::N_GLOBAL)
users_with_group_level_global = users_group_notification(project, Notification::N_GLOBAL)
users_with_group_level_global = group_member_notification(project, Notification::N_GLOBAL)
users = users_with_global_level_watch([users_with_project_level_global, users_with_group_level_global].flatten.uniq)
users_with_project_setting = select_project_member_setting(project, users_with_project_level_global, users)
users_with_group_setting = select_users_group_setting(project, project_members, users_with_group_level_global, users)
users_with_group_setting = select_group_member_setting(project, project_members, users_with_group_level_global, users)
User.where(id: users_with_project_setting.concat(users_with_group_setting).uniq).to_a
end
......@@ -213,7 +213,7 @@ class NotificationService
end
end
def users_group_notification(project, notification_level)
def group_member_notification(project, notification_level)
if project.group
project.group.group_members.where(notification_level: notification_level).pluck(:user_id)
else
......@@ -243,8 +243,8 @@ class NotificationService
end
# Build a list of users based on group notification settings
def select_users_group_setting(project, project_members, global_setting, users_global_level_watch)
uids = users_group_notification(project, Notification::N_WATCH)
def select_group_member_setting(project, project_members, global_setting, users_global_level_watch)
uids = group_member_notification(project, Notification::N_WATCH)
# Group setting is watch, add to users list if user is not project member
users = []
......@@ -273,20 +273,20 @@ class NotificationService
users.reject do |user|
next user.notification.disabled? unless project
tm = project.project_members.find_by(user_id: user.id)
member = project.project_members.find_by(user_id: user.id)
if !tm && project.group
tm = project.group.group_members.find_by(user_id: user.id)
if !member && project.group
member = project.group.group_members.find_by(user_id: user.id)
end
# reject users who globally disabled notification and has no membership
next user.notification.disabled? unless tm
next user.notification.disabled? unless member
# reject users who disabled notification in project
next true if tm.notification.disabled?
next true if member.notification.disabled?
# reject users who have N_GLOBAL in project and disabled in global settings
tm.notification.global? && user.notification.disabled?
member.notification.global? && user.notification.disabled?
end
end
......@@ -297,20 +297,20 @@ class NotificationService
users.reject do |user|
next user.notification.mention? unless project
tm = project.project_members.find_by(user_id: user.id)
member = project.project_members.find_by(user_id: user.id)
if !tm && project.group
tm = project.group.group_members.find_by(user_id: user.id)
if !member && project.group
member = project.group.group_members.find_by(user_id: user.id)
end
# reject users who globally set mention notification and has no membership
next user.notification.mention? unless tm
next user.notification.mention? unless member
# reject users who set mention notification in project
next true if tm.notification.mention?
next true if member.notification.mention?
# reject users who have N_MENTION in project and disabled in global settings
tm.notification.global? && user.notification.mention?
member.notification.global? && user.notification.mention?
end
end
......
......@@ -12,8 +12,8 @@ module Projects
else
[]
end
team_members = sorted(@project.team.members)
participants = all_members + groups + team_members + participating
project_members = sorted(@project.team.members)
participants = all_members + groups + project_members + participating
participants.uniq
end
......
......@@ -58,7 +58,7 @@
Read more about project permissions
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
= form_tag project_teams_update_admin_group_path(@group), id: "new_team_member", class: "bulk_import", method: :put do
= form_tag members_update_admin_group_path(@group), id: "new_project_member", class: "bulk_import", method: :put do
%div
= users_select_tag(:user_ids, multiple: true)
%div.prepend-top-10
......
......@@ -111,10 +111,10 @@
%small
(#{@project.users.count})
.pull-right
= link_to namespace_project_team_index_path(@project.namespace, @project), class: "btn btn-xs" do
= link_to namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-xs" do
%i.fa.fa-pencil-square-o
Manage Access
%ul.well-list.team_members
%ul.well-list.project_members
- @project_members.each do |project_member|
- user = project_member.user
%li.project_member
......@@ -126,7 +126,7 @@
%span.light Owner
- else
%span.light= project_member.human_access
= link_to namespace_project_team_member_path(@project.namespace, @project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, remote: true, class: "btn btn-sm btn-remove" do
= link_to namespace_project_project_member_path(@project.namespace, @project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, remote: true, class: "btn btn-sm btn-remove" do
%i.fa.fa-times
.panel-footer
= paginate @project_members, param_name: 'project_members_page', theme: 'gitlab'
......@@ -174,15 +174,15 @@
.panel.panel-default
.panel-heading Groups:
%ul.well-list
- @user.group_members.each do |user_group|
- group = user_group.group
- @user.group_members.each do |group_member|
- group = group_member.group
%li.group_member
%span{class: ("list-item-name" unless user_group.owner?)}
%span{class: ("list-item-name" unless group_member.owner?)}
%strong= link_to group.name, admin_group_path(group)
.pull-right
%span.light= user_group.human_access
- unless user_group.owner?
= link_to group_group_member_path(group, user_group), data: { confirm: remove_user_from_group_message(group, @user) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
%span.light= group_member.human_access
- unless group_member.owner?
= link_to group_group_member_path(group, group_member), data: { confirm: remove_user_from_group_message(group, @user) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
%i.fa.fa-times.fa-inverse
- else
.nothing-here-block This user has no groups.
......@@ -207,21 +207,21 @@
.panel-heading Joined projects (#{@joined_projects.count})
%ul.well-list
- @joined_projects.sort_by(&:name_with_namespace).each do |project|
- tm = project.team.find_tm(@user.id)
- member = project.team.find_member(@user.id)
%li.project_member
.list-item-name
= link_to admin_namespace_project_path(project.namespace, project), class: dom_class(project) do
= project.name_with_namespace
- if tm
- if member
.pull-right
- if tm.owner?
- if member.owner?
%span.light Owner
- else
%span.light= tm.human_access
%span.light= member.human_access
- if tm.respond_to? :project
= link_to namespace_project_team_member_path(project.namespace, project, @user), data: { confirm: remove_from_project_team_message(project, @user) }, remote: true, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove user from project' do
- if member.respond_to? :project
= link_to namespace_project_project_member_path(project.namespace, project, @user), data: { confirm: remove_from_project_team_message(project, @user) }, remote: true, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove user from project' do
%i.fa.fa-times
#ssh-keys.tab-pane
= render 'profiles/keys/key_table', admin: true
......@@ -11,10 +11,10 @@
.panel.panel-default
.panel-heading
%strong Groups
(#{@user_groups.count})
(#{@group_members.count})
%ul.well-list
- @user_groups.each do |user_group|
- group = user_group.group
- @group_members.each do |group_member|
- group = group_member.group
%li
.pull-right
- if can?(current_user, :manage_group, group)
......@@ -22,8 +22,8 @@
%i.fa.fa-cogs
Settings
- if can?(current_user, :destroy, user_group)
= link_to leave_dashboard_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-sm btn btn-grouped", title: 'Remove user from group' do
- if can?(current_user, :destroy_group_member, group_member)
= link_to leave_group_group_members_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-sm btn btn-grouped", title: 'Remove user from group' do
%i.fa.fa-sign-out
Leave
......@@ -32,9 +32,9 @@
%strong= group.name
as
%strong #{user_group.human_access}
%strong #{group_member.human_access}
%div.light
#{pluralize(group.projects.count, "project")}, #{pluralize(group.users.count, "user")}
= paginate @user_groups
= paginate @group_members
- user = member.user
- return unless user
- show_roles = true if show_roles.nil?
%li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
%span{class: ("list-item-name" if show_controls)}
= image_tag avatar_icon(user.email, 16), class: "avatar s16"
......@@ -16,13 +17,13 @@
%span.pull-right
%strong= member.human_access
- if show_controls
- if can?(current_user, :modify, member)
- if can?(current_user, :modify_group_member, member)
= button_tag class: "btn-xs btn js-toggle-button",
title: 'Edit access level', type: 'button' do
%i.fa.fa-pencil-square-o
- if can?(current_user, :destroy, member)
- if current_user == member.user
= link_to leave_dashboard_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
- if can?(current_user, :destroy_group_member, member)
- if current_user == user
= link_to leave_group_group_members_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
%i.fa.fa-minus.fa-inverse
- else
= link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
......
= form_for @users_group, url: group_group_members_path(@group), html: { class: 'form-horizontal users-group-form' } do |f|
= form_for @group_member, url: group_group_members_path(@group), html: { class: 'form-horizontal users-group-form' } do |f|
.form-group
= f.label :user_ids, "People", class: 'control-label'
.col-sm-10= users_select_tag(:user_ids, multiple: true, class: 'input-large')
......@@ -6,7 +6,7 @@
.form-group
= f.label :access_level, "Group Access", class: 'control-label'
.col-sm-10
= select_tag :access_level, options_for_select(GroupMember.access_level_roles, @users_group.access_level), class: "project-access-select select2"
= select_tag :access_level, options_for_select(GroupMember.access_level_roles, @group_member.access_level), class: "project-access-select select2"
.help-block
Read more about role permissions
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
......
- show_roles = should_user_see_group_roles?(current_user, @group)
%h3.page-title
Group members
- if show_roles
......@@ -10,7 +11,7 @@
%hr
.clearfix.js-toggle-container
= form_tag members_group_path(@group), method: :get, class: 'form-inline member-search-form' do
= form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do
.form-group
= search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control search-text-input input-mn-300' }
= button_tag 'Search', class: 'btn'
......@@ -33,6 +34,7 @@
%ul.well-list
- @members.each do |member|
= render 'groups/group_members/group_member', member: member, show_roles: show_roles, show_controls: true
= paginate @members, theme: 'gitlab'
:coffeescript
......
......@@ -16,7 +16,7 @@
%span.label.label-gray
= repository_size(project)
.pull-right
= link_to 'Members', namespace_project_team_index_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm"
= link_to 'Members', namespace_project_project_members_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm"
= link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-sm"
= link_to 'Remove', project, data: { confirm: remove_project_message(project)}, method: :delete, class: "btn btn-sm btn-remove"
- if @projects.blank?
......
......@@ -24,8 +24,8 @@
Merge Requests
- if current_user
%span.count= MergeRequest.opened.of_group(@group).count
= nav_link(path: 'groups#members') do
= link_to members_group_path(@group), title: 'Members' do
= nav_link(controller: [:group_members]) do
= link_to group_group_members_path(@group), title: 'Members' do
%i.fa.fa-users
%span
Members
......
%p
= "You have been granted #{@membership.human_access} access to group"
= "You have been granted #{@group_member.human_access} access to group"
= link_to group_url(@group) do
= @group.name
You have been granted <%= @membership.human_access %> access to group <%= @group.name %>
You have been granted <%= @group_member.human_access %> access to group <%= @group.name %>
<%= url_for(group_url(@group)) %>
......@@ -62,9 +62,9 @@
By default, all projects and groups will use the notification level set above.
%h4 Groups:
%ul.bordered-list
- @group_members.each do |users_group|
- notification = Notification.new(users_group)
= render 'settings', type: 'group', membership: users_group, notification: notification
- @group_members.each do |group_member|
- notification = Notification.new(group_member)
= render 'settings', type: 'group', membership: group_member, notification: notification
.col-md-6
%p
......
......@@ -15,9 +15,9 @@
%li
= link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
New snippet
- if can?(current_user, :admin_team_member, @project)
- if can?(current_user, :admin_project_member, @project)
%li
= link_to new_namespace_project_team_member_path(@project.namespace, @project), title: "New project member" do
= link_to namespace_project_project_members_path(@project.namespace, @project), title: "New project member" do
New project member
- if can? current_user, :push_code, @project
%li.divider
......
......@@ -4,8 +4,8 @@
%i.fa.fa-pencil-square-o
%span
Project
= nav_link(controller: [:team_members, :teams]) do
= link_to namespace_project_team_index_path(@project.namespace, @project), title: 'Members', class: "team-tab tab" do
= nav_link(controller: [:project_members, :teams]) do
= link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: "team-tab tab" do
%i.fa.fa-users
%span
Members
......
- group_users_count = @group.group_members.count
.panel.panel-default
.panel-heading
%strong #{@group.name}
group members (#{group_users_count})
group members
%small
(#{members.count})
.pull-right
= link_to members_group_path(@group), class: 'btn btn-sm' do
= link_to group_group_members_path(@group), class: 'btn btn-sm' do
%i.fa.fa-pencil-square-o
%ul.well-list
- @group.group_members.order('access_level DESC').limit(20).each do |member|
- members.each do |member|
= render 'groups/group_members/group_member', member: member, show_controls: false
- if group_users_count > 20
- if members.count > 20
%li
and #{group_users_count - 20} more. For full list visit #{link_to 'group members page', members_group_path(@group)}
and #{members.count - 20} more. For full list visit #{link_to 'group members page', group_group_members_path(@group)}
= form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project), html: { class: 'form-horizontal users-project-form' } do |f|
.form-group
= f.label :user_ids, "People", class: 'control-label'
.col-sm-10= users_select_tag(:user_ids, multiple: true, class: 'input-large')
.form-group
= f.label :access_level, "Project Access", class: 'control-label'
.col-sm-10
= select_tag :access_level, options_for_select(ProjectMember.access_roles, @project_member.access_level), class: "project-access-select select2"
.help-block
Read more about role permissions
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
.form-actions
= f.submit 'Add users to project', class: "btn btn-create"
- user = member.user
- return unless user
%li{class: "#{dom_class(member)} js-toggle-container project_member_row access-#{member.human_access.downcase}", id: dom_id(member)}
%span.list-item-name
= image_tag avatar_icon(user.email, 16), class: "avatar s16"
%strong= user.name
%span.cgray= user.username
- if user == current_user
%span.label.label-success It's you
- if user.blocked?
%label.label.label-danger
%strong Blocked
- if current_user_can_admin_project
- unless @project.personal? && user == current_user
.pull-right
%strong= member.human_access
= button_tag class: "btn-xs btn js-toggle-button",
title: 'Edit access level', type: 'button' do
%i.fa.fa-pencil-square-o
- if current_user == user
= link_to leave_namespace_project_project_members_path(@project.namespace, @project), data: { confirm: "Leave project?"}, method: :delete, class: "btn-xs btn btn-remove", title: 'Leave project' do
%i.fa.fa-minus.fa-inverse
- else
= link_to namespace_project_project_member_path(@project.namespace, @project, user), data: { confirm: remove_from_project_team_message(@project, user) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from team' do
%i.fa.fa-minus.fa-inverse
.edit-member.hide.js-toggle-content
= form_for member, as: :project_member, url: namespace_project_project_member_path(@project.namespace, @project, member.user), remote: true do |f|
.alert.prepend-top-20
= f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level)
= f.submit 'Save', class: 'btn btn-save btn-sm'
- can_admin_project = can?(current_user, :admin_project, @project)
.panel.panel-default.prepend-top-20
.panel-heading
%strong #{@project.name}
project members
%small
(#{members.count})
%ul.well-list
- members.each do |project_member|
= render 'project_member', member: project_member, current_user_can_admin_project: can_admin_project
......@@ -3,12 +3,12 @@
%p.light
Only project members will be imported. Group members will be skipped.
%hr
= form_tag apply_import_namespace_project_team_members_path(@project.namespace, @project), method: 'post', class: 'form-horizontal' do
= form_tag apply_import_namespace_project_project_members_path(@project.namespace, @project), method: 'post', class: 'form-horizontal' do
.form-group
= label_tag :source_project_id, "Project", class: 'control-label'
.col-sm-10= select_tag(:source_project_id, options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace), prompt: "Select project", class: "select2 lg", required: true)
.form-actions
= button_tag 'Import project members', class: "btn btn-create"
= link_to "Cancel", namespace_project_team_index_path(@project.namespace, @project), class: "btn btn-cancel"
= link_to "Cancel", namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-cancel"
%h3.page-title
Users with access to this project
%p.light
Read more about project permissions
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
%hr
.clearfix.js-toggle-container
= form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form' do
.form-group
= search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control search-text-input input-mn-300' }
= button_tag 'Search', class: 'btn'
- if can?(current_user, :admin_project_member, @project)
%span.pull-right
= button_tag class: 'btn btn-new btn-grouped js-toggle-button', type: 'button' do
Add members
%i.fa.fa-chevron-down
= link_to import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-grouped", title: "Import members from another project" do
Import members
.js-toggle-content.hide.new-group-member-holder
= render "new_project_member"
= render "team", members: @project_members
- if @group
= render "group_members", members: @group_members
:coffeescript
$('form.member-search-form').on 'submit', (event) ->
event.preventDefault()
Turbolinks.visit @.action + '?' + $(@).serialize()
- can_admin_project = can?(current_user, :admin_project, @project)
:plain
$("##{dom_id(@project_member)}").replaceWith('#{escape_javascript(render("project_member", member: @project_member, current_user_can_admin_project: can_admin_project))}');
%h3.page-title
New project member(s)
= form_for @user_project_relation, as: :project_member, url: namespace_project_team_members_path(@project.namespace, @project), html: { class: "form-horizontal users-project-form" } do |f|
-if @user_project_relation.errors.any?
.alert.alert-danger
%ul
- @user_project_relation.errors.full_messages.each do |msg|
%li= msg
%p 1. Choose people you want in the project
.form-group
= f.label :user_ids, "People", class: 'control-label'
.col-sm-10
= users_select_tag(:user_ids, multiple: true)
%p 2. Set access level for them
.form-group
= f.label :access_level, "Project Access", class: 'control-label'
.col-sm-10
= select_tag :access_level, options_for_select(Gitlab::Access.options, @user_project_relation.access_level), class: "project-access-select select2"
.help-block
Read more about role permissions
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
.form-actions
= f.submit 'Add users', class: "btn btn-create"
= link_to "Cancel", namespace_project_team_index_path(@project.namespace, @project), class: "btn btn-cancel"
.team-table
- can_admin_project = (can? current_user, :admin_project, @project)
.panel.panel-default
.panel-heading
%strong #{@project.name}
project members (#{members.count})
%ul.well-list
- members.each do |team_member|
= render 'team_member', member: team_member, current_user_can_admin_project: can_admin_project
- user = member.user
%li{id: dom_id(user), class: "team_member_row access-#{member.human_access.downcase}"}
.pull-right
- if current_user_can_admin_project
- unless @project.personal? && user == current_user
.pull-left
= form_for(member, as: :project_member, url: namespace_project_team_member_path(@project.namespace, @project, member.user)) do |f|
= f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level), {}, class: "trigger-submit"
&nbsp;
= link_to namespace_project_team_member_path(@project.namespace, @project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove user from team' do
%i.fa.fa-minus.fa-inverse
= image_tag avatar_icon(user.email, 32), class: "avatar s32"
%p
%strong= user.name
- if user.blocked?
%label.label.label-danger
%strong Blocked
%span.cgray= user.username
%h3.page-title
Users with access to this project
- if can? current_user, :admin_team_member, @project
%span.pull-right
= link_to new_namespace_project_team_member_path(@project.namespace, @project), class: "btn btn-new btn-grouped", title: "New project member" do
New project member
= link_to import_namespace_project_team_members_path(@project.namespace, @project), class: "btn btn-grouped", title: "Import members from another project" do
Import members
%p.light
Read more about project permissions
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
= render "team", members: @project_members
- if @group
= render "group_members"
- if @user_project_relation.valid?
:plain
$("##{dom_id(@user_project_relation)}").effect("highlight", {color: "#529214"}, 1000);;
- else
:plain
$("##{dom_id(@user_project_relation)}").effect("highlight", {color: "#D12F19"}, 1000);;
......@@ -136,7 +136,7 @@ Gitlab::Application.routes.draw do
resources :groups, constraints: { id: /[^\/]+/ } do
member do
put :project_teams_update
put :members_update
end
end
......@@ -215,11 +215,7 @@ Gitlab::Application.routes.draw do
scope module: :dashboard do
resources :milestones, only: [:index, :show]
resources :groups, only: [:index] do
member do
delete :leave
end
end
resources :groups, only: [:index]
resources :projects, only: [] do
collection do
......@@ -236,12 +232,14 @@ Gitlab::Application.routes.draw do
member do
get :issues
get :merge_requests
get :members
get :projects
end
scope module: :groups do
resources :group_members, only: [:create, :update, :destroy]
resources :group_members, only: [:index, :create, :update, :destroy] do
delete :leave, on: :collection
end
resource :avatar, only: [:destroy]
resources :milestones, only: [:index, :show, :update]
end
......@@ -425,7 +423,6 @@ Gitlab::Application.routes.draw do
end
end
resources :team, controller: 'team_members', only: [:index]
resources :milestones, except: [:destroy], constraints: { id: /\d+/ } do
member do
put :sort_issues
......@@ -445,7 +442,7 @@ Gitlab::Application.routes.draw do
end
end
resources :team_members, except: [:index, :edit], constraints: { id: /[a-zA-Z.\/0-9_\-#%+]+/ } do
resources :project_members, except: [:new, :edit], constraints: { id: /[a-zA-Z.\/0-9_\-#%+]+/ } do
collection do
delete :leave
......
......@@ -13,7 +13,7 @@ Feature: Project Team Management
@javascript
Scenario: Add user to project
Given I click link "New Team Member"
Given I click link "Add members"
And I select "Mike" as "Reporter"
Then I should see "Mike" in team list as "Reporter"
......
......@@ -38,7 +38,7 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps
When 'I select user "John Doe" from user list as "Reporter"' do
select2(user_john.id, from: "#user_ids", multiple: true)
within "#new_team_member" do
within "#new_project_member" do
select "Reporter", from: "access_level"
end
click_button "Add users to group"
......
......@@ -35,7 +35,7 @@ class Spinach::Features::ExploreGroups < Spinach::FeatureSteps
end
step 'I visit group "TestGroup" members page' do
visit members_group_path(Group.find_by(name: "TestGroup"))
visit group_group_members_path(Group.find_by(name: "TestGroup"))
end
step 'I should not see project "Enterprise" items' do
......
......@@ -15,18 +15,18 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps
page.should have_content(user.username)
end
step 'I click link "New Team Member"' do
click_link "New project member"
step 'I click link "Add members"' do
find(:css, 'button.btn-new').click
end
step 'I select "Mike" as "Reporter"' do
user = User.find_by(name: "Mike")
select2(user.id, from: "#user_ids", multiple: true)
within "#new_project_member" do
within ".users-project-form" do
select2(user.id, from: "#user_ids", multiple: true)
select "Reporter", from: "access_level"
end
click_button "Add users"
click_button "Add users to project"
end
step 'I should see "Mike" in team list as "Reporter"' do
......@@ -42,9 +42,13 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps
end
step 'I change "Sam" role to "Reporter"' do
user = User.find_by(name: "Sam")
within "#user_#{user.id}" do
project = Project.find_by(name: "Shop")
user = User.find_by(name: 'Sam')
project_member = project.project_members.find_by(user_id: user.id)
within "#project_member_#{project_member.id}" do
click_button "Edit access level"
select "Reporter", from: "project_member_access_level"
click_button "Save"
end
end
......@@ -100,7 +104,10 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps
end
step 'I click cancel link for "Sam"' do
within "#user_#{User.find_by(name: 'Sam').id}" do
project = Project.find_by(name: "Shop")
user = User.find_by(name: 'Sam')
project_member = project.project_members.find_by(user_id: user.id)
within "#project_member_#{project_member.id}" do
click_link('Remove user from team')
end
end
......
......@@ -32,7 +32,7 @@ module SharedPaths
end
step 'I visit group "Owned" members page' do
visit members_group_path(Group.find_by(name:"Owned"))
visit group_group_members_path(Group.find_by(name:"Owned"))
end
step 'I visit group "Owned" settings page' do
......@@ -52,7 +52,7 @@ module SharedPaths
end
step 'I visit group "Guest" members page' do
visit members_group_path(Group.find_by(name:"Guest"))
visit group_group_members_path(Group.find_by(name:"Guest"))
end
step 'I visit group "Guest" settings page' do
......@@ -386,7 +386,7 @@ module SharedPaths
end
step 'I visit project "Shop" team page' do
visit namespace_project_team_index_path(project.namespace, project)
visit namespace_project_project_members_path(project.namespace, project)
end
step 'I visit project wiki page' do
......
......@@ -53,14 +53,14 @@ module API
authorize! :manage_group, group
required_attributes! [:access_level]
team_member = group.group_members.find_by(user_id: params[:user_id])
not_found!('User can not be found') if team_member.nil?
group_member = group.group_members.find_by(user_id: params[:user_id])
not_found!('User can not be found') if group_member.nil?
if team_member.update_attributes(access_level: params[:access_level])
@member = team_member.user
if group_member.update_attributes(access_level: params[:access_level])
@member = group_member.user
present @member, with: Entities::GroupMember, group: group
else
handle_member_errors team_member.errors
handle_member_errors group_member.errors
end
end
......
......@@ -46,19 +46,19 @@ module API
required_attributes! [:user_id, :access_level]
# either the user is already a team member or a new one
team_member = user_project.team_member_by_id(params[:user_id])
if team_member.nil?
team_member = user_project.project_members.new(
project_member = user_project.project_member_by_id(params[:user_id])
if project_member.nil?
project_member = user_project.project_members.new(
user_id: params[:user_id],
access_level: params[:access_level]
)
end
if team_member.save
@member = team_member.user
if project_member.save
@member = project_member.user
present @member, with: Entities::ProjectMember, project: user_project
else
handle_member_errors team_member.errors
handle_member_errors project_member.errors
end
end
......@@ -74,14 +74,14 @@ module API
authorize! :admin_project, user_project
required_attributes! [:access_level]
team_member = user_project.project_members.find_by(user_id: params[:user_id])
not_found!("User can not be found") if team_member.nil?
project_member = user_project.project_members.find_by(user_id: params[:user_id])
not_found!("User can not be found") if project_member.nil?
if team_member.update_attributes(access_level: params[:access_level])
@member = team_member.user
if project_member.update_attributes(access_level: params[:access_level])
@member = project_member.user
present @member, with: Entities::ProjectMember, project: user_project
else
handle_member_errors team_member.errors
handle_member_errors project_member.errors
end
end
......@@ -94,9 +94,9 @@ module API
# DELETE /projects/:id/members/:user_id
delete ":id/members/:user_id" do
authorize! :admin_project, user_project
team_member = user_project.project_members.find_by(user_id: params[:user_id])
unless team_member.nil?
team_member.destroy
project_member = user_project.project_members.find_by(user_id: params[:user_id])
unless project_member.nil?
project_member.destroy
else
{ message: "Access revoked", id: params[:user_id].to_i }
end
......
......@@ -200,7 +200,7 @@ module Gitlab
def reference_user(identifier, project = @project, _ = nil)
options = html_options.merge(
class: "gfm gfm-team_member #{html_options[:class]}"
class: "gfm gfm-project_member #{html_options[:class]}"
)
if identifier == "all"
......
......@@ -59,8 +59,8 @@ describe "Group access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/members" do
subject { members_group_path(group) }
describe "GET /groups/:path/group_members" do
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
......
......@@ -55,8 +55,8 @@ describe "Group with internal project access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/members" do
subject { members_group_path(group) }
describe "GET /groups/:path/group_members" do
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
......
......@@ -56,8 +56,8 @@ describe "Group access", feature: true do
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/members" do
subject { members_group_path(group) }
describe "GET /groups/:path/group_members" do
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
......
......@@ -55,8 +55,8 @@ describe "Group with public project access", feature: true do
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/members" do
subject { members_group_path(group) }
describe "GET /groups/:path/group_members" do
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
......
......@@ -79,8 +79,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/team" do
subject { namespace_project_team_index_path(project.namespace, project) }
describe "GET /:project_path/project_members" do
subject { namespace_project_project_members_path(project.namespace, project) }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_denied_for reporter }
......
......@@ -79,8 +79,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/team" do
subject { namespace_project_team_index_path(project.namespace, project) }
describe "GET /:project_path/project_members" do
subject { namespace_project_project_members_path(project.namespace, project) }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_denied_for reporter }
......
......@@ -84,8 +84,8 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/team" do
subject { namespace_project_team_index_path(project.namespace, project) }
describe "GET /:project_path/project_members" do
subject { namespace_project_project_members_path(project.namespace, project) }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_denied_for reporter }
......
......@@ -180,7 +180,7 @@ describe GitlabMarkdownHelper do
end
it "should include standard gfm classes" do
expect(gfm(actual)).to match(/class="\s?gfm gfm-team_member\s?"/)
expect(gfm(actual)).to match(/class="\s?gfm gfm-project_member\s?"/)
end
end
......
......@@ -28,18 +28,18 @@ describe GroupMember do
describe "#after_update" do
before do
@membership = create :group_member
@membership.stub(notification_service: double('NotificationService').as_null_object)
@group_member = create :group_member
@group_member.stub(notification_service: double('NotificationService').as_null_object)
end
it "should send email to user" do
expect(@membership).to receive(:notification_service)
@membership.update_attribute(:access_level, GroupMember::MASTER)
expect(@group_member).to receive(:notification_service)
@group_member.update_attribute(:access_level, GroupMember::MASTER)
end
it "does not send an email when the access level has not changed" do
expect(@membership).not_to receive(:notification_service)
@membership.update_attribute(:access_level, GroupMember::OWNER)
expect(@group_member).not_to receive(:notification_service)
@group_member.update_attribute(:access_level, GroupMember::OWNER)
end
end
end
......
......@@ -338,17 +338,14 @@ describe Projects::CommitsController, 'routing' do
end
end
# project_team_members GET /:project_id/team_members(.:format) team_members#index
# POST /:project_id/team_members(.:format) team_members#create
# new_project_team_member GET /:project_id/team_members/new(.:format) team_members#new
# edit_project_team_member GET /:project_id/team_members/:id/edit(.:format) team_members#edit
# project_team_member GET /:project_id/team_members/:id(.:format) team_members#show
# PUT /:project_id/team_members/:id(.:format) team_members#update
# DELETE /:project_id/team_members/:id(.:format) team_members#destroy
describe Projects::TeamMembersController, 'routing' do
# project_project_members GET /:project_id/project_members(.:format) project_members#index
# POST /:project_id/project_members(.:format) project_members#create
# PUT /:project_id/project_members/:id(.:format) project_members#update
# DELETE /:project_id/project_members/:id(.:format) project_members#destroy
describe Projects::ProjectMembersController, 'routing' do
it_behaves_like 'RESTful project resources' do
let(:actions) { [:new, :create, :update, :destroy] }
let(:controller) { 'team_members' }
let(:actions) { [:index, :create, :update, :destroy] }
let(:controller) { 'project_members' }
end
end
......
......@@ -69,9 +69,9 @@ describe NotificationService do
user_project = note.project.project_members.find_by_user_id(@u_watcher.id)
user_project.notification_level = Notification::N_PARTICIPATING
user_project.save
user_group = note.project.group.group_members.find_by_user_id(@u_watcher.id)
user_group.notification_level = Notification::N_GLOBAL
user_group.save
group_member = note.project.group.group_members.find_by_user_id(@u_watcher.id)
group_member.notification_level = Notification::N_GLOBAL
group_member.save
end
it do
......
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