diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb
index 10c4cd9d00e5..4428102bd1a9 100644
--- a/app/controllers/members_controller.rb
+++ b/app/controllers/members_controller.rb
@@ -118,14 +118,20 @@ def authorize_for(controller, action)
current_user.allowed_in_project?({ controller:, action: }, @project)
end
+ def user_allowed_to_view_emails?
+ current_user.allowed_globally?(:view_user_email)
+ end
+
def build_members
paths = API::V3::Utilities::PathHelper::ApiV3Path
principals = @principals.map do |principal|
- {
+ member = {
id: principal.id,
name: principal.name,
href: paths.send(principal.type.underscore, principal.id)
}
+ member[:email] = principal.mail if user_allowed_to_view_emails?
+ member
end
if @email
@@ -195,7 +201,7 @@ def set_roles_and_principles!
def possible_members(criteria, limit)
Principal
.possible_member(@project)
- .like(criteria)
+ .like(criteria, email: user_allowed_to_view_emails?)
.limit(limit)
end
diff --git a/app/models/global_role.rb b/app/models/global_role.rb
index 5600bfd1e0dd..bda2366dac60 100644
--- a/app/models/global_role.rb
+++ b/app/models/global_role.rb
@@ -31,4 +31,15 @@ def self.givable
super
.where(type: "GlobalRole")
end
+
+ def self.standard
+ standard_global_role = where(builtin: BUILTIN_STANDARD_GLOBAL).first
+ if standard_global_role.nil?
+ standard_global_role = create(name: "Standard global role", position: 0) do |role|
+ role.builtin = BUILTIN_STANDARD_GLOBAL
+ end
+ raise "Unable to create the standard global role." if standard_global_role.new_record?
+ end
+ standard_global_role
+ end
end
diff --git a/app/models/principals/scopes/like.rb b/app/models/principals/scopes/like.rb
index ea8064cab837..3fd1e92c0827 100644
--- a/app/models/principals/scopes/like.rb
+++ b/app/models/principals/scopes/like.rb
@@ -36,21 +36,27 @@ module Like
extend ActiveSupport::Concern
class_methods do
- def like(query)
+ def like(query, email: true)
firstnamelastname = "((firstname || ' ') || lastname)"
lastnamefirstname = "((lastname || ' ') || firstname)"
s = "%#{query.to_s.downcase.strip.tr(',', '')}%"
- sql = <<~SQL
+ sql = <<~SQL.squish
LOWER(login) LIKE :s
OR unaccent(LOWER(#{firstnamelastname})) LIKE unaccent(:s)
OR unaccent(LOWER(#{lastnamefirstname})) LIKE unaccent(:s)
- OR LOWER(mail) LIKE :s
SQL
+ order_clause = %i[type login lastname firstname]
+
+ if email
+ sql += " OR LOWER(mail) LIKE :s"
+ order_clause << :mail
+ end
+
where([sql, { s: }])
- .order(:type, :login, :lastname, :firstname, :mail)
+ .order(*order_clause)
end
end
end
diff --git a/app/models/queries/filters/shared/any_user_name_attribute_filter.rb b/app/models/queries/filters/shared/any_user_name_attribute_filter.rb
index 498466a67f9c..964076c8b9fa 100644
--- a/app/models/queries/filters/shared/any_user_name_attribute_filter.rb
+++ b/app/models/queries/filters/shared/any_user_name_attribute_filter.rb
@@ -43,21 +43,25 @@ def available_operators
Queries::Operators::NotContains]
end
+ def email_field_allowed?
+ true
+ end
+
private
def sql_concat_name
- <<-SQL.squish
- LOWER(
- CONCAT(
- users.firstname, ' ', users.lastname,
- ' ',
- users.lastname, ' ', users.firstname,
- ' ',
- users.login,
- ' ',
- users.mail
- )
- )
+ fields = <<~SQL.squish
+ users.firstname, ' ', users.lastname,
+ ' ',
+ users.lastname, ' ', users.firstname,
+ ' ',
+ users.login
+ SQL
+
+ fields << ", ' ',users.mail" if email_field_allowed?
+
+ <<~SQL.squish
+ LOWER(CONCAT(#{fields}))
SQL
end
end
diff --git a/app/models/queries/principals/filters/typeahead_filter.rb b/app/models/queries/principals/filters/typeahead_filter.rb
index 374f3a5ca110..5d69b4c6ac3c 100644
--- a/app/models/queries/principals/filters/typeahead_filter.rb
+++ b/app/models/queries/principals/filters/typeahead_filter.rb
@@ -35,6 +35,10 @@ def type
:search
end
+ def email_field_allowed?
+ User.current.allowed_globally?(:view_user_email)
+ end
+
def human_name
I18n.t("label_search")
end
diff --git a/app/models/role.rb b/app/models/role.rb
index bbaff72cd4a4..77c940dc55b2 100644
--- a/app/models/role.rb
+++ b/app/models/role.rb
@@ -36,6 +36,7 @@ class Role < ApplicationRecord
BUILTIN_WORK_PACKAGE_EDITOR = 5
BUILTIN_PROJECT_QUERY_VIEW = 6
BUILTIN_PROJECT_QUERY_EDIT = 7
+ BUILTIN_STANDARD_GLOBAL = 8
HIDDEN_ROLE_TYPES = [
"WorkPackageRole",
@@ -93,7 +94,8 @@ def self.givable
Role::BUILTIN_WORK_PACKAGE_COMMENTER,
Role::BUILTIN_WORK_PACKAGE_EDITOR,
Role::BUILTIN_PROJECT_QUERY_VIEW,
- Role::BUILTIN_PROJECT_QUERY_EDIT
+ Role::BUILTIN_PROJECT_QUERY_EDIT,
+ Role::BUILTIN_STANDARD_GLOBAL
]
)
.order(Arel.sql("position"))
diff --git a/app/seeders/basic_data/base_role_seeder.rb b/app/seeders/basic_data/base_role_seeder.rb
index e1ffed74629e..f3a09bfb4041 100644
--- a/app/seeders/basic_data/base_role_seeder.rb
+++ b/app/seeders/basic_data/base_role_seeder.rb
@@ -49,6 +49,7 @@ def builtin(value)
case value
when :non_member then Role::BUILTIN_NON_MEMBER
when :anonymous then Role::BUILTIN_ANONYMOUS
+ when :standard_global then Role::BUILTIN_STANDARD_GLOBAL
when :work_package_editor then Role::BUILTIN_WORK_PACKAGE_EDITOR
when :work_package_commenter then Role::BUILTIN_WORK_PACKAGE_COMMENTER
when :work_package_viewer then Role::BUILTIN_WORK_PACKAGE_VIEWER
diff --git a/app/seeders/common.yml b/app/seeders/common.yml
index 16ca0a3560ca..2b3544a5237f 100644
--- a/app/seeders/common.yml
+++ b/app/seeders/common.yml
@@ -398,3 +398,9 @@ global_roles:
- :create_user
- :manage_user
- :manage_placeholder_user
+ - reference: :default_role_standard_global
+ t_name: Standard global role
+ position: 7
+ builtin: :standard_global
+ permissions:
+ - :view_user_email
diff --git a/app/services/authorization/user_global_roles_query.rb b/app/services/authorization/user_global_roles_query.rb
index 4fc93822512c..8300997fe945 100644
--- a/app/services/authorization/user_global_roles_query.rb
+++ b/app/services/authorization/user_global_roles_query.rb
@@ -35,7 +35,8 @@ class Authorization::UserGlobalRolesQuery < Authorization::UserRolesQuery
Role::BUILTIN_ANONYMOUS
end
- builtin_role_condition = roles_table[:builtin].eq(builtin_role)
+ builtin_roles = [builtin_role, Role::BUILTIN_STANDARD_GLOBAL]
+ builtin_role_condition = roles_table[:builtin].in(builtin_roles)
statement.or(builtin_role_condition)
end
diff --git a/app/views/principals/_available_global_roles.html.erb b/app/views/principals/_available_global_roles.html.erb
index ae3e852f8458..c4510e0b7dd9 100644
--- a/app/views/principals/_available_global_roles.html.erb
+++ b/app/views/principals/_available_global_roles.html.erb
@@ -27,7 +27,7 @@ See COPYRIGHT and LICENSE files for more details.
++#%>
-<% available_roles = GlobalRole.all - (global_member&.roles || []) %>
+<% available_roles = GlobalRole.givable - (global_member&.roles || []) %>