mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
Invite users by email
This commit is contained in:
@@ -219,6 +219,7 @@ Rails/DynamicFindBy:
|
||||
- "modules/*/spec/features/**/*.rb"
|
||||
Whitelist:
|
||||
- find_by_login
|
||||
- find_by_mail
|
||||
|
||||
# Allow reorder to prevent find each cop triggering
|
||||
Rails/FindEach:
|
||||
|
||||
@@ -55,21 +55,28 @@ module MemberHelper
|
||||
|
||||
def invite_new_user(id, send_notification: true) # rubocop:disable Metrics/PerceivedComplexity
|
||||
if id.present? && (id.to_i == 0 || EmailValidator.valid?(id)) # we've got an email - invite that user
|
||||
# Users with create_user permission or invite_members_by_email permission can add users.
|
||||
if (current_user.allowed_globally?(:create_user) ||
|
||||
current_user.allowed_in_project?(:invite_members_by_email, @project)) &&
|
||||
enterprise_allow_new_users?
|
||||
# The invitation can pretty much only fail due to the user already
|
||||
# having been invited. So look them up if it does.
|
||||
user = UserInvitation.invite_new_user(email: id, send_notification:) || User.find_by_mail(id) # rubocop:disable Rails/DynamicFindBy
|
||||
|
||||
user&.id
|
||||
end
|
||||
invite_existing_or_new_users(email: id, send_notification:)
|
||||
else
|
||||
id
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# When inviting a user, it might be that the user already exists but is not visible to the inviting user.
|
||||
# In that case, we just return the existing user.
|
||||
# Otherwise, send an invitation and return the newly created invited user
|
||||
# Users with create_user permission or invite_members_by_email permission can add users.
|
||||
def invite_existing_or_new_users(email:, send_notification:)
|
||||
return unless user_allowed_to_invite?(current_user) && enterprise_allow_new_users?
|
||||
|
||||
user = User.find_by_mail(email) || UserInvitation.invite_new_user(email:, send_notification:)
|
||||
user&.id
|
||||
end
|
||||
|
||||
def user_allowed_to_invite?(user)
|
||||
user.allowed_globally?(:create_user) || user.allowed_in_project?(:invite_members_by_email, @project)
|
||||
end
|
||||
|
||||
def invite_new_users(user_ids, send_notification: true)
|
||||
user_ids.filter_map do |id|
|
||||
invite_new_user(id, send_notification:)
|
||||
|
||||
@@ -177,10 +177,11 @@ class MembersController < ApplicationController
|
||||
}
|
||||
end
|
||||
|
||||
def suggest_invite_via_email?(user, query, principals)
|
||||
user.allowed_globally?(:create_user) &&
|
||||
query =~ mail_regex &&
|
||||
principals.none? { |p| p.mail == query || p.login == query } &&
|
||||
def suggest_invite_via_email?(user, query, visible_principals)
|
||||
return false unless user_allowed_to_invite?(user)
|
||||
|
||||
query =~ mail_regex &&
|
||||
visible_principals.none? { |p| p.mail == query || p.login == query } &&
|
||||
query # finally return email
|
||||
end
|
||||
|
||||
|
||||
@@ -193,6 +193,12 @@ Rails.application.reloader.to_prepare do
|
||||
dependencies: :view_members,
|
||||
contract_actions: { members: %i[create update destroy] }
|
||||
|
||||
map.permission :invite_members_by_email,
|
||||
{},
|
||||
permissible_on: :project,
|
||||
require: :member,
|
||||
dependencies: :manage_members
|
||||
|
||||
map.permission :view_members,
|
||||
{
|
||||
members: %i[index menu],
|
||||
|
||||
@@ -3976,6 +3976,11 @@ en:
|
||||
permission_edit_wiki_pages: "Edit wiki pages"
|
||||
permission_export_work_packages: "Export work packages"
|
||||
permission_export_wiki_pages: "Export wiki pages"
|
||||
permission_invite_members_by_email: "Invite members by email"
|
||||
permission_invite_members_by_email_explanation: >
|
||||
Allows users to invite new members by email.
|
||||
Invited users will receive an email with a link to set their password and activate their account.
|
||||
Depends on the permission to manage members
|
||||
permission_list_attachments: "List attachments"
|
||||
permission_log_own_time: "Log own time"
|
||||
permission_log_time: "Log time for other users"
|
||||
|
||||
@@ -264,6 +264,47 @@ RSpec.describe MembersController do
|
||||
end
|
||||
end
|
||||
|
||||
describe "#create with reduced visibility" do
|
||||
let(:project_permissions) { %i[manage_members invite_members_by_email] }
|
||||
let!(:other_project) { create(:project) }
|
||||
let!(:other_user) { create(:user, member_with_permissions: { other_project => %i[view_project] }) }
|
||||
let!(:user) do
|
||||
create(:user, member_with_permissions: { project => project_permissions, other_project => %i[view_project] })
|
||||
end
|
||||
|
||||
before do
|
||||
login_as(user)
|
||||
end
|
||||
|
||||
context "when inviting by email an existing user who is not visible" do
|
||||
let!(:hidden_user) { create(:user, mail: "hidden@example.com") }
|
||||
let(:params) do
|
||||
{
|
||||
project_id: project.id,
|
||||
member: {
|
||||
role_ids: [role.id],
|
||||
user_ids: [hidden_user.mail]
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "adds the existing user as a member instead of creating a new invitation" do
|
||||
expect { post :create, params: }
|
||||
.to not_change(User, :count).by(0)
|
||||
.and change(Member, :count).by(1)
|
||||
|
||||
expect(response).to redirect_to "/projects/pet_project/members?status=all"
|
||||
|
||||
# The hidden user should now be a member of the project
|
||||
hidden_user.reload
|
||||
expect(hidden_user).to be_member_of(project)
|
||||
|
||||
# No invitation email should be sent since the user already exists
|
||||
expect(ActionMailer::Base.deliveries).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#create" do
|
||||
render_views
|
||||
let(:user2) { create(:user) }
|
||||
|
||||
Reference in New Issue
Block a user