Commit 877e42ec authored by Rémy Coutable's avatar Rémy Coutable
Browse files

Add request access for groups



Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent 58f08aa9e328
......@@ -286,10 +286,6 @@
color: #555;
}
.project_member_row form {
margin: 0;
}
.transfer-project .select2-container {
min-width: 200px;
}
......
class Groups::GroupMembersController < Groups::ApplicationController
# Authorize
before_action :authorize_admin_group_member!, except: [:index, :leave]
before_action :authorize_admin_group_member!, except: [:index, :leave, :request_access]
def index
@project = @group.projects.find(params[:project_id]) if params[:project_id]
@members = @group.group_members
......@@ -4,8 +4,8 @@
def index
@project = @group.projects.find(params[:project_id]) if params[:project_id]
@members = @group.group_members
@members = @members.non_invite unless can?(current_user, :admin_group, @group)
@members = @members.non_pending unless can?(current_user, :admin_group, @group)
if params[:search].present?
users = @group.users.search(params[:search]).to_a
......@@ -36,7 +36,7 @@
return render_403 unless can?(current_user, :destroy_group_member, @group_member)
@group_member.destroy
@group_member.request? ? @group_member.decline_request : @group_member.destroy
respond_to do |format|
format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
......@@ -59,6 +59,8 @@
end
def leave
@group_member = @group.group_members.find_by(user_id: current_user)
@group_member =
@group.group_members.find_by(user_id: current_user.id) ||
@group.group_members.find_by(created_by_id: current_user.id)
if can?(current_user, :destroy_group_member, @group_member)
......@@ -63,4 +65,10 @@
if can?(current_user, :destroy_group_member, @group_member)
notice =
if @group_member.request?
'You withdrawn your access request to the group.'
else
"You left #{@group.name} group."
end
@group_member.destroy
......@@ -65,6 +73,6 @@
@group_member.destroy
redirect_to(dashboard_groups_path, notice: "You left #{group.name} group.")
redirect_to dashboard_groups_path, notice: notice
else
if @group.last_owner?(current_user)
redirect_to(dashboard_groups_path, alert: "You can not leave #{group.name} group because you're the last owner. Transfer or delete the group.")
......@@ -74,6 +82,22 @@
end
end
def request_access
@group.request_access(current_user)
redirect_to group_path(@group), notice: 'Your request for access has been queued for review.'
end
def approve
@group_member = @group.group_members.request.find(params[:id])
return render_403 unless can?(current_user, :update_group_member, @group_member)
@group_member.accept_request
redirect_to group_group_members_path(@group)
end
protected
def member_params
......
......@@ -14,5 +14,6 @@
@project_members = @project_members.order('access_level DESC')
@group = @project.group
if @group
@group_members = @group.group_members
......@@ -17,6 +18,6 @@
if @group
@group_members = @group.group_members
@group_members = @group_members.non_invite unless can?(current_user, :admin_group, @group)
@group_members = @group_members.non_pending unless can?(current_user, :admin_group, @group)
if params[:search].present?
users = @group.users.search(params[:search]).to_a
......@@ -49,7 +50,7 @@
return render_403 unless can?(current_user, :destroy_project_member, @project_member)
@project_member.destroy
@project_member.request? ? @project_member.decline_request : @project_member.destroy
respond_to do |format|
format.html do
......@@ -74,6 +75,8 @@
end
def leave
@project_member = @project.project_members.find_by(user_id: current_user)
@project_member =
@project.project_members.find_by(user_id: current_user.id) ||
@project.project_members.find_by(created_by_id: current_user.id)
if can?(current_user, :destroy_project_member, @project_member)
......@@ -78,4 +81,10 @@
if can?(current_user, :destroy_project_member, @project_member)
notice =
if @project_member.request?
'You withdrawn your access request to the project.'
else
'You left the project.'
end
@project_member.destroy
......@@ -80,9 +89,6 @@
@project_member.destroy
respond_to do |format|
format.html { redirect_to dashboard_projects_path, notice: "You left the project." }
format.js { head :ok }
end
redirect_to dashboard_projects_path, notice: notice
else
if current_user == @project.owner
message = 'You can not leave your own project. Transfer or delete the project.'
......@@ -94,9 +100,5 @@
end
def request_access
redirect_path = namespace_project_path(@project.namespace, @project)
# current_user
# @project
@project_member = ProjectMember.new(source: @project, access_level: ProjectMember::DEVELOPER, user_id: current_user.id, created_by_id: current_user.id, requested: true)
@project_member.save!
@project.request_access(current_user)
......@@ -102,5 +104,5 @@
redirect_to redirect_path, notice: 'Your request for access has been queued for review.'
redirect_to namespace_project_path(@project.namespace, @project),
notice: 'Your request for access has been queued for review.'
end
......@@ -105,7 +107,7 @@
end
def approval
@project_member = @project.project_members.find(params[:id])
def approve
@project_member = @project.project_members.request.find(params[:id])
return render_403 unless can?(current_user, :update_project_member, @project_member)
......@@ -109,6 +111,5 @@
return render_403 unless can?(current_user, :update_project_member, @project_member)
@project_member.requested = nil
@project_member.save!
@project_member.accept_request
......@@ -114,10 +115,5 @@
respond_to do |format|
format.html do
redirect_to namespace_project_project_members_path(@project.namespace, @project)
end
format.js { render nothing: true }
end
redirect_to namespace_project_project_members_path(@project.namespace, @project)
end
def apply_import
......
module GroupsHelper
def remove_user_from_group_message(group, member)
if member.user
"Are you sure you want to remove \"#{member.user.name}\" from \"#{group.name}\"?"
else
"Are you sure you want to revoke the invitation for \"#{member.invite_email}\" to join \"#{group.name}\"?"
end
end
def leave_group_message(group)
"Are you sure you want to leave \"#{group}\" group?"
end
def should_user_see_group_roles?(user, group)
if user
user.is_admin? || group.members.exists?(user_id: user.id)
else
false
end
end
def can_change_group_visibility_level?(group)
can?(current_user, :change_visibility_level, group)
end
......
module MembersHelper
def member_class(member)
"#{member.source.class.to_s}Member".constantize
end
def members_association(entity)
"#{entity.class.to_s.underscore}_members".to_sym
end
def action_member_permission(action, member)
"#{action}_#{member.source.class.to_s.underscore}_member".to_sym
end
def can_see_entity_roles?(user, entity)
return false unless user
user.is_admin? || entity.send(members_association(entity)).exists?(user_id: user.id)
end
def member_path(member)
case member.source
when Project
namespace_project_project_member_path(member.source.namespace, member.source, member)
when Group
group_group_member_path(member.source, member)
else
raise ArgumentError.new('Unknown object class')
end
end
def resend_invite_member_path(member)
case member.source
when Project
resend_invite_namespace_project_project_member_path(member.source.namespace, member.source, member)
when Group
resend_invite_group_group_member_path(member.source, member)
else
raise ArgumentError.new('Unknown object class')
end
end
def request_access_path(entity)
case entity
when Project
request_access_namespace_project_project_members_path(entity.namespace, entity)
when Group
request_access_group_group_members_path(entity)
else
raise ArgumentError.new('Unknown object class')
end
end
def approve_request_member_path(member)
case member.source
when Project
approve_namespace_project_project_member_path(member.source.namespace, member.source, member)
when Group
approve_group_group_member_path(member.source, member)
else
raise ArgumentError.new('Unknown object class')
end
end
def leave_path(entity)
case entity
when Project
leave_namespace_project_project_members_path(entity.namespace, entity)
when Group
leave_group_group_members_path(entity)
else
raise ArgumentError.new('Unknown object class')
end
end
def withdraw_request_message(entity)
"Are you sure you want to withdraw your access request for the \"#{entity_name(entity)}\" #{entity_type(entity)}?"
end
def remove_member_message(member)
entity = member.source
entity_type = entity_type(entity)
entity_name = entity_name(entity)
if member.request?
"You are going to deny #{member.created_by.name}'s request to join the #{entity_name} #{entity_type}. Are you sure?"
elsif member.invite?
"You are going to revoke the invitation for #{member.invite_email} to join the #{entity_name} #{entity_type}. Are you sure?"
else
"You are going to remove #{member.user.name} from the #{entity_name} #{entity_type}. Are you sure?"
end
end
def remove_member_title(member)
member.request? ? 'Deny access request' : 'Remove user'
end
def leave_confirmation_message(entity)
"Are you sure you want to leave \"#{entity_name(entity)}\" #{entity_type(entity)}?"
end
private
def entity_type(entity)
entity.class.to_s.underscore
end
def entity_name(entity)
case entity
when Project
entity.name_with_namespace
when Group
entity.name
else
raise ArgumentError.new('Unknown object class')
end
end
end
module ProjectsHelper
def remove_from_project_team_message(project, member)
if !member.user
"You are going to revoke the invitation for #{member.invite_email} to join #{project.name} project team. Are you sure?"
elsif member.request?
"You are going to deny #{member.user.name}'s request to join #{project.name} project team. Are you sure?"
else
"You are going to remove #{member.user.name} from #{project.name} project team. Are you sure?"
end
end
def approve_for_project_team_message(project, member)
"You are going to approve #{member.user.name}'s request for #{member.human_access} access to the #{project.name} project team. Are you sure?"
def max_access_level(project, user)
Gitlab::Access.options_with_owner.key(project.team.max_member_access(user.id))
end
def link_to_project(project)
......@@ -121,14 +111,6 @@
end
end
def user_max_access_in_project(user_id, project)
level = project.team.max_member_access(user_id)
if level
Gitlab::Access.options_with_owner.key(level)
end
end
def license_short_name(project)
return 'LICENSE' if project.repository.license_key.nil?
......@@ -292,10 +274,6 @@
end
end
def leave_project_message(project)
"Are you sure you want to leave \"#{project.name}\" project?"
end
def new_readme_path
ref = @repository.root_ref if @repository
ref ||= 'master'
......
module Emails
module Groups
def group_access_requested_email(group_member_id)
setup_group_member_mail(group_member_id)
@requester = @group_member.created_by
group_admins = User.where(id: @group.group_members.admins.pluck(:user_id)).pluck(:notification_email)
mail(to: group_admins,
subject: subject("Request to join #{@group.name} group"))
end
def group_access_granted_email(group_member_id)
......@@ -3,4 +14,3 @@
def group_access_granted_email(group_member_id)
@group_member = GroupMember.find(group_member_id)
@group = @group_member.group
setup_group_member_mail(group_member_id)
......@@ -6,4 +16,3 @@
@target_url = group_url(@group)
@current_user = @group_member.user
......@@ -8,7 +17,16 @@
@current_user = @group_member.user
mail(to: @group_member.user.notification_email,
subject: subject("Access to group was granted"))
mail(to: @current_user.notification_email,
subject: subject("Access to #{@group.name} group was granted"))
end
def group_access_denied_email(group_id, user_id)
@group = Group.find(group_id)
@current_user = User.find(user_id)
@target_url = group_url(@group)
mail(to: @current_user.notification_email,
subject: subject("Access to #{@group.name} group was denied"))
end
def group_member_invited_email(group_member_id, token)
......@@ -12,6 +30,6 @@
end
def group_member_invited_email(group_member_id, token)
@group_member = GroupMember.find group_member_id
@group = @group_member.group
setup_group_member_mail(group_member_id)
@token = token
......@@ -17,6 +35,4 @@
@token = token
@target_url = group_url(@group)
@current_user = @group_member.user
mail(to: @group_member.invite_email,
......@@ -24,6 +40,6 @@
end
def group_invite_accepted_email(group_member_id)
@group_member = GroupMember.find group_member_id
setup_group_member_mail(group_member_id)
return if @group_member.created_by.nil?
......@@ -28,7 +44,4 @@
return if @group_member.created_by.nil?
@group = @group_member.group
@target_url = group_url(@group)
@current_user = @group_member.created_by
......@@ -33,6 +46,6 @@
@current_user = @group_member.created_by
mail(to: @group_member.created_by.notification_email,
mail(to: @current_user.notification_email,
subject: subject("Invitation accepted"))
end
......@@ -43,8 +56,8 @@
@current_user = @created_by = User.find(created_by_id)
@access_level = access_level
@invite_email = invite_email
@target_url = group_url(@group)
mail(to: @created_by.notification_email,
subject: subject("Invitation declined"))
end
......@@ -47,6 +60,14 @@
@target_url = group_url(@group)
mail(to: @created_by.notification_email,
subject: subject("Invitation declined"))
end
private
def setup_group_member_mail(group_member_id)
@group_member = GroupMember.find(group_member_id)
@group = @group_member.group
@target_url = group_url(@group)
end
end
end
module Emails
module Projects
def project_access_granted_email(project_member_id)
@project_member = ProjectMember.find project_member_id
@project = @project_member.project
def project_access_requested_email(project_member_id)
setup_project_member_mail(project_member_id)
......@@ -6,8 +5,3 @@
@target_url = namespace_project_url(@project.namespace, @project)
@current_user = @project_member.user
mail(to: @project_member.user.notification_email,
subject: subject("Access to project was granted"))
end
@requester = @project_member.created_by
......@@ -13,6 +7,3 @@
def project_member_requested_access(project_member_id)
@project_member = ProjectMember.find project_member_id
@project = @project_member.project
@target_url = namespace_project_url(@project.namespace, @project)
project_admins = User.where(id: @project.project_members.admins.pluck(:user_id)).pluck(:notification_email)
......@@ -18,11 +9,5 @@
project_admins = ProjectMember.in_project(@project)
.where(access_level: [Gitlab::Access::OWNER, Gitlab::Access::MASTER])
.pluck(:notification_email)
project_admins.each do |address|
mail(to: address,
subject: subject("Request to join project: #{@project.name_with_namespace}"))
end
mail(to: project_admins,
subject: subject("Request to join #{@project.name_with_namespace} project"))
end
......@@ -27,8 +12,5 @@
end
def project_request_access_accepted_email(project_member_id)
@project_member = ProjectMember.find project_member_id
return if @project_member.created_by.nil?
@project = @project_member.project
def project_access_granted_email(project_member_id)
setup_project_member_mail(project_member_id)
......@@ -34,4 +16,3 @@
@target_url = namespace_project_url(@project.namespace, @project)
@current_user = @project_member.created_by
@current_user = @project_member.user
......@@ -37,5 +18,5 @@
mail(to: @project_member.created_by.notification_email,
subject: subject('Request for access granted'))
mail(to: @current_user.notification_email,
subject: subject("Access to #{@project.name_with_namespace} project was granted"))
end
......@@ -40,8 +21,7 @@
end
def project_request_access_declined_email(project_member_id)
@project_member = ProjectMember.find project_member_id
return if @project_member.created_by.nil?
@project = @project_member.project
def project_access_denied_email(project_id, user_id)
@project = Project.find(project_id)
@current_user = User.find(user_id)
@target_url = namespace_project_url(@project.namespace, @project)
......@@ -47,8 +27,5 @@
@target_url = namespace_project_url(@project.namespace, @project)
@current_user = @project_member.created_by
mail(to: @project_member.created_by.notification_email,
subject: subject('Request for access declined'))
mail(to: @current_user.notification_email,
subject: subject("Access to #{@project.name_with_namespace} project was denied"))
end
......@@ -53,3 +30,5 @@
end
def project_member_invited_email(project_member_id, token)
setup_project_member_mail(project_member_id)
......@@ -55,5 +34,2 @@
def project_member_invited_email(project_member_id, token)
@project_member = ProjectMember.find project_member_id
@project = @project_member.project
@token = token
......@@ -59,6 +35,4 @@
@token = token
@target_url = namespace_project_url(@project.namespace, @project)
@current_user = @project_member.user
mail(to: @project_member.invite_email,
......@@ -66,6 +40,6 @@
end
def project_invite_accepted_email(project_member_id)
@project_member = ProjectMember.find project_member_id
setup_project_member_mail(project_member_id)
return if @project_member.created_by.nil?
......@@ -70,8 +44,5 @@
return if @project_member.created_by.nil?
@project = @project_member.project
@target_url = namespace_project_url(@project.namespace, @project)
@current_user = @project_member.created_by
mail(to: @project_member.created_by.notification_email,
......@@ -117,5 +88,13 @@
reply_to: @message.reply_to,
subject: @message.subject)
end
private
def setup_project_member_mail(project_member_id)
@project_member = ProjectMember.find(project_member_id)
@project = @project_member.project
@target_url = namespace_project_url(@project.namespace, @project)
end
end
end