mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-20 18:16:45 +10:00
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:  After:  See merge request !1695
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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.'
|
||||
|
||||
@@ -1,21 +1,5 @@
|
||||
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
|
||||
|
||||
@@ -1,15 +1,30 @@
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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]
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
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
|
||||
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
|
||||
@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_project_members_path(@project.namespace, @project)
|
||||
end
|
||||
|
||||
def update
|
||||
@project_member = @project.project_members.find_by(user_id: member)
|
||||
@project_member.update_attributes(member_params)
|
||||
end
|
||||
|
||||
def 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_project_members_path(@project.namespace,
|
||||
@project)
|
||||
end
|
||||
format.js { render nothing: true }
|
||||
end
|
||||
end
|
||||
|
||||
def leave
|
||||
@project.project_members.find_by(user_id: current_user).destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to :back }
|
||||
format.js { render nothing: true }
|
||||
end
|
||||
end
|
||||
|
||||
def apply_import
|
||||
giver = Project.find(params[:source_project_id])
|
||||
status = @project.team.import(giver)
|
||||
notice = status ? "Successfully imported" : "Import failed"
|
||||
|
||||
redirect_to(namespace_project_project_members_path(project.namespace, project),
|
||||
notice: notice)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def member
|
||||
@member ||= User.find_by(username: params[:id])
|
||||
end
|
||||
|
||||
def member_params
|
||||
params.require(:project_member).permit(:user_id, :access_level)
|
||||
end
|
||||
end
|
||||
@@ -1,73 +0,0 @@
|
||||
class Projects::TeamMembersController < Projects::ApplicationController
|
||||
# Authorize
|
||||
before_filter :authorize_admin_project!, except: :leave
|
||||
|
||||
layout "project_settings"
|
||||
|
||||
def index
|
||||
@group = @project.group
|
||||
@project_members = @project.project_members.order('access_level DESC')
|
||||
end
|
||||
|
||||
def new
|
||||
@user_project_relation = @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)
|
||||
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)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@user_project_relation = @project.project_members.find_by(user_id: member)
|
||||
@user_project_relation.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to namespace_project_team_index_path(@project.namespace,
|
||||
@project)
|
||||
end
|
||||
format.js { render nothing: true }
|
||||
end
|
||||
end
|
||||
|
||||
def leave
|
||||
@project.project_members.find_by(user_id: current_user).destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to :back }
|
||||
format.js { render nothing: true }
|
||||
end
|
||||
end
|
||||
|
||||
def apply_import
|
||||
giver = Project.find(params[:source_project_id])
|
||||
status = @project.team.import(giver)
|
||||
notice = status ? "Successfully imported" : "Import failed"
|
||||
|
||||
redirect_to(namespace_project_team_index_path(project.namespace, project),
|
||||
notice: notice)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def member
|
||||
@member ||= User.find_by(username: params[:id])
|
||||
end
|
||||
|
||||
def member_params
|
||||
params.require(:project_member).permit(:user_id, :access_level)
|
||||
end
|
||||
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
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
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
|
||||
|
||||
|
||||
+21
-21
@@ -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)
|
||||
|
||||
|
||||
+1
-4
@@ -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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
- 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
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
= 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"
|
||||
@@ -1,4 +1,5 @@
|
||||
- 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
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
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
%strong #{@group.name}
|
||||
group members
|
||||
%small
|
||||
(#{members.count})
|
||||
.pull-right
|
||||
= link_to group_group_members_path(@group), class: 'btn btn-sm' do
|
||||
%i.fa.fa-pencil-square-o
|
||||
%ul.well-list
|
||||
- members.each do |member|
|
||||
= render 'groups/group_members/group_member', member: member, show_controls: false
|
||||
- if members.count > 20
|
||||
%li
|
||||
and #{members.count - 20} more. For full list visit #{link_to 'group members page', group_group_members_path(@group)}
|
||||
@@ -0,0 +1,15 @@
|
||||
= 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"
|
||||
@@ -0,0 +1,34 @@
|
||||
- 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'
|
||||
@@ -0,0 +1,11 @@
|
||||
- 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
|
||||
+2
-2
@@ -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"
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
%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()
|
||||
@@ -0,0 +1,3 @@
|
||||
- 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))}');
|
||||
@@ -1,29 +0,0 @@
|
||||
%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"
|
||||
@@ -1,14 +0,0 @@
|
||||
- group_users_count = @group.group_members.count
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
%strong #{@group.name}
|
||||
group members (#{group_users_count})
|
||||
.pull-right
|
||||
= link_to members_group_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|
|
||||
= render 'groups/group_members/group_member', member: member, show_controls: false
|
||||
- if group_users_count > 20
|
||||
%li
|
||||
and #{group_users_count - 20} more. For full list visit #{link_to 'group members page', members_group_path(@group)}
|
||||
@@ -1,9 +0,0 @@
|
||||
.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
|
||||
@@ -1,18 +0,0 @@
|
||||
- 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"
|
||||
|
||||
= 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
|
||||
@@ -1,16 +0,0 @@
|
||||
%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"
|
||||
@@ -1 +0,0 @@
|
||||
= render "form"
|
||||
@@ -1,6 +0,0 @@
|
||||
- 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);;
|
||||
+7
-10
@@ -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
|
||||
|
||||
|
||||
+14
-14
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user