From 455a4fe91a32d0ab2de72d1e62a7a6edfcb40d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1o=20Stanovnik?= Date: Tue, 24 Mar 2015 00:11:41 +0100 Subject: Fixed generating SSH key fingerprints in OpenSSH 6.8. --- app/models/key.rb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/models/key.rb b/app/models/key.rb index e2e59296eed..b74daf50fec 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -86,7 +86,24 @@ class Key < ActiveRecord::Base Tempfile.open('gitlab_key_file') do |file| file.puts key file.rewind - cmd_output, cmd_status = popen(%W(ssh-keygen -lf #{file.path}), '/tmp') + + # OpenSSH 6.8 introduces a new default output format for fingerprints. + # Check the version and decide which command to use. + version_output, version_status = popen(%W(ssh -V)) + explicit_fingerprint_algorithm = false + if version_status.zero? + out, _ = version_output.scan /.*?(\d)\.(\d).*?,/ + major, minor = out[0], out[1] + if major.to_i > 6 or (major.to_i == 6 and minor.to_i >= 8) + explicit_fingerprint_algorithm = true + end + end + + if explicit_fingerprint_algorithm + cmd_output, cmd_status = popen(%W(ssh-keygen -E md5 -lf #{file.path}), '/tmp') + else + cmd_output, cmd_status = popen(%W(ssh-keygen -lf #{file.path}), '/tmp') + end end if cmd_status.zero? -- cgit v1.2.1 From 05d4658b3233b3f37876772c10fbf5e648682154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1o=20Stanovnik?= Date: Tue, 24 Mar 2015 00:49:30 +0100 Subject: Use 2 spaces for indentation, not 4. --- app/models/key.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/models/key.rb b/app/models/key.rb index b74daf50fec..1c41f8b8d7a 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -95,7 +95,7 @@ class Key < ActiveRecord::Base out, _ = version_output.scan /.*?(\d)\.(\d).*?,/ major, minor = out[0], out[1] if major.to_i > 6 or (major.to_i == 6 and minor.to_i >= 8) - explicit_fingerprint_algorithm = true + explicit_fingerprint_algorithm = true end end -- cgit v1.2.1 From 38384bd9521a42683d9ba33ac482993496c6f986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1o=20Stanovnik?= Date: Tue, 24 Mar 2015 10:55:31 +0100 Subject: The new fingerprint format wis incompatible with the previous regex. --- app/models/key.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/models/key.rb b/app/models/key.rb index 1c41f8b8d7a..480a16f9335 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -83,14 +83,14 @@ class Key < ActiveRecord::Base cmd_status = 0 cmd_output = '' + explicit_fingerprint_algorithm = false Tempfile.open('gitlab_key_file') do |file| file.puts key file.rewind - + # OpenSSH 6.8 introduces a new default output format for fingerprints. # Check the version and decide which command to use. version_output, version_status = popen(%W(ssh -V)) - explicit_fingerprint_algorithm = false if version_status.zero? out, _ = version_output.scan /.*?(\d)\.(\d).*?,/ major, minor = out[0], out[1] @@ -107,8 +107,15 @@ class Key < ActiveRecord::Base end if cmd_status.zero? - cmd_output.gsub /(\h{2}:)+\h{2}/ do |match| - self.fingerprint = match + if explicit_fingerprint_algorithm + cmd_output.gsub /(MD5:)(\h{2}:)+\h{2}/ do |match| + match.slice! /^MD5:/ + self.fingerprint = match + end + else + cmd_output.gsub /(\h{2}:)+\h{2}/ do |match| + self.fingerprint = match + end end end end -- cgit v1.2.1 From 1221bec56ca7d3bf1ba3b09e7a283ff5c11449f2 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 12:00:43 +0200 Subject: Refactor key fingerprint generation. --- app/models/key.rb | 44 ++++---------------------------------------- 1 file changed, 4 insertions(+), 40 deletions(-) (limited to 'app') diff --git a/app/models/key.rb b/app/models/key.rb index 480a16f9335..016eee86992 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -16,7 +16,6 @@ require 'digest/md5' class Key < ActiveRecord::Base include Sortable - include Gitlab::Popen belongs_to :user @@ -79,44 +78,9 @@ class Key < ActiveRecord::Base def generate_fingerprint self.fingerprint = nil - return unless key.present? - - cmd_status = 0 - cmd_output = '' - explicit_fingerprint_algorithm = false - Tempfile.open('gitlab_key_file') do |file| - file.puts key - file.rewind - - # OpenSSH 6.8 introduces a new default output format for fingerprints. - # Check the version and decide which command to use. - version_output, version_status = popen(%W(ssh -V)) - if version_status.zero? - out, _ = version_output.scan /.*?(\d)\.(\d).*?,/ - major, minor = out[0], out[1] - if major.to_i > 6 or (major.to_i == 6 and minor.to_i >= 8) - explicit_fingerprint_algorithm = true - end - end - - if explicit_fingerprint_algorithm - cmd_output, cmd_status = popen(%W(ssh-keygen -E md5 -lf #{file.path}), '/tmp') - else - cmd_output, cmd_status = popen(%W(ssh-keygen -lf #{file.path}), '/tmp') - end - end - - if cmd_status.zero? - if explicit_fingerprint_algorithm - cmd_output.gsub /(MD5:)(\h{2}:)+\h{2}/ do |match| - match.slice! /^MD5:/ - self.fingerprint = match - end - else - cmd_output.gsub /(\h{2}:)+\h{2}/ do |match| - self.fingerprint = match - end - end - end + + return unless self.key.present? + + self.fingerprint = Gitlab::KeyFingerprint.new(self.key).fingerprint end end -- cgit v1.2.1 From ff3caad4caf46049c8f202849a05fb15a2aaccb8 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 14:39:10 +0200 Subject: Rename manage_group ability to admin_group for consistency with project. --- app/controllers/groups/application_controller.rb | 2 +- app/controllers/groups/milestones_controller.rb | 2 +- app/models/ability.rb | 12 ++++++------ app/views/dashboard/groups/index.html.haml | 2 +- app/views/groups/group_members/index.html.haml | 2 +- app/views/groups/milestones/_milestone.html.haml | 2 +- app/views/groups/milestones/show.html.haml | 2 +- app/views/groups/projects.html.haml | 2 +- app/views/layouts/nav/_group.html.haml | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) (limited to 'app') diff --git a/app/controllers/groups/application_controller.rb b/app/controllers/groups/application_controller.rb index a73b8fa212a..469a6813ee2 100644 --- a/app/controllers/groups/application_controller.rb +++ b/app/controllers/groups/application_controller.rb @@ -13,7 +13,7 @@ class Groups::ApplicationController < ApplicationController end def authorize_admin_group! - unless can?(current_user, :manage_group, group) + unless can?(current_user, :admin_group, group) return render_404 end end diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index c46b8fff88f..546ff2cc71f 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -51,6 +51,6 @@ class Groups::MilestonesController < ApplicationController end def authorize_group_milestone! - return render_404 unless can?(current_user, :manage_group, group) + return render_404 unless can?(current_user, :admin_group, group) end end diff --git a/app/models/ability.rb b/app/models/ability.rb index d2b39f667f2..85a15596f8d 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -198,11 +198,11 @@ class Ability ]) end - # Only group owner and administrators can manage group + # Only group owner and administrators can admin group if group.has_owner?(user) || user.admin? rules.push(*[ - :manage_group, - :manage_namespace + :admin_group, + :admin_namespace ]) end @@ -212,11 +212,11 @@ class Ability def namespace_abilities(user, namespace) rules = [] - # Only namespace owner and administrators can manage it + # Only namespace owner and administrators can admin it if namespace.owner == user || user.admin? rules.push(*[ :create_projects, - :manage_namespace + :admin_namespace ]) end @@ -254,7 +254,7 @@ class Ability rules = [] target_user = subject.user group = subject.group - can_manage = group_abilities(user, group).include?(:manage_group) + can_manage = group_abilities(user, group).include?(:admin_group) if can_manage && (user != target_user) rules << :modify_group_member rules << :destroy_group_member diff --git a/app/views/dashboard/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml index 165db214d75..0cb7f764fab 100644 --- a/app/views/dashboard/groups/index.html.haml +++ b/app/views/dashboard/groups/index.html.haml @@ -17,7 +17,7 @@ - group = group_member.group %li .pull-right - - if can?(current_user, :manage_group, group) + - if can?(current_user, :admin_group, group) = link_to edit_group_path(group), class: "btn-sm btn btn-grouped" do %i.fa.fa-cogs Settings diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index 0d501fe7bd3..c0c9cd170ad 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -16,7 +16,7 @@ = 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 current_user && current_user.can?(:manage_group, @group) + - if current_user && current_user.can?(:admin_group, @group) .pull-right = button_tag class: 'btn btn-new js-toggle-button', type: 'button' do Add members diff --git a/app/views/groups/milestones/_milestone.html.haml b/app/views/groups/milestones/_milestone.html.haml index 94fc43a581e..30093d2d05d 100644 --- a/app/views/groups/milestones/_milestone.html.haml +++ b/app/views/groups/milestones/_milestone.html.haml @@ -1,6 +1,6 @@ %li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) } .pull-right - - if can?(current_user, :manage_group, @group) + - if can?(current_user, :admin_group, @group) - if milestone.closed? = link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen" - else diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml index fea70f5cbc3..fb32f2caa4c 100644 --- a/app/views/groups/milestones/show.html.haml +++ b/app/views/groups/milestones/show.html.haml @@ -6,7 +6,7 @@ Open Milestone #{@group_milestone.title} .pull-right - - if can?(current_user, :manage_group, @group) + - if can?(current_user, :admin_group, @group) - if @group_milestone.active? = link_to 'Close Milestone', group_milestone_path(@group, @group_milestone.safe_title, title: @group_milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-sm btn-close" - else diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml index dd1fa3840d5..0d547984cc9 100644 --- a/app/views/groups/projects.html.haml +++ b/app/views/groups/projects.html.haml @@ -2,7 +2,7 @@ .panel-heading %strong= @group.name projects: - - if can? current_user, :manage_group, @group + - if can? current_user, :admin_group, @group .panel-head-actions = link_to new_project_path(namespace_id: @group.id), class: "btn btn-sm btn-success" do %i.fa.fa-plus diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml index 32fe0e37df8..f0d92b7a12c 100644 --- a/app/views/layouts/nav/_group.html.haml +++ b/app/views/layouts/nav/_group.html.haml @@ -30,7 +30,7 @@ %span Members - - if can?(current_user, :manage_group, @group) + - if can?(current_user, :admin_group, @group) = nav_link(html_options: { class: "#{"active" if group_settings_page?} separate-item" }) do = link_to edit_group_path(@group), title: 'Settings', class: "tab no-highlight" do %i.fa.fa-cogs -- cgit v1.2.1 From 2b2bd402dcee427a43de771036b348e156fea6c9 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 14:46:09 +0200 Subject: Track who created a group or project member. --- app/controllers/admin/groups_controller.rb | 2 +- app/controllers/groups/group_members_controller.rb | 2 +- .../projects/project_members_controller.rb | 2 +- app/models/group.rb | 16 +++++++------ app/models/member.rb | 5 ++++ app/models/members/project_member.rb | 3 ++- app/models/project_team.rb | 28 ++++++++++------------ app/services/projects/create_service.rb | 2 +- app/services/projects/fork_service.rb | 2 +- 9 files changed, 34 insertions(+), 28 deletions(-) (limited to 'app') diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index 9d9adaa467f..22d045fc388 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -41,7 +41,7 @@ class Admin::GroupsController < Admin::ApplicationController end def members_update - @group.add_users(params[:user_ids].split(','), params[:access_level]) + @group.add_users(params[:user_ids].split(','), params[:access_level], current_user) redirect_to [:admin, @group], notice: 'Users were successfully added.' end diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 2df51c97a22..93fc4edb3bb 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -22,7 +22,7 @@ class Groups::GroupMembersController < Groups::ApplicationController end def create - @group.add_users(params[:user_ids].split(','), params[:access_level]) + @group.add_users(params[:user_ids].split(','), params[:access_level], current_user) redirect_to group_group_members_path(@group), notice: 'Users were successfully added.' end diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 4ab15db01f7..e534db7af84 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -69,7 +69,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController def apply_import giver = Project.find(params[:source_project_id]) - status = @project.team.import(giver) + status = @project.team.import(giver, current_user) notice = status ? "Successfully imported" : "Import failed" redirect_to(namespace_project_project_members_path(project.namespace, project), diff --git a/app/models/group.rb b/app/models/group.rb index da9621a2a1a..eec961f6012 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -46,19 +46,21 @@ class Group < Namespace @owners ||= group_members.owners.map(&:user) end - def add_users(user_ids, access_level) + def add_users(user_ids, access_level, current_user = nil) user_ids.compact.each do |user_id| - user = self.group_members.find_or_initialize_by(user_id: user_id) - user.update_attributes(access_level: access_level) + member = self.group_members.find_or_initialize_by(user_id: user_id) + member.access_level = access_level + member.created_by ||= current_user + member.save end end - def add_user(user, access_level) - self.group_members.create(user_id: user.id, access_level: access_level) + def add_user(user, access_level, current_user = nil) + add_users([user], access_level, current_user) end - def add_owner(user) - self.add_user(user, Gitlab::Access::OWNER) + def add_owner(user, current_user = nil) + self.add_user(user, Gitlab::Access::OWNER, current_user) end def has_owner?(user) diff --git a/app/models/member.rb b/app/models/member.rb index fe3d2f40e87..d92e69b2ce6 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -11,6 +11,10 @@ # type :string(255) # created_at :datetime # updated_at :datetime +# created_by_id :integer +# invite_email :string +# invite_token :string +# invite_accepted_at :datetime # class Member < ActiveRecord::Base @@ -18,6 +22,7 @@ class Member < ActiveRecord::Base include Notifiable include Gitlab::Access + belongs_to :created_by, class_name: "User" belongs_to :user belongs_to :source, polymorphic: true diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 6b13e0ff30b..2205041cd51 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -55,7 +55,7 @@ class ProjectMember < Member # :master # ) # - def add_users_into_projects(project_ids, user_ids, access) + def add_users_into_projects(project_ids, user_ids, access, current_user = nil) access_level = if roles_hash.has_key?(access) roles_hash[access] elsif roles_hash.values.include?(access.to_i) @@ -69,6 +69,7 @@ class ProjectMember < Member user_ids.each do |user_id| member = ProjectMember.new(access_level: access_level, user_id: user_id) member.source_id = project_id + member.created_by ||= current_user member.save end end diff --git a/app/models/project_team.rb b/app/models/project_team.rb index d4a07caf9ef..313e459d701 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -12,12 +12,12 @@ class ProjectTeam # @team << [@users, :master] # def <<(args) - users = args.first + users, access, current_user = *args if users.respond_to?(:each) - add_users(users, args.second) + add_users(users, access, current_user) else - add_user(users, args.second) + add_user(users, access, current_user) end end @@ -43,22 +43,19 @@ class ProjectTeam member end - def add_user(user, access) - add_users_ids([user.id], access) - end - - def add_users(users, access) - add_users_ids(users.map(&:id), access) - end - - def add_users_ids(user_ids, access) + def add_users(users, access, current_user = nil) ProjectMember.add_users_into_projects( [project.id], - user_ids, - access + users, + access, + current_user ) end + def add_user(user, access, current_user = nil) + add_users([user], access, current_user) + end + # Remove all users from project team def truncate ProjectMember.truncate_team(project) @@ -88,7 +85,7 @@ class ProjectTeam @masters ||= fetch_members(:masters) end - def import(source_project) + def import(source_project, current_user = nil) target_project = project source_members = source_project.project_members.to_a @@ -103,6 +100,7 @@ class ProjectTeam new_member = member.dup new_member.id = nil new_member.source = target_project + new_member.created_by = current_user new_member end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 7ffd0b3882a..a7afcf8f64b 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -83,7 +83,7 @@ module Projects system_hook_service.execute_hooks_for(@project, :create) unless @project.group - @project.team << [current_user, :master] + @project.team << [current_user, :master, current_user] end @project.update_column(:last_activity_at, @project.created_at) diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb index 4ec98696a65..1e4deb6ed39 100644 --- a/app/services/projects/fork_service.rb +++ b/app/services/projects/fork_service.rb @@ -38,7 +38,7 @@ module Projects #First save the DB entries as they can be rolled back if the repo fork fails project.build_forked_project_link(forked_to_project_id: project.id, forked_from_project_id: @from_project.id) if project.save - project.team << [@current_user, :master] + project.team << [@current_user, :master, @current_user] end #Now fork the repo -- cgit v1.2.1 From 629fa7fbe3a8a2f06d7c053ddcbcd78beed24e9c Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:09:37 +0200 Subject: Add invite logic to Member. --- app/models/member.rb | 82 +++++++++++++++++++++++++++++++++++- app/models/members/group_member.rb | 23 +++------- app/models/members/project_member.rb | 33 ++++++--------- 3 files changed, 100 insertions(+), 38 deletions(-) (limited to 'app') diff --git a/app/models/member.rb b/app/models/member.rb index d92e69b2ce6..ec79f531740 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -26,16 +26,94 @@ class Member < ActiveRecord::Base belongs_to :user belongs_to :source, polymorphic: true - validates :user, presence: true + validates :user, presence: true, unless: :invite? validates :source, presence: true - validates :user_id, uniqueness: { scope: [:source_type, :source_id], message: "already exists in source" } + validates :user_id, uniqueness: { scope: [:source_type, :source_id], + message: "already exists in source", + allow_nil: true } validates :access_level, inclusion: { in: Gitlab::Access.all_values }, presence: true + validates :invite_email, presence: { if: :invite? }, + email: { strict_mode: true, allow_nil: true }, + uniqueness: { scope: [:source_type, :source_id], allow_nil: true } + scope :invite, -> { where(user_id: nil) } + scope :non_invite, -> { where("user_id IS NOT NULL") } scope :guests, -> { where(access_level: GUEST) } scope :reporters, -> { where(access_level: REPORTER) } scope :developers, -> { where(access_level: DEVELOPER) } scope :masters, -> { where(access_level: MASTER) } scope :owners, -> { where(access_level: OWNER) } + before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? } + after_create :send_invite, if: :invite? + after_create :post_create_hook, unless: :invite? + after_update :post_update_hook, unless: :invite? + after_destroy :post_destroy_hook, unless: :invite? + delegate :name, :username, :email, to: :user, prefix: true + + def invite? + self.invite_token.present? + end + + def accept_invite!(new_user) + self.invite_token = nil + self.invite_accepted_at = Time.now.utc + + self.user = new_user + + saved = self.save + + after_accept_invite if saved + + saved + end + + def generate_invite_token + raw, enc = Devise.token_generator.generate(self.class, :invite_token) + @raw_invite_token = raw + self.invite_token = enc + end + + def generate_invite_token! + generate_invite_token && save(validate: false) + end + + def resend_invite + return unless invite? + + generate_invite_token! unless @raw_invite_token + + send_invite + end + + private + + def send_invite + # override in subclass + end + + def post_create_hook + system_hook_service.execute_hooks_for(self, :create) + end + + def post_update_hook + # override in subclass + end + + def post_destroy_hook + system_hook_service.execute_hooks_for(self, :destroy) + end + + def after_accept_invite + post_create_hook + end + + def system_hook_service + SystemHooksService.new + end + + def notification_service + NotificationService.new + end end diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index 28d0b4483b4..ccbbab6afc5 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -27,10 +27,6 @@ class GroupMember < Member scope :with_group, ->(group) { where(source_id: group.id) } scope :with_user, ->(user) { where(user_id: user.id) } - after_create :post_create_hook - after_update :notify_update - after_destroy :post_destroy_hook - def self.access_level_roles Gitlab::Access.options_with_owner end @@ -43,26 +39,19 @@ class GroupMember < Member access_level end + private + def post_create_hook notification_service.new_group_member(self) - system_hook_service.execute_hooks_for(self, :create) + + super end - def notify_update + def post_update_hook if access_level_changed? notification_service.update_group_member(self) end - end - - def post_destroy_hook - system_hook_service.execute_hooks_for(self, :destroy) - end - - def system_hook_service - SystemHooksService.new - end - def notification_service - NotificationService.new + super end end diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 2205041cd51..6c5d161940d 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -27,10 +27,6 @@ class ProjectMember < Member validates_format_of :source_type, with: /\AProject\z/ default_scope { where(source_type: SOURCE_TYPE) } - after_create :post_create_hook - after_update :post_update_hook - after_destroy :post_destroy_hook - scope :in_project, ->(project) { where(source_id: project.id) } scope :in_projects, ->(projects) { where(source_id: projects.pluck(:id)) } scope :with_user, ->(user) { where(user_id: user.id) } @@ -110,41 +106,40 @@ class ProjectMember < Member access_level end + def project + source + end + def owner? project.owner == user end + private + def post_create_hook unless owner? event_service.join_project(self.project, self.user) notification_service.new_project_member(self) end - system_hook_service.execute_hooks_for(self, :create) + super end def post_update_hook - notification_service.update_project_member(self) if self.access_level_changed? + if access_level_changed? + notification_service.update_project_member(self) + end + + super end def post_destroy_hook event_service.leave_project(self.project, self.user) - system_hook_service.execute_hooks_for(self, :destroy) + + super end def event_service EventCreateService.new end - - def notification_service - NotificationService.new - end - - def system_hook_service - SystemHooksService.new - end - - def project - source - end end -- cgit v1.2.1 From cee98f22478b5ec27f91da04fe564a9760f79a38 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:13:00 +0200 Subject: Reference project members by id instead of user_id. --- app/controllers/projects/project_members_controller.rb | 8 ++------ app/views/admin/projects/show.html.haml | 2 +- app/views/projects/project_members/_project_member.html.haml | 4 ++-- 3 files changed, 5 insertions(+), 9 deletions(-) (limited to 'app') diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index e534db7af84..99ee3ebf92e 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -41,12 +41,12 @@ class Projects::ProjectMembersController < Projects::ApplicationController end def update - @project_member = @project.project_members.find_by(user_id: member) + @project_member = @project.project_members.find(params[:id]) @project_member.update_attributes(member_params) end def destroy - @project_member = @project.project_members.find_by(user_id: member) + @project_member = @project.project_members.find(params[:id]) @project_member.destroy respond_to do |format| @@ -78,10 +78,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController protected - def member - @member ||= User.find_by(username: params[:id]) - end - def member_params params.require(:project_member).permit(:user_id, :access_level) end diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index b0b23132560..be31551dc96 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -131,7 +131,7 @@ %span.light Owner - else %span.light= project_member.human_access - = 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 + = link_to namespace_project_project_member_path(@project.namespace, @project, project_member), 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' diff --git a/app/views/projects/project_members/_project_member.html.haml b/app/views/projects/project_members/_project_member.html.haml index 4f053977215..67d703a4121 100644 --- a/app/views/projects/project_members/_project_member.html.haml +++ b/app/views/projects/project_members/_project_member.html.haml @@ -25,12 +25,12 @@ = 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 + = link_to namespace_project_project_member_path(@project.namespace, @project, member), 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 %br - = form_for member, as: :project_member, url: namespace_project_project_member_path(@project.namespace, @project, member.user), remote: true do |f| + = form_for member, as: :project_member, url: namespace_project_project_member_path(@project.namespace, @project, member), remote: true do |f| .prepend-top-10 = f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level), {}, class: 'form-control' .prepend-top-10 -- cgit v1.2.1 From 2a1d4255da396d37579e25dd88d5a9ea76116c22 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:14:14 +0200 Subject: Correctly render invite members without user. --- app/helpers/groups_helper.rb | 8 ++++-- app/helpers/projects_helper.rb | 8 ++++-- app/views/admin/groups/show.html.haml | 13 ++++++--- app/views/admin/projects/show.html.haml | 11 ++++++-- app/views/admin/users/show.html.haml | 4 +-- .../groups/group_members/_group_member.html.haml | 31 ++++++++++++++------- .../project_members/_project_member.html.haml | 32 +++++++++++++++------- 7 files changed, 74 insertions(+), 33 deletions(-) (limited to 'app') diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 2d0d0b494f6..52d88133d5e 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -1,6 +1,10 @@ module GroupsHelper - def remove_user_from_group_message(group, user) - "Are you sure you want to remove \"#{user.name}\" from \"#{group.name}\"?" + 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 cancel invitation for \"#{member.invite_email}\" to join \"#{group.name}\"?" + end end def leave_group_message(group) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index ebbd2bfd77d..06e5d3b7383 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -1,6 +1,10 @@ module ProjectsHelper - def remove_from_project_team_message(project, user) - "You are going to remove #{user.name} from #{project.name} project team. Are you sure?" + def remove_from_project_team_message(project, member) + if member.user + "You are going to remove #{member.user.name} from #{project.name} project team. Are you sure?" + else + "You are going to cancel invitation for #{member.invite_email} to join #{project.name} project team. Are you sure?" + end end def link_to_project(project) diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 7d292118075..404b918c245 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -74,13 +74,18 @@ %ul.well-list.group-users-list - @members.each do |member| - user = member.user - %li{class: dom_class(member), id: dom_id(user)} + %li{class: dom_class(member), id: (dom_id(user) if user)} .list-item-name - %strong - = link_to user.name, admin_user_path(user) + - if user + %strong + = link_to user.name, admin_user_path(user) + - else + %strong + = member.invite_email + (invited) %span.pull-right.light = member.human_access - = 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 + = link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do %i.fa.fa-minus.fa-inverse .panel-footer = paginate @members, param_name: 'members_page', theme: 'gitlab' diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index be31551dc96..78684c692c7 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -124,14 +124,19 @@ - user = project_member.user %li.project_member .list-item-name - %strong - = link_to user.name, admin_user_path(user) + - if user + %strong + = link_to user.name, admin_user_path(user) + - else + %strong + = project_member.invite_email + (invited) .pull-right - if project_member.owner? %span.light Owner - else %span.light= project_member.human_access - = link_to namespace_project_project_member_path(@project.namespace, @project, project_member), 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, project_member), data: { confirm: remove_from_project_team_message(@project, project_member)}, 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' diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 0a2934d3bda..3524f04c5ed 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -182,7 +182,7 @@ .pull-right %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 + = link_to group_group_member_path(group, group_member), data: { confirm: remove_user_from_group_message(group, group_member) }, 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. @@ -221,7 +221,7 @@ %span.light= member.human_access - 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 + = link_to namespace_project_project_member_path(project.namespace, project, member), data: { confirm: remove_from_project_team_message(project, member) }, 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 diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml index 2462c952090..670d5e02e61 100644 --- a/app/views/groups/group_members/_group_member.html.haml +++ b/app/views/groups/group_members/_group_member.html.haml @@ -1,17 +1,28 @@ - user = member.user -- return unless user +- return unless user || member.invite? - 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", alt: '' - %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 member.user + = image_tag avatar_icon(user.email, 16), class: "avatar s16", alt: '' + %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 + - else + = image_tag avatar_icon(member.invite_email, 16), class: "avatar s16", alt: '' + %strong + = member.invite_email + %span.cgray + invited + - if member.created_by + by + = link_to member.created_by.name, user_path(member.created_by) + = time_ago_with_tooltip(member.created_at) - if show_roles %span.pull-right @@ -27,7 +38,7 @@ = 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 + = link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do %i.fa.fa-minus.fa-inverse .edit-member.hide.js-toggle-content diff --git a/app/views/projects/project_members/_project_member.html.haml b/app/views/projects/project_members/_project_member.html.haml index 67d703a4121..4be531deddd 100644 --- a/app/views/projects/project_members/_project_member.html.haml +++ b/app/views/projects/project_members/_project_member.html.haml @@ -1,16 +1,28 @@ - user = member.user -- return unless user +- return unless user || member.invite? %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", alt: '' - %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 member.user + = image_tag avatar_icon(user.email, 16), class: "avatar s16", alt: '' + %strong + = link_to user.name, user_path(user) + %span.cgray= user.username + - if user == current_user + %span.label.label-success It's you + - if user.blocked? + %label.label.label-danger + %strong Blocked + - else + = image_tag avatar_icon(member.invite_email, 16), class: "avatar s16", alt: '' + %strong + = member.invite_email + %span.cgray + invited + - if member.created_by + by + = link_to member.created_by.name, user_path(member.created_by) + = time_ago_with_tooltip(member.created_at) - if current_user_can_admin_project - unless @project.personal? && user == current_user @@ -25,7 +37,7 @@ = 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, member), 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 + = link_to namespace_project_project_member_path(@project.namespace, @project, member), data: { confirm: remove_from_project_team_message(@project, member) }, 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 -- cgit v1.2.1 From 90dafe31c4b1bb54bcd0476a873c4f5cdb62e981 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:14:59 +0200 Subject: Only show invited users to people who can admin group. --- app/controllers/groups/group_members_controller.rb | 1 + app/controllers/projects/project_members_controller.rb | 2 ++ 2 files changed, 3 insertions(+) (limited to 'app') diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 93fc4edb3bb..f8aa4b0bbd5 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -11,6 +11,7 @@ class Groups::GroupMembersController < Groups::ApplicationController 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) if params[:search].present? users = @group.users.search(params[:search]).to_a diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 99ee3ebf92e..148768e8fa1 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -6,6 +6,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController def index @project_members = @project.project_members + @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) if params[:search].present? users = @project.users.search(params[:search]).to_a @@ -17,6 +18,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController @group = @project.group if @group @group_members = @group.group_members + @group_members = @group_members.non_invite unless can?(current_user, :admin_group, @group) if params[:search].present? users = @group.users.search(params[:search]).to_a -- cgit v1.2.1 From 39f389ae0fff5706b73b03c8fb5fc4e3dd7da638 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:22:31 +0200 Subject: Add invites controller. --- app/controllers/confirmations_controller.rb | 4 +- app/controllers/invites_controller.rb | 57 ++++++++++++++++++++++ app/models/member.rb | 7 +++ app/views/invites/show.html.haml | 28 +++++++++++ .../notify/group_invite_accepted_email.html.haml | 7 +++ .../notify/group_invite_accepted_email.text.erb | 3 ++ .../notify/group_member_invited_email.html.haml | 12 +++++ .../notify/group_member_invited_email.text.erb | 3 ++ .../notify/project_invite_accepted_email.html.haml | 7 +++ .../notify/project_invite_accepted_email.text.erb | 3 ++ .../notify/project_member_invited_email.html.haml | 11 +++++ .../notify/project_member_invited_email.text.erb | 3 ++ 12 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 app/controllers/invites_controller.rb create mode 100644 app/views/invites/show.html.haml create mode 100644 app/views/notify/group_invite_accepted_email.html.haml create mode 100644 app/views/notify/group_invite_accepted_email.text.erb create mode 100644 app/views/notify/group_member_invited_email.html.haml create mode 100644 app/views/notify/group_member_invited_email.text.erb create mode 100644 app/views/notify/project_invite_accepted_email.html.haml create mode 100644 app/views/notify/project_invite_accepted_email.text.erb create mode 100644 app/views/notify/project_member_invited_email.html.haml create mode 100644 app/views/notify/project_member_invited_email.text.erb (limited to 'app') diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index bc98eab133c..af1faca93f6 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -4,11 +4,11 @@ class ConfirmationsController < Devise::ConfirmationsController def after_confirmation_path_for(resource_name, resource) if signed_in?(resource_name) - signed_in_root_path(resource) + after_sign_in_path_for(resource) else sign_in(resource) if signed_in?(resource_name) - signed_in_root_path(resource) + after_sign_in_path_for(resource) else new_session_path(resource_name) end diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb new file mode 100644 index 00000000000..8b1f6eeba1b --- /dev/null +++ b/app/controllers/invites_controller.rb @@ -0,0 +1,57 @@ +class InvitesController < ApplicationController + before_filter :member + + respond_to :html + + layout 'navless' + + def show + + end + + def accept + if member.accept_invite!(current_user) + case member.source + when Project + project = member.source + source = "project #{project.name_with_namespace}" + path = namespace_project_path(project.namespace, project) + when Group + group = member.source + source = "group #{group.name}" + path = group_path(group) + else + source = "who knows what" + path = dashboard_path + end + + redirect_to path, notice: "You have been granted #{member.human_access} access to #{source}." + else + redirect_to :back, alert: "The invite could not be accepted." + end + end + + private + + def member + return @member if defined?(@member) + + @token = params[:id] + if member = Member.find_by_invite_token(@token) + @member = member + else + render_404 + end + end + + def authenticate_user! + return if current_user + + notice = "To accept this invitation, sign in" + notice << " or create an account" if current_application_settings.signup_enabled? + notice << "." + + store_location_for :user, request.fullpath + redirect_to new_user_session_path, notice: notice + end +end diff --git a/app/models/member.rb b/app/models/member.rb index ec79f531740..d8cc65ca6cb 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -52,11 +52,18 @@ class Member < ActiveRecord::Base delegate :name, :username, :email, to: :user, prefix: true + def self.find_by_invite_token(invite_token) + invite_token = Devise.token_generator.digest(self, :invite_token, invite_token) + find_by(invite_token: invite_token) + end + def invite? self.invite_token.present? end def accept_invite!(new_user) + return false unless invite? + self.invite_token = nil self.invite_accepted_at = Time.now.utc diff --git a/app/views/invites/show.html.haml b/app/views/invites/show.html.haml new file mode 100644 index 00000000000..e2657ac6df2 --- /dev/null +++ b/app/views/invites/show.html.haml @@ -0,0 +1,28 @@ +%h3.page-title Invitation + +%p + You have been invited + - if inviter = @member.created_by + by + = link_to inviter.name, user_url(inviter) + to join + - case @member.source + - when Project + - project = @member.source + project + %strong + = link_to project.name_with_namespace, namespace_project_url(project.namespace, project) + - when Group + - group = @member.source + group + %strong + = link_to group.name, group_url(group) + as #{@member.human_access}. + +- if @member.source.users.include?(current_user) + %p + However, you are already a member of this #{@member.source.is_a?(Group) ? "group" : "project"}. + Sign in using a different account to accept the invitation. +- else + .actions + = link_to "Accept invitation", accept_invite_url(@token), method: :post, class: "btn btn-success" diff --git a/app/views/notify/group_invite_accepted_email.html.haml b/app/views/notify/group_invite_accepted_email.html.haml new file mode 100644 index 00000000000..d50d182102b --- /dev/null +++ b/app/views/notify/group_invite_accepted_email.html.haml @@ -0,0 +1,7 @@ +%p + #{@group_member.invite_email}, now known as + #{link_to @group_member.user.name, user_url(@group_member.user)}, + has accepted your invitation to join group + = link_to @group.name, group_url(@group) + as #{@group_member.human_access}. + diff --git a/app/views/notify/group_invite_accepted_email.text.erb b/app/views/notify/group_invite_accepted_email.text.erb new file mode 100644 index 00000000000..0072f5252da --- /dev/null +++ b/app/views/notify/group_invite_accepted_email.text.erb @@ -0,0 +1,3 @@ +<%= @group_member.invite_email %>, now known as <%= @group_member.user.name %>, has accepted your invitation to join group <%= @group.name %> as <%= @group_member.human_access %>. + +<%= group_url(@group) %> diff --git a/app/views/notify/group_member_invited_email.html.haml b/app/views/notify/group_member_invited_email.html.haml new file mode 100644 index 00000000000..39798a2c0e6 --- /dev/null +++ b/app/views/notify/group_member_invited_email.html.haml @@ -0,0 +1,12 @@ +%p + You have been invited + - if inviter = @group_member.created_by + by + = link_to inviter.name, user_url(inviter) + to join group + = link_to @group.name, group_url(@group) + as #{@group_member.human_access}. + +%p + = link_to 'Accept invitation', invite_url(@token) + diff --git a/app/views/notify/group_member_invited_email.text.erb b/app/views/notify/group_member_invited_email.text.erb new file mode 100644 index 00000000000..dec0cf0d01e --- /dev/null +++ b/app/views/notify/group_member_invited_email.text.erb @@ -0,0 +1,3 @@ +You have been invited <%= "by #{@group_member.created_by.name} " if @group_member.created_by %>to join group <%= @group.name %> as <%= @group_member.human_access %>. + +Accept invitation: <%= invite_url(@token) %> diff --git a/app/views/notify/project_invite_accepted_email.html.haml b/app/views/notify/project_invite_accepted_email.html.haml new file mode 100644 index 00000000000..0c01eef7621 --- /dev/null +++ b/app/views/notify/project_invite_accepted_email.html.haml @@ -0,0 +1,7 @@ +%p + #{@project_member.invite_email}, now known as + #{link_to @project_member.user.name, user_url(@project_member.user)}, + has accepted your invitation to join project + = link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project) + as #{@project_member.human_access}. + diff --git a/app/views/notify/project_invite_accepted_email.text.erb b/app/views/notify/project_invite_accepted_email.text.erb new file mode 100644 index 00000000000..e90217c1ab2 --- /dev/null +++ b/app/views/notify/project_invite_accepted_email.text.erb @@ -0,0 +1,3 @@ +<%= @project_member.invite_email %>, now known as <%= @project_member.user.name %>, has accepted your invitation to join project <%= @group.name_with_namespace %> as <%= @project_member.human_access %>. + +<%= namespace_project_url(@project.namespace, @project) %> diff --git a/app/views/notify/project_member_invited_email.html.haml b/app/views/notify/project_member_invited_email.html.haml new file mode 100644 index 00000000000..f44adc244c9 --- /dev/null +++ b/app/views/notify/project_member_invited_email.html.haml @@ -0,0 +1,11 @@ +%p + You have been invited + - if inviter = @project_member.created_by + by + = link_to inviter.name, user_url(inviter) + to join project + = link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project) + as #{@project_member.human_access}. + +%p + = link_to 'Accept invitation', invite_url(@token) diff --git a/app/views/notify/project_member_invited_email.text.erb b/app/views/notify/project_member_invited_email.text.erb new file mode 100644 index 00000000000..55b16ef6c56 --- /dev/null +++ b/app/views/notify/project_member_invited_email.text.erb @@ -0,0 +1,3 @@ +You have been invited <%= "by #{@project_member.created_by.name} " if @project_member.created_by %>to join project <%= @project.name_with_namespace %> as <%= @project_member.human_access %>. + +Accept invitation: <%= invite_url(@token) %> -- cgit v1.2.1 From 717fa136a5146d45660d3d97f5671352a47a0601 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:23:38 +0200 Subject: Add emails around invitation. --- app/mailers/emails/groups.rb | 21 ++++++++++++++++++++- app/mailers/emails/projects.rb | 25 ++++++++++++++++++++++--- app/models/members/group_member.rb | 12 ++++++++++++ app/models/members/project_member.rb | 12 ++++++++++++ app/services/notification_service.rb | 16 ++++++++++++++++ 5 files changed, 82 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/mailers/emails/groups.rb b/app/mailers/emails/groups.rb index 626eb593d51..9db609006e0 100644 --- a/app/mailers/emails/groups.rb +++ b/app/mailers/emails/groups.rb @@ -5,8 +5,27 @@ module Emails @group = @group_member.group @target_url = group_url(@group) @current_user = @group_member.user - mail(to: @group_member.user.email, + mail(to: @group_member.user.notification_email, subject: subject("Access to group was granted")) end + + def group_member_invited_email(group_member_id, token) + @group_member = GroupMember.find group_member_id + @group = @group_member.group + @token = token + @target_url = group_url(@group) + mail(to: @group_member.invite_email, + subject: "Invite to join group #{@group.name}") + end + + def group_invite_accepted_email(group_member_id) + @group_member = GroupMember.find group_member_id + return if @group_member.created_by.nil? + + @group = @group_member.group + @target_url = group_url(@group) + mail(to: @group_member.created_by.notification_email, + subject: subject("Invite accepted")) + end end end diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 20a863c3742..64c35618a52 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -1,14 +1,33 @@ module Emails module Projects - def project_access_granted_email(user_project_id) - @project_member = ProjectMember.find user_project_id + def project_access_granted_email(project_member_id) + @project_member = ProjectMember.find project_member_id @project = @project_member.project @target_url = namespace_project_url(@project.namespace, @project) @current_user = @project_member.user - mail(to: @project_member.user.email, + mail(to: @project_member.user.notification_email, subject: subject("Access to project was granted")) end + def project_member_invited_email(project_member_id, token) + @project_member = ProjectMember.find project_member_id + @project = @project_member.project + @token = token + @target_url = namespace_project_url(@project.namespace, @project) + mail(to: @project_member.invite_email, + subject: "Invite to join project #{@project.name_with_namespace}") + end + + def project_invite_accepted_email(project_member_id) + @project_member = ProjectMember.find project_member_id + return if @project_member.created_by.nil? + + @project = @project_member.project + @target_url = namespace_project_url(@project.namespace, @project) + mail(to: @project_member.created_by.notification_email, + subject: subject("Invite accepted")) + end + def project_was_moved_email(project_id, user_id) @current_user = @user = User.find user_id @project = Project.find project_id diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index ccbbab6afc5..68b7c169f72 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -41,6 +41,12 @@ class GroupMember < Member private + def send_invite + notification_service.invite_group_member(self, @raw_invite_token) + + super + end + def post_create_hook notification_service.new_group_member(self) @@ -54,4 +60,10 @@ class GroupMember < Member super end + + def after_accept_invite + notification_service.accept_group_invite(self) + + super + end end diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 6c5d161940d..a63d5af1219 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -116,6 +116,12 @@ class ProjectMember < Member private + def send_invite + notification_service.invite_project_member(self, @raw_invite_token) + + super + end + def post_create_hook unless owner? event_service.join_project(self.project, self.user) @@ -139,6 +145,12 @@ class ProjectMember < Member super end + def after_accept_invite + notification_service.accept_project_invite(self) + + super + end + def event_service EventCreateService.new end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 42547f6f481..a97abe289f5 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -165,6 +165,14 @@ class NotificationService end end + def invite_project_member(project_member, token) + mailer.project_member_invited_email(project_member.id, token) + end + + def accept_project_invite(project_member) + mailer.project_invite_accepted_email(project_member.id) + end + def new_project_member(project_member) mailer.project_access_granted_email(project_member.id) end @@ -173,6 +181,14 @@ class NotificationService mailer.project_access_granted_email(project_member.id) end + def invite_group_member(group_member, token) + mailer.group_member_invited_email(group_member.id, token) + end + + def accept_group_invite(group_member) + mailer.group_invite_accepted_email(group_member.id) + end + def new_group_member(group_member) mailer.group_access_granted_email(group_member.id) end -- cgit v1.2.1 From 87dd3f215f8c087d85cde7ac880c5480fd501303 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:25:32 +0200 Subject: Let members be invited from Add members pane. --- app/assets/javascripts/users_select.js.coffee | 38 ++++++++++++++-------- .../projects/project_members_controller.rb | 3 +- app/helpers/selects_helper.rb | 2 ++ app/models/group.rb | 20 ++++++++++-- app/models/members/project_member.rb | 22 +++++++++++-- app/views/admin/groups/show.html.haml | 2 +- .../group_members/_new_group_member.html.haml | 5 ++- .../project_members/_new_project_member.html.haml | 5 ++- 8 files changed, 72 insertions(+), 25 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index ccd85f2455d..aeeed9ca3cc 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -8,6 +8,7 @@ class @UsersSelect @groupId = $(select).data('group-id') showNullUser = $(select).data('null-user') showAnyUser = $(select).data('any-user') + showEmailUser = $(select).data('email-user') firstUser = $(select).data('first-user') $(select).select2 @@ -19,20 +20,6 @@ class @UsersSelect data = { results: users } if query.term.length == 0 - anyUser = { - name: 'Any', - avatar: null, - username: 'none', - id: null - } - - nullUser = { - name: 'Unassigned', - avatar: null, - username: 'none', - id: 0 - } - if firstUser # Move current user to the front of the list for obj, index in data.results @@ -40,11 +27,34 @@ class @UsersSelect data.results.splice(index, 1) data.results.unshift(obj) break + if showNullUser + nullUser = { + name: 'Unassigned', + avatar: null, + username: 'none', + id: 0 + } data.results.unshift(nullUser) + if showAnyUser + anyUser = { + name: 'Any', + avatar: null, + username: 'none', + id: null + } data.results.unshift(anyUser) + if showEmailUser && data.results.length == 0 && query.term.match(/^[^@]+@[^@]+$/) + emailUser = { + name: "Invite \"#{query.term}\"", + avatar: null, + username: query.term, + id: query.term + } + data.results.unshift(emailUser) + query.callback(data) initSelection: (element, callback) => diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 148768e8fa1..91aba9a7068 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -36,8 +36,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController end def create - users = User.where(id: params[:user_ids].split(',')) - @project.team << [users, params[:access_level]] + @project.team.add_users(params[:user_ids].split(','), params[:access_level], current_user) redirect_to namespace_project_project_members_path(@project.namespace, @project) end diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb index 54e0f4f9b3e..bec8f2f1aa7 100644 --- a/app/helpers/selects_helper.rb +++ b/app/helpers/selects_helper.rb @@ -8,6 +8,7 @@ module SelectsHelper null_user = opts[:null_user] || false any_user = opts[:any_user] || false + email_user = opts[:email_user] || false first_user = opts[:first_user] && current_user ? current_user.username : false html = { @@ -15,6 +16,7 @@ module SelectsHelper 'data-placeholder' => placeholder, 'data-null-user' => null_user, 'data-any-user' => any_user, + 'data-email-user' => email_user, 'data-first-user' => first_user } diff --git a/app/models/group.rb b/app/models/group.rb index eec961f6012..2de397f90f7 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -47,10 +47,24 @@ class Group < Namespace end def add_users(user_ids, access_level, current_user = nil) - user_ids.compact.each do |user_id| - member = self.group_members.find_or_initialize_by(user_id: user_id) - member.access_level = access_level + users = user_ids.map do |user_id| + (user_id if user_id.is_a?(User)) || + User.find_by(id: user_id) || + User.find_by(email: user_id) || + user_id + end + + users.compact.each do |user| + if user.is_a?(User) + member = self.group_members.find_or_initialize_by(user_id: user.id) + else + member = self.group_members.build + member.invite_email = user + end + member.created_by ||= current_user + member.access_level = access_level + member.save end end diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index a63d5af1219..3b3b1bd4680 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -60,12 +60,28 @@ class ProjectMember < Member raise "Non valid access" end + users = user_ids.map do |user_id| + (user_id if user_id.is_a?(User)) || + User.find_by(id: user_id) || + User.find_by(email: user_id) || + user_id + end + ProjectMember.transaction do project_ids.each do |project_id| - user_ids.each do |user_id| - member = ProjectMember.new(access_level: access_level, user_id: user_id) - member.source_id = project_id + project = Project.find(project_id) + + users.each do |user| + if user.is_a?(User) + member = project.project_members.find_or_initialize_by(user_id: user.id) + else + member = project.project_members.build + member.invite_email = user + end + member.created_by ||= current_user + member.access_level = access_level + member.save end end diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 404b918c245..14996dcd6a2 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -60,7 +60,7 @@ = 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) + = users_select_tag(:user_ids, multiple: true, email_user: true) %div.prepend-top-10 = select_tag :access_level, options_for_select(GroupMember.access_level_roles), class: "project-access-select select2" %hr diff --git a/app/views/groups/group_members/_new_group_member.html.haml b/app/views/groups/group_members/_new_group_member.html.haml index a52b8197384..3361d7e2a8d 100644 --- a/app/views/groups/group_members/_new_group_member.html.haml +++ b/app/views/groups/group_members/_new_group_member.html.haml @@ -1,7 +1,10 @@ = 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', scope: :all) + .col-sm-10 + = users_select_tag(:user_ids, multiple: true, class: 'input-large', scope: :all, email_user: true) + .help-block + Search for existing users or invite new ones using their email address. .form-group = f.label :access_level, "Group Access", class: 'control-label' diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index 5daae2708e6..d708b01a114 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -1,7 +1,10 @@ = 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', scope: :all) + .col-sm-10 + = users_select_tag(:user_ids, multiple: true, class: 'input-large', scope: :all, email_user: true) + .help-block + Search for existing users or invite new ones using their email address. .form-group = f.label :access_level, "Project Access", class: 'control-label' -- cgit v1.2.1 From 453340d4496ce0500985d6432c32e8d31be350a7 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:26:03 +0200 Subject: Let membership invitations be resent. --- app/controllers/groups/group_members_controller.rb | 11 +++++++++++ app/controllers/projects/project_members_controller.rb | 13 +++++++++++++ app/views/groups/group_members/_group_member.html.haml | 4 ++++ .../projects/project_members/_project_member.html.haml | 4 ++++ 4 files changed, 32 insertions(+) (limited to 'app') diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index f8aa4b0bbd5..1a4b13b9d73 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -47,6 +47,17 @@ class Groups::GroupMembersController < Groups::ApplicationController end end + def resend_invite + @group_member = @group.group_members.find(params[:id]) + if @group_member.invite? + @group_member.resend_invite + + redirect_to group_group_members_path(@group), notice: 'Invite was successfully resent.' + else + redirect_to group_group_members_path(@group), alert: 'The invite has already been accepted.' + end + end + def leave @group_member = @group.group_members.where(user_id: current_user.id).first diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 91aba9a7068..e55e8e4c504 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -59,6 +59,19 @@ class Projects::ProjectMembersController < Projects::ApplicationController end end + def resend_invite + @project_member = @project.project_members.find(params[:id]) + if @project_member.invite? + @project_member.resend_invite + + redirect_to namespace_project_project_members_path(@project.namespace, + @project), notice: 'Invite was successfully resent.' + else + redirect_to namespace_project_project_members_path(@project.namespace, + @project), alert: 'The invite has already been accepted.' + end + end + def leave @project.project_members.find_by(user_id: current_user).destroy diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml index 670d5e02e61..56b1948a474 100644 --- a/app/views/groups/group_members/_group_member.html.haml +++ b/app/views/groups/group_members/_group_member.html.haml @@ -24,6 +24,10 @@ = link_to member.created_by.name, user_path(member.created_by) = time_ago_with_tooltip(member.created_at) + - if show_controls && can?(current_user, :admin_group, @group) + = link_to resend_invite_group_group_member_path(@group, member), method: :post, class: "btn-xs btn", title: 'Resend invite' do + Resend invite + - if show_roles %span.pull-right %strong= member.human_access diff --git a/app/views/projects/project_members/_project_member.html.haml b/app/views/projects/project_members/_project_member.html.haml index 4be531deddd..635e4d70941 100644 --- a/app/views/projects/project_members/_project_member.html.haml +++ b/app/views/projects/project_members/_project_member.html.haml @@ -24,6 +24,10 @@ = link_to member.created_by.name, user_path(member.created_by) = time_ago_with_tooltip(member.created_at) + - if current_user_can_admin_project + = link_to resend_invite_namespace_project_project_member_path(@project.namespace, @project, member), method: :post, class: "btn-xs btn", title: 'Resend invite' do + Resend invite + - if current_user_can_admin_project - unless @project.personal? && user == current_user .pull-right -- cgit v1.2.1 From 2a45eb6a912a35b71e3cbe7aacbda3323730d9da Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:26:18 +0200 Subject: Use notice flash type rather than nonexistent info. --- app/controllers/groups/group_members_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 1a4b13b9d73..0018cd34bbe 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -39,7 +39,7 @@ class Groups::GroupMembersController < Groups::ApplicationController 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 group_group_members_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 @@ -63,7 +63,7 @@ class Groups::GroupMembersController < Groups::ApplicationController if can?(current_user, :destroy_group_member, @group_member) @group_member.destroy - redirect_to(dashboard_groups_path, info: "You left #{group.name} group.") + redirect_to(dashboard_groups_path, notice: "You left #{group.name} group.") else return render_403 end -- cgit v1.2.1 From 1c0824f451a3fe8f328f0360c94cd251ff664ed6 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:26:53 +0200 Subject: Correctly import invited members. --- app/models/project_team.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/models/project_team.rb b/app/models/project_team.rb index 313e459d701..56e49af2324 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -93,7 +93,7 @@ class ProjectTeam source_members.reject! do |member| # Skip if user already present in team - target_user_ids.include?(member.user_id) + !member.invite? && target_user_ids.include?(member.user_id) end source_members.map! do |member| -- cgit v1.2.1 From 405df435587c674dda049868cb2009b00c243dd8 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 15:27:06 +0200 Subject: Use "Sign out" instead of "Logout" for consistency. --- app/views/layouts/_head_panel.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index b1c2e1a7b19..d58582c107a 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -39,7 +39,7 @@ = link_to profile_path, title: "Profile settings", class: 'has_bottom_tooltip', 'data-original-title' => 'Profile settings"' do %i.fa.fa-user %li - = link_to destroy_user_session_path, class: "logout", method: :delete, title: "Logout", class: 'has_bottom_tooltip', 'data-original-title' => 'Logout' do + = link_to destroy_user_session_path, class: "logout", method: :delete, title: "Sign out", class: 'has_bottom_tooltip', 'data-original-title' => 'Sign out' do %i.fa.fa-sign-out %li.hidden-xs = link_to current_user, class: "profile-pic has_bottom_tooltip", id: 'profile-pic', 'data-original-title' => 'Your profile' do -- cgit v1.2.1 From e50556fcc8d81dae5978bcb3e1dd5104789aab0f Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 10 Apr 2015 16:37:02 +0200 Subject: Let invites be declined. --- app/controllers/invites_controller.rb | 27 ++++++++++++++++++++++ app/mailers/emails/groups.rb | 13 +++++++++++ app/mailers/emails/projects.rb | 13 +++++++++++ app/models/member.rb | 14 +++++++++++ app/models/members/group_member.rb | 6 +++++ app/models/members/project_member.rb | 6 +++++ app/services/notification_service.rb | 8 +++++++ app/views/invites/show.html.haml | 1 + .../notify/group_invite_declined_email.html.haml | 6 +++++ .../notify/group_invite_declined_email.text.erb | 3 +++ .../notify/group_member_invited_email.html.haml | 2 ++ .../notify/group_member_invited_email.text.erb | 1 + .../notify/project_invite_accepted_email.text.erb | 2 +- .../notify/project_invite_declined_email.html.haml | 6 +++++ .../notify/project_invite_declined_email.text.erb | 3 +++ .../notify/project_member_invited_email.html.haml | 2 ++ .../notify/project_member_invited_email.text.erb | 1 + 17 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 app/views/notify/group_invite_declined_email.html.haml create mode 100644 app/views/notify/group_invite_declined_email.text.erb create mode 100644 app/views/notify/project_invite_declined_email.html.haml create mode 100644 app/views/notify/project_invite_declined_email.text.erb (limited to 'app') diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 8b1f6eeba1b..1b236a48e90 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -1,5 +1,6 @@ class InvitesController < ApplicationController before_filter :member + skip_before_filter :authenticate_user!, only: :decline respond_to :html @@ -31,6 +32,32 @@ class InvitesController < ApplicationController end end + def decline + if member.decline_invite! + case member.source + when Project + project = member.source + source = "project #{project.name_with_namespace}" + when Group + group = member.source + source = "group #{group.name}" + else + source = "who knows what" + end + + path = + if current_user + dashboard_path + else + new_user_session_path + end + + redirect_to path, notice: "You have declined the invite to join #{source}." + else + redirect_to :back, alert: "The invite could not be declined." + end + end + private def member diff --git a/app/mailers/emails/groups.rb b/app/mailers/emails/groups.rb index 9db609006e0..f3da3990c5f 100644 --- a/app/mailers/emails/groups.rb +++ b/app/mailers/emails/groups.rb @@ -27,5 +27,18 @@ module Emails mail(to: @group_member.created_by.notification_email, subject: subject("Invite accepted")) end + + def group_invite_declined_email(group_id, invite_email, access_level, created_by_id) + return if created_by_id.nil? + + @group = Group.find(group_id) + @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("Invite declined")) + end end end diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 64c35618a52..bbfb7a3e409 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -28,6 +28,19 @@ module Emails subject: subject("Invite accepted")) end + def project_invite_declined_email(project_id, invite_email, access_level, created_by_id) + return if created_by_id.nil? + + @project = Project.find(project_id) + @created_by = User.find(created_by_id) + @access_level = access_level + @invite_email = invite_email + @target_url = namespace_project_url(@project.namespace, @project) + + mail(to: @created_by.notification_email, + subject: subject("Invite declined")) + end + def project_was_moved_email(project_id, user_id) @current_user = @user = User.find user_id @project = Project.find project_id diff --git a/app/models/member.rb b/app/models/member.rb index d8cc65ca6cb..2421222eaa2 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -76,6 +76,16 @@ class Member < ActiveRecord::Base saved end + def decline_invite! + return false unless invite? + + destroyed = self.destroy + + after_decline_invite if destroyed + + destroyed + end + def generate_invite_token raw, enc = Devise.token_generator.generate(self.class, :invite_token) @raw_invite_token = raw @@ -116,6 +126,10 @@ class Member < ActiveRecord::Base post_create_hook end + def after_decline_invite + # override in subclass + end + def system_hook_service SystemHooksService.new end diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index 68b7c169f72..84c91372b3f 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -66,4 +66,10 @@ class GroupMember < Member super end + + def after_decline_invite + notification_service.decline_group_invite(self) + + super + end end diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 3b3b1bd4680..8af7499dd82 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -167,6 +167,12 @@ class ProjectMember < Member super end + def after_decline_invite + notification_service.decline_project_invite(self) + + super + end + def event_service EventCreateService.new end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index a97abe289f5..203e654c18f 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -173,6 +173,10 @@ class NotificationService mailer.project_invite_accepted_email(project_member.id) end + def decline_project_invite(project_member) + mailer.project_invite_declined_email(project_member.project.id, project_member.invite_email, project_member.access_level, project_member.created_by_id) + end + def new_project_member(project_member) mailer.project_access_granted_email(project_member.id) end @@ -189,6 +193,10 @@ class NotificationService mailer.group_invite_accepted_email(group_member.id) end + def decline_group_invite(group_member) + mailer.group_invite_declined_email(group_member.group.id, group_member.invite_email, group_member.access_level, group_member.created_by_id) + end + def new_group_member(group_member) mailer.group_access_granted_email(group_member.id) end diff --git a/app/views/invites/show.html.haml b/app/views/invites/show.html.haml index e2657ac6df2..ab0ecffe4d2 100644 --- a/app/views/invites/show.html.haml +++ b/app/views/invites/show.html.haml @@ -26,3 +26,4 @@ - else .actions = link_to "Accept invitation", accept_invite_url(@token), method: :post, class: "btn btn-success" + = link_to "Decline", decline_invite_url(@token), method: :post, class: "btn btn-danger prepend-left-10" diff --git a/app/views/notify/group_invite_declined_email.html.haml b/app/views/notify/group_invite_declined_email.html.haml new file mode 100644 index 00000000000..80f39c3f1ea --- /dev/null +++ b/app/views/notify/group_invite_declined_email.html.haml @@ -0,0 +1,6 @@ +%p + #{@invite_email} + has declined your invitation to join group + = link_to @group.name, group_url(@group) + as #{Gitlab::Access.options_with_owner.key(@access_level)}. + diff --git a/app/views/notify/group_invite_declined_email.text.erb b/app/views/notify/group_invite_declined_email.text.erb new file mode 100644 index 00000000000..31cdac0e7fb --- /dev/null +++ b/app/views/notify/group_invite_declined_email.text.erb @@ -0,0 +1,3 @@ +<%= @invite_email %> has declined your invitation to join group <%= @group.name %> as <%= Gitlab::Access.options_with_owner.key(@access_level) %>. + +<%= group_url(@group) %> diff --git a/app/views/notify/group_member_invited_email.html.haml b/app/views/notify/group_member_invited_email.html.haml index 39798a2c0e6..163e88bfea3 100644 --- a/app/views/notify/group_member_invited_email.html.haml +++ b/app/views/notify/group_member_invited_email.html.haml @@ -9,4 +9,6 @@ %p = link_to 'Accept invitation', invite_url(@token) + or + = link_to 'decline', decline_invite_url(@token) diff --git a/app/views/notify/group_member_invited_email.text.erb b/app/views/notify/group_member_invited_email.text.erb index dec0cf0d01e..28ce4819b14 100644 --- a/app/views/notify/group_member_invited_email.text.erb +++ b/app/views/notify/group_member_invited_email.text.erb @@ -1,3 +1,4 @@ You have been invited <%= "by #{@group_member.created_by.name} " if @group_member.created_by %>to join group <%= @group.name %> as <%= @group_member.human_access %>. Accept invitation: <%= invite_url(@token) %> +Decline invitation: <%= decline_invite_url(@token) %> diff --git a/app/views/notify/project_invite_accepted_email.text.erb b/app/views/notify/project_invite_accepted_email.text.erb index e90217c1ab2..0bbe274931e 100644 --- a/app/views/notify/project_invite_accepted_email.text.erb +++ b/app/views/notify/project_invite_accepted_email.text.erb @@ -1,3 +1,3 @@ -<%= @project_member.invite_email %>, now known as <%= @project_member.user.name %>, has accepted your invitation to join project <%= @group.name_with_namespace %> as <%= @project_member.human_access %>. +<%= @project_member.invite_email %>, now known as <%= @project_member.user.name %>, has accepted your invitation to join project <%= @project.name_with_namespace %> as <%= @project_member.human_access %>. <%= namespace_project_url(@project.namespace, @project) %> diff --git a/app/views/notify/project_invite_declined_email.html.haml b/app/views/notify/project_invite_declined_email.html.haml new file mode 100644 index 00000000000..dad9f505b9e --- /dev/null +++ b/app/views/notify/project_invite_declined_email.html.haml @@ -0,0 +1,6 @@ +%p + #{@invite_email} + has declined your invitation to join project + = link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project) + as #{Gitlab::Access.options_with_owner.key(@access_level)}. + diff --git a/app/views/notify/project_invite_declined_email.text.erb b/app/views/notify/project_invite_declined_email.text.erb new file mode 100644 index 00000000000..06a0013cff5 --- /dev/null +++ b/app/views/notify/project_invite_declined_email.text.erb @@ -0,0 +1,3 @@ +<%= @invite_email %> has declined your invitation to join project <%= @project.name_with_namespace %> as <%= Gitlab::Access.options_with_owner.key(@access_level) %>. + +<%= namespace_project_url(@project.namespace, @project) %> diff --git a/app/views/notify/project_member_invited_email.html.haml b/app/views/notify/project_member_invited_email.html.haml index f44adc244c9..79eb89616de 100644 --- a/app/views/notify/project_member_invited_email.html.haml +++ b/app/views/notify/project_member_invited_email.html.haml @@ -9,3 +9,5 @@ %p = link_to 'Accept invitation', invite_url(@token) + or + = link_to 'decline', decline_invite_url(@token) diff --git a/app/views/notify/project_member_invited_email.text.erb b/app/views/notify/project_member_invited_email.text.erb index 55b16ef6c56..e0706272115 100644 --- a/app/views/notify/project_member_invited_email.text.erb +++ b/app/views/notify/project_member_invited_email.text.erb @@ -1,3 +1,4 @@ You have been invited <%= "by #{@project_member.created_by.name} " if @project_member.created_by %>to join project <%= @project.name_with_namespace %> as <%= @project_member.human_access %>. Accept invitation: <%= invite_url(@token) %> +Decline invitation: <%= decline_invite_url(@token) %> -- cgit v1.2.1 From 1b5c483d89d9a20a92e98fc37879389ee2c8dd00 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 12:25:16 +0200 Subject: Consistently use "invitation" rather than "invite" in text. --- app/controllers/groups/group_members_controller.rb | 4 ++-- app/controllers/invites_controller.rb | 6 +++--- app/controllers/projects/project_members_controller.rb | 8 ++++---- app/helpers/groups_helper.rb | 2 +- app/helpers/projects_helper.rb | 2 +- app/mailers/emails/groups.rb | 11 ++++++----- app/mailers/emails/projects.rb | 11 +++++++---- 7 files changed, 24 insertions(+), 20 deletions(-) (limited to 'app') diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 0018cd34bbe..359eeb4d27a 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -52,9 +52,9 @@ class Groups::GroupMembersController < Groups::ApplicationController if @group_member.invite? @group_member.resend_invite - redirect_to group_group_members_path(@group), notice: 'Invite was successfully resent.' + redirect_to group_group_members_path(@group), notice: 'The invitation was successfully resent.' else - redirect_to group_group_members_path(@group), alert: 'The invite has already been accepted.' + redirect_to group_group_members_path(@group), alert: 'The invitation has already been accepted.' end end diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 1b236a48e90..00d274a7f1d 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -28,7 +28,7 @@ class InvitesController < ApplicationController redirect_to path, notice: "You have been granted #{member.human_access} access to #{source}." else - redirect_to :back, alert: "The invite could not be accepted." + redirect_to :back, alert: "The invitation could not be accepted." end end @@ -52,9 +52,9 @@ class InvitesController < ApplicationController new_user_session_path end - redirect_to path, notice: "You have declined the invite to join #{source}." + redirect_to path, notice: "You have declined the invitation to join #{label}." else - redirect_to :back, alert: "The invite could not be declined." + redirect_to :back, alert: "The invitation could not be declined." end end diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index e55e8e4c504..9831a2089be 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -60,15 +60,15 @@ class Projects::ProjectMembersController < Projects::ApplicationController end def resend_invite + redirect_path = namespace_project_project_members_path(@project.namespace, @project) + @project_member = @project.project_members.find(params[:id]) if @project_member.invite? @project_member.resend_invite - redirect_to namespace_project_project_members_path(@project.namespace, - @project), notice: 'Invite was successfully resent.' + redirect_to redirect_path, notice: 'The invitation was successfully resent.' else - redirect_to namespace_project_project_members_path(@project.namespace, - @project), alert: 'The invite has already been accepted.' + redirect_to redirect_path, alert: 'The invitation has already been accepted.' end end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 52d88133d5e..add0a776a63 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -3,7 +3,7 @@ module GroupsHelper if member.user "Are you sure you want to remove \"#{member.user.name}\" from \"#{group.name}\"?" else - "Are you sure you want to cancel invitation for \"#{member.invite_email}\" to join \"#{group.name}\"?" + "Are you sure you want to revoke the invitation for \"#{member.invite_email}\" to join \"#{group.name}\"?" end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 06e5d3b7383..c2a7732e6f0 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -3,7 +3,7 @@ module ProjectsHelper if member.user "You are going to remove #{member.user.name} from #{project.name} project team. Are you sure?" else - "You are going to cancel invitation for #{member.invite_email} to join #{project.name} project team. Are you sure?" + "You are going to revoke the invitation for #{member.invite_email} to join #{project.name} project team. Are you sure?" end end diff --git a/app/mailers/emails/groups.rb b/app/mailers/emails/groups.rb index f3da3990c5f..07b8f6d735a 100644 --- a/app/mailers/emails/groups.rb +++ b/app/mailers/emails/groups.rb @@ -14,8 +14,9 @@ module Emails @group = @group_member.group @token = token @target_url = group_url(@group) + @current_user = @group_member.user mail(to: @group_member.invite_email, - subject: "Invite to join group #{@group.name}") + subject: "Invitation to join group #{@group.name}") end def group_invite_accepted_email(group_member_id) @@ -24,21 +25,21 @@ module Emails @group = @group_member.group @target_url = group_url(@group) + @current_user = @group_member.created_by mail(to: @group_member.created_by.notification_email, - subject: subject("Invite accepted")) + subject: subject("Invitation accepted")) end def group_invite_declined_email(group_id, invite_email, access_level, created_by_id) return if created_by_id.nil? @group = Group.find(group_id) - @created_by = User.find(created_by_id) + @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("Invite declined")) + subject: subject("Invitation declined")) end end end diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index bbfb7a3e409..7baeead3fb5 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -14,8 +14,9 @@ module Emails @project = @project_member.project @token = token @target_url = namespace_project_url(@project.namespace, @project) + @current_user = @project_member.user mail(to: @project_member.invite_email, - subject: "Invite to join project #{@project.name_with_namespace}") + subject: "Invitation to join project #{@project.name_with_namespace}") end def project_invite_accepted_email(project_member_id) @@ -24,21 +25,23 @@ module Emails @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, - subject: subject("Invite accepted")) + subject: subject("Invitation accepted")) end def project_invite_declined_email(project_id, invite_email, access_level, created_by_id) return if created_by_id.nil? @project = Project.find(project_id) - @created_by = User.find(created_by_id) + @current_user = @created_by = User.find(created_by_id) @access_level = access_level @invite_email = invite_email @target_url = namespace_project_url(@project.namespace, @project) mail(to: @created_by.notification_email, - subject: subject("Invite declined")) + subject: subject("Invitation declined")) end def project_was_moved_email(project_id, user_id) -- cgit v1.2.1 From 1c0b58a7994f2942799c5ccdbdd37a48aa034f97 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 12:25:38 +0200 Subject: Remove duplication from InvitesController. --- app/controllers/invites_controller.rb | 47 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'app') diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 00d274a7f1d..2a98fb0b48b 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -12,21 +12,9 @@ class InvitesController < ApplicationController def accept if member.accept_invite!(current_user) - case member.source - when Project - project = member.source - source = "project #{project.name_with_namespace}" - path = namespace_project_path(project.namespace, project) - when Group - group = member.source - source = "group #{group.name}" - path = group_path(group) - else - source = "who knows what" - path = dashboard_path - end - - redirect_to path, notice: "You have been granted #{member.human_access} access to #{source}." + label, path = source_info(member.source) + + redirect_to path, notice: "You have been granted #{member.human_access} access to #{label}." else redirect_to :back, alert: "The invitation could not be accepted." end @@ -34,16 +22,7 @@ class InvitesController < ApplicationController def decline if member.decline_invite! - case member.source - when Project - project = member.source - source = "project #{project.name_with_namespace}" - when Group - group = member.source - source = "group #{group.name}" - else - source = "who knows what" - end + label, _ = source_info(member.source) path = if current_user @@ -81,4 +60,22 @@ class InvitesController < ApplicationController store_location_for :user, request.fullpath redirect_to new_user_session_path, notice: notice end + + def source_info(source) + case source + when Project + project = member.source + label = "project #{project.name_with_namespace}" + path = namespace_project_path(project.namespace, project) + when Group + group = member.source + label = "group #{group.name}" + path = group_path(group) + else + label = "who knows what" + path = dashboard_path + end + + [label, path] + end end -- cgit v1.2.1 From a8b462bbfe3647574e17c483aad27281c2adc5f2 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 12:25:47 +0200 Subject: Clear up InvitesController member lookup logic. --- app/controllers/invites_controller.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 2a98fb0b48b..3ac8654fcce 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -43,11 +43,10 @@ class InvitesController < ApplicationController return @member if defined?(@member) @token = params[:id] - if member = Member.find_by_invite_token(@token) - @member = member - else - render_404 - end + + @member = Member.find_by_invite_token(@token) + + render_404 unless @member end def authenticate_user! -- cgit v1.2.1 From 0013ea5130494326f37fb1d6988a369fa2c91d22 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 12:33:27 +0200 Subject: Remove duplication between Group and ProjectMember. --- .../projects/project_members_controller.rb | 3 +- app/models/group.rb | 21 ++----------- app/models/member.rb | 36 ++++++++++++++++++++-- app/models/members/project_member.rb | 19 ++---------- 4 files changed, 38 insertions(+), 41 deletions(-) (limited to 'app') diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 9831a2089be..3da44cbc9d6 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -52,8 +52,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController respond_to do |format| format.html do - redirect_to namespace_project_project_members_path(@project.namespace, - @project) + redirect_to namespace_project_project_members_path(@project.namespace, @project) end format.js { render nothing: true } end diff --git a/app/models/group.rb b/app/models/group.rb index 2de397f90f7..1386a9eccc9 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -47,25 +47,8 @@ class Group < Namespace end def add_users(user_ids, access_level, current_user = nil) - users = user_ids.map do |user_id| - (user_id if user_id.is_a?(User)) || - User.find_by(id: user_id) || - User.find_by(email: user_id) || - user_id - end - - users.compact.each do |user| - if user.is_a?(User) - member = self.group_members.find_or_initialize_by(user_id: user.id) - else - member = self.group_members.build - member.invite_email = user - end - - member.created_by ||= current_user - member.access_level = access_level - - member.save + user_ids.each do |user_id| + Member.add_user(self.group_members, user_id, access_level, current_user) end end diff --git a/app/models/member.rb b/app/models/member.rb index 2421222eaa2..9340c442172 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -52,9 +52,39 @@ class Member < ActiveRecord::Base delegate :name, :username, :email, to: :user, prefix: true - def self.find_by_invite_token(invite_token) - invite_token = Devise.token_generator.digest(self, :invite_token, invite_token) - find_by(invite_token: invite_token) + class << self + def find_by_invite_token(invite_token) + invite_token = Devise.token_generator.digest(self, :invite_token, invite_token) + find_by(invite_token: invite_token) + end + + # This method is used to find users that have been entered into the "Add members" field. + # These can be the User objects directly, their IDs, their emails, or new emails to be invited. + def user_for_id(user_id) + return user_id if user_id.is_a?(User) + + user = User.find_by(id: user_id) + user ||= User.find_by(email: user_id) + user ||= user_id + user + end + + def add_user(members, user_id, access_level, current_user = nil) + user = user_for_id(user_id) + + # `user` can be either a User object or an email to be invited + if user.is_a?(User) + member = members.find_or_initialize_by(user_id: user.id) + else + member = members.build + member.invite_email = user + end + + member.created_by ||= current_user + member.access_level = access_level + + member.save + end end def invite? diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 8af7499dd82..ce704a60d63 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -60,29 +60,14 @@ class ProjectMember < Member raise "Non valid access" end - users = user_ids.map do |user_id| - (user_id if user_id.is_a?(User)) || - User.find_by(id: user_id) || - User.find_by(email: user_id) || - user_id - end + users = user_ids.map { |user_id| Member.user_for_id(user_id) } ProjectMember.transaction do project_ids.each do |project_id| project = Project.find(project_id) users.each do |user| - if user.is_a?(User) - member = project.project_members.find_or_initialize_by(user_id: user.id) - else - member = project.project_members.build - member.invite_email = user - end - - member.created_by ||= current_user - member.access_level = access_level - - member.save + Member.add_user(project.project_members, user, access_level, current_user) end end end -- cgit v1.2.1 From c26b001ebcf43c3bdc18d1afcfbafa87b0b18366 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 12:52:33 +0200 Subject: Set EmailsOnPush reply-to address to committer email when enabled. --- app/mailers/emails/projects.rb | 14 +++++++++++--- app/mailers/notify.rb | 22 +++++++++++++--------- 2 files changed, 24 insertions(+), 12 deletions(-) (limited to 'app') diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 20a863c3742..d15123e7311 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -84,9 +84,17 @@ module Emails @disable_footer = true - mail(from: sender(author_id, send_from_committer_email), - to: recipient, - subject: @subject) + reply_to = + if send_from_committer_email && can_send_from_user_email?(@author) + @author.email + else + Gitlab.config.gitlab.email_reply_to + end + + mail(from: sender(author_id, send_from_committer_email), + reply_to: reply_to, + to: recipient, + subject: @subject) end end end diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 7c8b37029d1..2c0d451511f 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -60,20 +60,24 @@ class Notify < ActionMailer::Base address end + def can_send_from_user_email?(sender) + sender_domain = sender.email.split("@").last + self.class.allowed_email_domains.include?(sender_domain) + end + # Return an email address that displays the name of the sender. # Only the displayed name changes; the actual email address is always the same. def sender(sender_id, send_from_user_email = false) - if sender = User.find(sender_id) - address = default_sender_address - address.display_name = sender.name + return unless sender = User.find(sender_id) + + address = default_sender_address + address.display_name = sender.name - sender_domain = sender.email.split("@").last - if send_from_user_email && self.class.allowed_email_domains.include?(sender_domain) - address.address = sender.email - end - - address.format + if send_from_user_email && can_send_from_user_email?(sender) + address.address = sender.email end + + address.format end # Look up a User by their ID and return their email address -- cgit v1.2.1 From cb5362e7ce0496e4fa7bec4ae629fd24e93d721e Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 15:16:00 +0200 Subject: Follow newline guidelines. --- app/controllers/groups/group_members_controller.rb | 7 +++++-- app/controllers/invites_controller.rb | 7 +++++-- app/controllers/projects/project_members_controller.rb | 1 + app/mailers/emails/groups.rb | 7 +++++++ app/mailers/emails/projects.rb | 6 ++++++ app/models/members/project_member.rb | 1 + 6 files changed, 25 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 359eeb4d27a..265cf4f0f4a 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -48,13 +48,16 @@ class Groups::GroupMembersController < Groups::ApplicationController end def resend_invite + redirect_path = group_group_members_path(@group) + @group_member = @group.group_members.find(params[:id]) + if @group_member.invite? @group_member.resend_invite - redirect_to group_group_members_path(@group), notice: 'The invitation was successfully resent.' + redirect_to redirect_path, notice: 'The invitation was successfully resent.' else - redirect_to group_group_members_path(@group), alert: 'The invitation has already been accepted.' + redirect_to redirect_path, alert: 'The invitation has already been accepted.' end end diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 3ac8654fcce..1f97ff16c55 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -43,10 +43,13 @@ class InvitesController < ApplicationController return @member if defined?(@member) @token = params[:id] - @member = Member.find_by_invite_token(@token) - render_404 unless @member + unless @member + render_404 and return + end + + @member end def authenticate_user! diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 3da44cbc9d6..72967a26ff1 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -62,6 +62,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController redirect_path = namespace_project_project_members_path(@project.namespace, @project) @project_member = @project.project_members.find(params[:id]) + if @project_member.invite? @project_member.resend_invite diff --git a/app/mailers/emails/groups.rb b/app/mailers/emails/groups.rb index 07b8f6d735a..1c43f95dc8c 100644 --- a/app/mailers/emails/groups.rb +++ b/app/mailers/emails/groups.rb @@ -3,8 +3,10 @@ module Emails def group_access_granted_email(group_member_id) @group_member = GroupMember.find(group_member_id) @group = @group_member.group + @target_url = group_url(@group) @current_user = @group_member.user + mail(to: @group_member.user.notification_email, subject: subject("Access to group was granted")) end @@ -13,8 +15,10 @@ module Emails @group_member = GroupMember.find group_member_id @group = @group_member.group @token = token + @target_url = group_url(@group) @current_user = @group_member.user + mail(to: @group_member.invite_email, subject: "Invitation to join group #{@group.name}") end @@ -24,8 +28,10 @@ module Emails return if @group_member.created_by.nil? @group = @group_member.group + @target_url = group_url(@group) @current_user = @group_member.created_by + mail(to: @group_member.created_by.notification_email, subject: subject("Invitation accepted")) end @@ -37,6 +43,7 @@ module Emails @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")) diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 7baeead3fb5..2584e9d48b1 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -3,8 +3,10 @@ module Emails def project_access_granted_email(project_member_id) @project_member = ProjectMember.find project_member_id @project = @project_member.project + @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 @@ -13,8 +15,10 @@ module Emails @project_member = ProjectMember.find project_member_id @project = @project_member.project @token = token + @target_url = namespace_project_url(@project.namespace, @project) @current_user = @project_member.user + mail(to: @project_member.invite_email, subject: "Invitation to join project #{@project.name_with_namespace}") end @@ -24,6 +28,7 @@ module Emails 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 @@ -38,6 +43,7 @@ module Emails @current_user = @created_by = User.find(created_by_id) @access_level = access_level @invite_email = invite_email + @target_url = namespace_project_url(@project.namespace, @project) mail(to: @created_by.notification_email, diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index ce704a60d63..0a3b4d2182b 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -80,6 +80,7 @@ class ProjectMember < Member def truncate_teams(project_ids) ProjectMember.transaction do members = ProjectMember.where(source_id: project_ids) + members.each do |member| member.destroy end -- cgit v1.2.1 From 5662b2413206db20f935a0dffb5f12debd248447 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 15:45:06 +0200 Subject: Don't use HTML ellipsis in EmailsOnPush subject truncated commit message. --- app/models/commit.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/models/commit.rb b/app/models/commit.rb index 7a0ad137650..006fa62c8f9 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -77,7 +77,7 @@ class Commit title_end = title.index("\n") if (!title_end && title.length > 100) || (title_end && title_end > 100) - title[0..79] << "…".html_safe + title[0..79] << "…" else title.split("\n", 2).first end @@ -90,7 +90,7 @@ class Commit title_end = safe_message.index("\n") @description ||= if (!title_end && safe_message.length > 100) || (title_end && title_end > 100) - "…".html_safe << safe_message[80..-1] + "…" << safe_message[80..-1] else safe_message.split("\n", 2)[1].try(:chomp) end -- cgit v1.2.1 From c1531fe1d801b175d8ecf7646592b1f5e9a8e508 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 18:04:29 +0200 Subject: Add spinach tests around accepting and declining invitations. --- app/models/member.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app') diff --git a/app/models/member.rb b/app/models/member.rb index 9340c442172..d151c7b2390 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -22,6 +22,8 @@ class Member < ActiveRecord::Base include Notifiable include Gitlab::Access + attr_accessor :raw_invite_token + belongs_to :created_by, class_name: "User" belongs_to :user belongs_to :source, polymorphic: true -- cgit v1.2.1 From 88c2639356e6e4b4b05d96584768e07a9ce4b048 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 23:06:21 +0200 Subject: Remove superfluous info from invite accepted/declined mails. --- app/views/notify/group_invite_accepted_email.html.haml | 3 +-- app/views/notify/group_invite_accepted_email.text.erb | 2 +- app/views/notify/group_invite_declined_email.html.haml | 3 +-- app/views/notify/group_invite_declined_email.text.erb | 2 +- app/views/notify/project_invite_accepted_email.html.haml | 3 +-- app/views/notify/project_invite_accepted_email.text.erb | 2 +- app/views/notify/project_invite_declined_email.html.haml | 3 +-- app/views/notify/project_invite_declined_email.text.erb | 2 +- 8 files changed, 8 insertions(+), 12 deletions(-) (limited to 'app') diff --git a/app/views/notify/group_invite_accepted_email.html.haml b/app/views/notify/group_invite_accepted_email.html.haml index d50d182102b..55efad384a7 100644 --- a/app/views/notify/group_invite_accepted_email.html.haml +++ b/app/views/notify/group_invite_accepted_email.html.haml @@ -2,6 +2,5 @@ #{@group_member.invite_email}, now known as #{link_to @group_member.user.name, user_url(@group_member.user)}, has accepted your invitation to join group - = link_to @group.name, group_url(@group) - as #{@group_member.human_access}. + #{link_to @group.name, group_url(@group)}. diff --git a/app/views/notify/group_invite_accepted_email.text.erb b/app/views/notify/group_invite_accepted_email.text.erb index 0072f5252da..f8b70f7a5a6 100644 --- a/app/views/notify/group_invite_accepted_email.text.erb +++ b/app/views/notify/group_invite_accepted_email.text.erb @@ -1,3 +1,3 @@ -<%= @group_member.invite_email %>, now known as <%= @group_member.user.name %>, has accepted your invitation to join group <%= @group.name %> as <%= @group_member.human_access %>. +<%= @group_member.invite_email %>, now known as <%= @group_member.user.name %>, has accepted your invitation to join group <%= @group.name %>. <%= group_url(@group) %> diff --git a/app/views/notify/group_invite_declined_email.html.haml b/app/views/notify/group_invite_declined_email.html.haml index 80f39c3f1ea..f9525d84fac 100644 --- a/app/views/notify/group_invite_declined_email.html.haml +++ b/app/views/notify/group_invite_declined_email.html.haml @@ -1,6 +1,5 @@ %p #{@invite_email} has declined your invitation to join group - = link_to @group.name, group_url(@group) - as #{Gitlab::Access.options_with_owner.key(@access_level)}. + #{link_to @group.name, group_url(@group)}. diff --git a/app/views/notify/group_invite_declined_email.text.erb b/app/views/notify/group_invite_declined_email.text.erb index 31cdac0e7fb..6c19a288d15 100644 --- a/app/views/notify/group_invite_declined_email.text.erb +++ b/app/views/notify/group_invite_declined_email.text.erb @@ -1,3 +1,3 @@ -<%= @invite_email %> has declined your invitation to join group <%= @group.name %> as <%= Gitlab::Access.options_with_owner.key(@access_level) %>. +<%= @invite_email %> has declined your invitation to join group <%= @group.name %>. <%= group_url(@group) %> diff --git a/app/views/notify/project_invite_accepted_email.html.haml b/app/views/notify/project_invite_accepted_email.html.haml index 0c01eef7621..7e58d30b10a 100644 --- a/app/views/notify/project_invite_accepted_email.html.haml +++ b/app/views/notify/project_invite_accepted_email.html.haml @@ -2,6 +2,5 @@ #{@project_member.invite_email}, now known as #{link_to @project_member.user.name, user_url(@project_member.user)}, has accepted your invitation to join project - = link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project) - as #{@project_member.human_access}. + #{link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project)}. diff --git a/app/views/notify/project_invite_accepted_email.text.erb b/app/views/notify/project_invite_accepted_email.text.erb index 0bbe274931e..fcbe752114d 100644 --- a/app/views/notify/project_invite_accepted_email.text.erb +++ b/app/views/notify/project_invite_accepted_email.text.erb @@ -1,3 +1,3 @@ -<%= @project_member.invite_email %>, now known as <%= @project_member.user.name %>, has accepted your invitation to join project <%= @project.name_with_namespace %> as <%= @project_member.human_access %>. +<%= @project_member.invite_email %>, now known as <%= @project_member.user.name %>, has accepted your invitation to join project <%= @project.name_with_namespace %>. <%= namespace_project_url(@project.namespace, @project) %> diff --git a/app/views/notify/project_invite_declined_email.html.haml b/app/views/notify/project_invite_declined_email.html.haml index dad9f505b9e..c2d7e6f6e3a 100644 --- a/app/views/notify/project_invite_declined_email.html.haml +++ b/app/views/notify/project_invite_declined_email.html.haml @@ -1,6 +1,5 @@ %p #{@invite_email} has declined your invitation to join project - = link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project) - as #{Gitlab::Access.options_with_owner.key(@access_level)}. + #{link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project)}. diff --git a/app/views/notify/project_invite_declined_email.text.erb b/app/views/notify/project_invite_declined_email.text.erb index 06a0013cff5..484687fa51c 100644 --- a/app/views/notify/project_invite_declined_email.text.erb +++ b/app/views/notify/project_invite_declined_email.text.erb @@ -1,3 +1,3 @@ -<%= @invite_email %> has declined your invitation to join project <%= @project.name_with_namespace %> as <%= Gitlab::Access.options_with_owner.key(@access_level) %>. +<%= @invite_email %> has declined your invitation to join project <%= @project.name_with_namespace %>. <%= namespace_project_url(@project.namespace, @project) %> -- cgit v1.2.1 From 36b54fc04f7619faad37f052528f9cb30c3dd99e Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 14 Apr 2015 23:26:53 +0200 Subject: Don't crash when project repository doesn't exist. --- app/controllers/application_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0521a9ef8cf..920a981e7c9 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -126,7 +126,7 @@ class ApplicationController < ActionController::Base def repository @repository ||= project.repository - rescue Grit::NoSuchPathError(e) + rescue Grit::NoSuchPathError => e log_exception(e) nil end -- cgit v1.2.1