Skip to content

Commit

Permalink
Release OpenProject 12.4.2
Browse files Browse the repository at this point in the history
  • Loading branch information
oliverguenther committed Jan 16, 2023
2 parents ed1c162 + 33242ad commit a50dfa0
Show file tree
Hide file tree
Showing 228 changed files with 14,366 additions and 686 deletions.
4 changes: 4 additions & 0 deletions app/models/custom_value.rb
Expand Up @@ -61,6 +61,10 @@ def strategy
end
end

def default?
value == custom_field.default_value
end

protected

def validate_presence_of_required_value
Expand Down
2 changes: 1 addition & 1 deletion app/models/group.rb
Expand Up @@ -72,6 +72,6 @@ def uniqueness_of_name
end

def fail_add
fail "Do not add users through association, use `group.add_members!` instead."
fail "Do not add users through association, use `Groups::AddUsersService` instead."
end
end
18 changes: 11 additions & 7 deletions app/models/work_package/pdf_export/view.rb
Expand Up @@ -55,27 +55,25 @@ def document
end

def fallback_fonts
[]
[noto_font_base_path.join('NotoSansSymbols2-Regular.ttf')]
end

def register_fonts!(document)
font_path = Rails.public_path.join('fonts')

document.font_families['NotoSans'] = {
normal: {
file: font_path.join('noto/NotoSans-Regular.ttf'),
file: noto_font_base_path.join('NotoSans-Regular.ttf'),
font: 'NotoSans-Regular'
},
italic: {
file: font_path.join('noto/NotoSans-Italic.ttf'),
file: noto_font_base_path.join('NotoSans-Italic.ttf'),
font: 'NotoSans-Italic'
},
bold: {
file: font_path.join('noto/NotoSans-Bold.ttf'),
file: noto_font_base_path.join('NotoSans-Bold.ttf'),
font: 'NotoSans-Bold'
},
bold_italic: {
file: font_path.join('noto/NotoSans-BoldItalic.ttf'),
file: noto_font_base_path.join('NotoSans-BoldItalic.ttf'),
font: 'NotoSans-BoldItalic'
}
}
Expand All @@ -99,4 +97,10 @@ def font(name: nil, style: nil, size: nil)

document.font
end

private

def noto_font_base_path
Rails.public_path.join('fonts/noto')
end
end
105 changes: 23 additions & 82 deletions app/services/groups/add_users_service.rb
Expand Up @@ -29,7 +29,6 @@
module Groups
class AddUsersService < ::BaseServices::BaseContracted
using CoreExtensions::SquishSql
include Groups::Concerns::MembershipManipulation

def initialize(group, current_user:, contract_class: AdminOnlyContract)
self.model = group
Expand All @@ -40,95 +39,37 @@ def initialize(group, current_user:, contract_class: AdminOnlyContract)

private

def modify_members_and_roles(params)
def persist(call)
sql_query = ::OpenProject::SqlSanitization
.sanitize add_to_user_and_projects_cte,
group_id: model.id,
user_ids: params[:ids]

.sanitize add_to_group,
group_id: model.id,
user_ids: params[:ids]
execute_query(sql_query)

call
end

def add_to_user_and_projects_cte
<<~SQL.squish
-- select existing users from given IDs
WITH found_users AS (
SELECT id as user_id FROM #{User.table_name} WHERE id IN (:user_ids)
),
timestamp AS (
SELECT CURRENT_TIMESTAMP as time
),
-- select existing memberships of the group
group_memberships AS (
SELECT project_id, user_id FROM #{Member.table_name} WHERE user_id = :group_id
),
-- select existing member_roles of the group
group_roles AS (
SELECT members.project_id AS project_id,
members.user_id AS user_id,
members.id AS member_id,
member_roles.role_id AS role_id,
member_roles.id AS member_role_id
FROM #{MemberRole.table_name} member_roles
JOIN #{Member.table_name} members
ON members.id = member_roles.member_id AND members.user_id = :group_id
),
-- insert into group_users association
new_group_users AS (
INSERT INTO group_users (group_id, user_id)
SELECT :group_id as group_id, user_id FROM found_users
ON CONFLICT DO NOTHING
),
-- find members that already exist
existing_members AS (
SELECT members.id, found_users.user_id, members.project_id
FROM members, found_users, group_memberships
WHERE members.user_id = found_users.user_id
AND members.project_id IS NOT DISTINCT FROM group_memberships.project_id
AND members.id IS NOT NULL
),
-- insert the group user into members
new_members AS (
INSERT INTO #{Member.table_name} (project_id, user_id, updated_at, created_at)
SELECT group_memberships.project_id, found_users.user_id, (SELECT time from timestamp), (SELECT time from timestamp)
FROM found_users, group_memberships
WHERE NOT EXISTS (SELECT 1 FROM existing_members WHERE existing_members.user_id = found_users.user_id AND existing_members.project_id IS NOT DISTINCT FROM group_memberships.project_id)
ON CONFLICT(project_id, user_id) DO NOTHING
RETURNING id, user_id, project_id
),
-- copy the member roles of the group
add_roles AS (
INSERT INTO #{MemberRole.table_name} (member_id, role_id, inherited_from)
SELECT members.id, group_roles.role_id, group_roles.member_role_id
FROM group_roles
JOIN
(SELECT * FROM new_members UNION SELECT * from existing_members) members ON group_roles.project_id IS NOT DISTINCT FROM members.project_id
-- Ignore if the role was already inserted by us
ON CONFLICT DO NOTHING
RETURNING id, member_id, role_id
),
-- get the ids of members where roles have been added the member did not have before
members_with_added_roles AS (
SELECT DISTINCT add_roles.member_id
FROM add_roles
WHERE NOT EXISTS
(SELECT 1 FROM #{MemberRole.table_name}
WHERE #{MemberRole.table_name}.member_id = add_roles.member_id
AND #{MemberRole.table_name}.role_id = add_roles.role_id
AND #{MemberRole.table_name}.id != add_roles.id)
),
touch_existing_members AS (
UPDATE members SET updated_AT = CURRENT_TIMESTAMP
WHERE id IN (SELECT id from existing_members)
AND id IN (SELECT member_id from members_with_added_roles)
)
def after_perform(call)
Groups::CreateInheritedRolesService
.new(model, current_user: user, contract_class:)
.call(user_ids: params[:ids], message: params[:message])

SELECT member_id from members_with_added_roles
call
end

def add_to_group
<<~SQL.squish
INSERT INTO group_users (group_id, user_id)
SELECT :group_id as group_id, user_id FROM
(SELECT id as user_id FROM #{User.table_name} WHERE id IN (:user_ids)) users
ON CONFLICT DO NOTHING
SQL
end

def touch_updated(member_ids)
# do nothing in this case as we already touch while updating
def execute_query(query)
::Group
.connection
.exec_query(query)
end
end
end
137 changes: 137 additions & 0 deletions app/services/groups/create_inherited_roles_service.rb
@@ -0,0 +1,137 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2022 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module Groups
# Adds inherited roles to the users provided to mirror the roles the group has.
# This can be scoped to only a certain project which results in considerably better performance.
class CreateInheritedRolesService < ::BaseServices::BaseContracted
using CoreExtensions::SquishSql
include Groups::Concerns::MembershipManipulation

def initialize(group, current_user:, contract_class: AdminOnlyContract)
self.model = group

super user: current_user,
contract_class:
end

private

def modify_members_and_roles(params)
sql_query = ::OpenProject::SqlSanitization
.sanitize add_to_user_and_projects_cte(project_ids: params[:project_ids]),
group_id: model.id,
user_ids: params[:user_ids],
project_ids: params[:project_ids]

execute_query(sql_query)
end

def add_to_user_and_projects_cte(project_ids: nil)
project_limit = if project_ids
"project_id IN (:project_ids)"
else
"1=1"
end

<<~SQL.squish
-- select existing users from given IDs
WITH found_users AS (
SELECT id as user_id FROM #{User.table_name} WHERE id IN (:user_ids)
),
timestamp AS (
SELECT CURRENT_TIMESTAMP as time
),
-- select existing memberships of the group
group_memberships AS (
SELECT project_id, user_id FROM #{Member.table_name} WHERE user_id = :group_id AND #{project_limit}
),
-- select existing member_roles of the group
group_roles AS (
SELECT members.project_id AS project_id,
members.user_id AS user_id,
members.id AS member_id,
member_roles.role_id AS role_id,
member_roles.id AS member_role_id
FROM #{MemberRole.table_name} member_roles
JOIN #{Member.table_name} members
ON members.id = member_roles.member_id AND members.user_id = :group_id
),
-- find members that already exist
existing_members AS (
SELECT members.id, found_users.user_id, members.project_id
FROM members, found_users, group_memberships
WHERE members.user_id = found_users.user_id
AND members.project_id IS NOT DISTINCT FROM group_memberships.project_id
AND members.id IS NOT NULL
),
-- insert the group user into members
new_members AS (
INSERT INTO #{Member.table_name} (project_id, user_id, updated_at, created_at)
SELECT group_memberships.project_id, found_users.user_id, (SELECT time from timestamp), (SELECT time from timestamp)
FROM found_users, group_memberships
WHERE NOT EXISTS (SELECT 1 FROM existing_members WHERE existing_members.user_id = found_users.user_id AND existing_members.project_id IS NOT DISTINCT FROM group_memberships.project_id)
ON CONFLICT(project_id, user_id) DO NOTHING
RETURNING id, user_id, project_id
),
-- copy the member roles of the group
add_roles AS (
INSERT INTO #{MemberRole.table_name} (member_id, role_id, inherited_from)
SELECT members.id, group_roles.role_id, group_roles.member_role_id
FROM group_roles
JOIN
(SELECT * FROM new_members UNION SELECT * from existing_members) members ON group_roles.project_id IS NOT DISTINCT FROM members.project_id
-- Ignore if the role was already inserted by us
ON CONFLICT DO NOTHING
RETURNING id, member_id, role_id
),
-- get the ids of members where roles have been added the member did not have before
members_with_added_roles AS (
SELECT DISTINCT add_roles.member_id
FROM add_roles
WHERE NOT EXISTS
(SELECT 1 FROM #{MemberRole.table_name}
WHERE #{MemberRole.table_name}.member_id = add_roles.member_id
AND #{MemberRole.table_name}.role_id = add_roles.role_id
AND #{MemberRole.table_name}.id != add_roles.id)
),
touch_existing_members AS (
UPDATE members SET updated_at = CURRENT_TIMESTAMP
WHERE id IN (SELECT id from existing_members)
AND id IN (SELECT member_id from members_with_added_roles)
)
SELECT member_id from members_with_added_roles
SQL
end

def touch_updated(member_ids)
# do nothing in this case as we already touch while updating
end
end
end
4 changes: 2 additions & 2 deletions app/services/members/create_service.rb
Expand Up @@ -47,9 +47,9 @@ def post_process
def add_group_memberships(member)
return unless member.principal.is_a?(Group)

Groups::AddUsersService
Groups::CreateInheritedRolesService
.new(member.principal, current_user: user, contract_class: EmptyContract)
.call(ids: member.principal.user_ids, send_notifications: false)
.call(user_ids: member.principal.user_ids, send_notifications: false, project_ids: [member.project_id])
end

def event_type
Expand Down
11 changes: 2 additions & 9 deletions app/services/oauth_clients/connection_manager.rb
Expand Up @@ -151,7 +151,7 @@ def request_with_token_refresh(oauth_client_token)
# `yield` needs to returns a ServiceResult:
# success: result= any object with data
# failure: result= :error or :not_authorized
yield_service_result = yield
yield_service_result = yield(oauth_client_token)

if yield_service_result.failure? && yield_service_result.result == :not_authorized
refresh_service_result = refresh_token
Expand All @@ -162,19 +162,12 @@ def request_with_token_refresh(oauth_client_token)
end

oauth_client_token.reload
yield_service_result = yield # Should contain result=<data> in case of success
yield_service_result = yield(oauth_client_token) # Should contain result=<data> in case of success
end

yield_service_result
end

def with_refreshed_token(&)
token = get_existing_token
return ServiceResult.failure(result: :not_authorized) if token.blank?

request_with_token_refresh(token, &)
end

private

# Check if a OAuthClientToken already exists and return nil otherwise.
Expand Down
5 changes: 3 additions & 2 deletions app/workers/application_job.rb
Expand Up @@ -36,7 +36,7 @@ class ApplicationJob < ::ActiveJob::Base
# to avoid leaking sensitive information to logs
self.log_arguments = false

around_perform :clean_context
around_perform :prepare_job_context

##
# Return a priority number on the given payload
Expand Down Expand Up @@ -94,8 +94,9 @@ def reload_mailer_settings!

private

def clean_context
def prepare_job_context
with_clean_request_store do
::OpenProject::Appsignal.tag_request
reload_mailer_settings!

yield
Expand Down

0 comments on commit a50dfa0

Please sign in to comment.