Merge branch 'release/12.3' into dev

pull/11490/head
ulferts 2 years ago
commit 3f96c1043a
No known key found for this signature in database
GPG Key ID: A205708DE1284017
  1. 25
      app/services/copy/concerns/copy_attachments.rb
  2. 2
      app/uploaders/fog_file_uploader.rb
  3. 8
      docs/installation-and-operations/configuration/environment/README.md
  4. 22
      frontend/src/app/features/invite-user-modal/summary/summary.component.html
  5. 8
      frontend/src/app/features/invite-user-modal/summary/summary.component.sass
  6. 2
      frontend/src/app/shared/components/modal/modal-wrapper-augment.service.ts
  7. 2
      frontend/src/global_styles/openproject/_onboarding.sass
  8. 1
      lib/api/v3/queries/query_params_representer.rb
  9. 13
      modules/meeting/app/models/meeting.rb
  10. 11
      modules/meeting/spec/models/meeting_spec.rb
  11. 2
      modules/two_factor_authentication/app/views/two_factor_authentication/authentication/enter_backup_code.html.erb
  12. 2
      modules/two_factor_authentication/app/views/two_factor_authentication/authentication/request_otp.html.erb
  13. 2
      modules/two_factor_authentication/app/views/two_factor_authentication/two_factor_devices/confirm.html.erb
  14. 2
      packaging/addons/openproject/bin/postinstall
  15. 55
      spec/lib/api/v3/queries/queries_params_representer_spec.rb
  16. 4
      spec/lib/api/v3/queries/query_representer_rendering_spec.rb

@ -6,21 +6,28 @@ module Copy
def copy_attachments(container_type, from_id:, to_id:)
Attachment
.where(container_type:, container_id: from_id)
.find_each do |old_attachment|
copied = old_attachment.dup
old_attachment.file.copy_to(copied)
.find_each do |source|
copied.author = user
copied.container_type = old_attachment.container_type
copied.container_id = to_id
copy = Attachment
.new(attachment_copy_attributes(source, to_id))
source.file.copy_to(copy)
unless copied.save
Rails.logger.error { "Attachments ##{old_attachment.id} could not be copied: #{copied.errors.full_messages} " }
unless copy.save
Rails.logger.error { "Attachments ##{source.id} could not be copy: #{copy.errors.full_messages} " }
end
rescue StandardError => e
Rails.logger.error { "Failed to copy attachments from ##{from_container_id} to ##{to_container_id}: #{e}" }
Rails.logger.error { "Failed to copy attachments from ##{from_id} to ##{to_id}: #{e}" }
end
end
def attachment_copy_attributes(source, to_id)
source
.dup
.attributes
.except('file')
.merge('author_id' => user.id,
'container_id' => to_id)
end
end
end
end

@ -40,7 +40,7 @@ class FogFileUploader < CarrierWave::Uploader::Base
after :store, :delete_old_tmp_file
def copy_to(attachment)
attachment.remote_file_url = remote_file.url
attachment.file = local_file
end
def store_dir

@ -315,3 +315,11 @@ OPENPROJECT_WORK__PACKAGES__DURATION__FIELD__ACTIVE (default=false)
OPENPROJECT_WORK__PACKAGES__PROJECTS__EXPORT__LIMIT (default=500)
OPENPROJECT_YOUTUBE__CHANNEL (default="https://www.youtube.com/c/OpenProjectCommunity")
```
# Environment-specific configuration variables
## Docker
### PostgreSQL statement_timeout
In docker installations, there is a default `statement_timeout` of 90s set for the docker image. To override this value in case you're getting statement timeout errros such as "ERROR: canceling statement due to statement timeout", use the environment variable `POSTGRES_STATEMENT_TIMEOUT`

@ -8,22 +8,24 @@
<div class="spot-divider"></div>
<div class="spot-modal--body spot-container">
<spot-form-field [label]="text.projectLabel">
<p slot="input">{{ project.name }}</p>
<p slot="input" class="spot-body-small op-ium-summary--details">{{ project.name }}</p>
</spot-form-field>
<div class="op-ium-summary__row">
<spot-form-field [label]="text.principalLabel[type]">
<p slot="input">{{ principal?.name }}</p>
</spot-form-field>
<spot-form-field [label]="text.roleLabel()">
<p slot="input">{{ role.name }}</p>
</spot-form-field>
</div>
<spot-form-field [label]="text.principalLabel[type]">
<p slot="input" class="spot-body-small op-ium-summary--details">{{ principal?.name }}</p>
</spot-form-field>
<spot-form-field [label]="text.roleLabel()">
<p slot="input" class="spot-body-small op-ium-summary--details">{{ role.name }}</p>
</spot-form-field>
<spot-form-field
[label]="text.messageLabel"
*ngIf="type !== PrincipalType.Placeholder && message"
>
<p slot="input" class="op-ium-summary-message">{{ message }}</p>
<p slot="input" class="spot-body-small op-ium-summary--message">{{ message }}</p>
</spot-form-field>
</div>

@ -1,2 +1,6 @@
.op-ium-summary-message
white-space: pre-wrap
.op-ium-summary
&--message
white-space: pre-wrap
&--details
margin-bottom: 0

@ -99,7 +99,7 @@ export class OpModalWrapperAugmentService {
}
private appendIframe(body:JQuery<HTMLElement>, url:string) {
const iframe = jQuery('<iframe frameborder="0" height="400" allowfullscreen>></iframe>');
const iframe = jQuery('<iframe frameborder="0" height="350" allowfullscreen>></iframe>');
iframe.attr('src', url);
body.find(iframeSelector).append(iframe);

@ -31,9 +31,11 @@
display: flex
justify-content: space-between
flex-direction: column
margin-bottom: 0
.onboarding--video-text
line-height: 1.25
margin-bottom: 1.25rem
.onboarding--video
align-self: center

@ -55,6 +55,7 @@ module API
def to_h(column_key: :columns)
p = super
p[:includeSubprojects] = query.include_subprojects
p[:showHierarchies] = query.show_hierarchies
p[:showSums] = query.display_sums?
p[:groupBy] = query.group_by if query.group_by?

@ -157,7 +157,7 @@ class Meeting < ApplicationRecord
copy.set_initial_values
copy.participants.clear
copy.participants_attributes = participants.collect(&:copy_attributes)
copy.participants_attributes = allowed_participants.collect(&:copy_attributes)
copy
end
@ -212,6 +212,17 @@ class Meeting < ApplicationRecord
protected
# Participants of older meetings
# might contain users no longer in the project
#
# This returns the set currently allowed to view the meeting
def allowed_participants
available_members = User.allowed_members(:view_meetings, project).select(:id)
participants
.where(user_id: available_members)
end
def set_initial_values
# set defaults
write_attribute(:start_time, Date.tomorrow + 10.hours) if start_time.nil?

@ -222,5 +222,16 @@ describe Meeting, type: :model do
copy = meeting.copy({})
expect(copy.participants.all? { |p| p.id.nil? && !p.attended }).to be_truthy
end
context 'when old meeting as user no longer in project' do
before do
user2.memberships.destroy_all
end
it 'does not copy that user' do
copy = meeting.copy({})
expect(copy.participants.map(&:user_id)).to eq [user1.id]
end
end
end
end

@ -10,7 +10,7 @@
<div class="form--field -required -wide-label">
<%= styled_label_tag 'backup_code', t('two_factor_authentication.backup_codes.singular') %>
<div class="form--field-container">
<%= styled_text_field_tag 'backup_code', nil, required: true, autocomplete: 'off', size: 20, maxlength: 20, tabindex: 1, focus: true %>
<%= styled_text_field_tag 'backup_code', nil, required: true, autocomplete: 'off', size: 20, maxlength: 20, tabindex: 1, autofocus: true %>
</div>
</div>
<input type="submit" name="login" value="<%=t(:button_submit)%>" class="button -highlight" tabindex="2" />

@ -16,7 +16,7 @@
<div class="form--field -wide-label">
<%= styled_label_tag 'otp', t(:field_otp) %>
<div class="form--field-container">
<%= styled_text_field_tag 'otp', nil, autocomplete: 'off', size: 6, maxlength: 6, tabindex: 1, focus: true %>
<%= styled_text_field_tag 'otp', nil, autocomplete: 'off', size: 6, maxlength: 6, tabindex: 1, autofocus: true %>
</div>
</div>
<% if remember_2fa_enabled? %>

@ -11,7 +11,7 @@
<div class="form--field -required -wide-label">
<%= styled_label_tag 'otp', t(:field_otp) %>
<div class="form--field-container">
<%= styled_text_field_tag 'otp', nil, required: true, autocomplete: 'off', size: 6, maxlength: 6, tabindex: 1, focus: true %>
<%= styled_text_field_tag 'otp', nil, required: true, autocomplete: 'off', size: 6, maxlength: 6, tabindex: 1, autofocus: true %>
</div>
</div>
<div>

@ -112,4 +112,4 @@ fi
${CLI} scale web=1 worker=1 || true
# restart
service ${APP_NAME} restart
${APP_NAME} restart

@ -0,0 +1,55 @@
#-- 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.
#++
require 'spec_helper'
describe ::API::V3::Queries::QueryParamsRepresenter do
let(:query) { build_stubbed(:query, **params) }
let(:instance) { described_class.new(query) }
describe '#to_h' do
subject { instance.to_h }
context 'with include_subprojects true' do
let(:params) { { include_subprojects: true } }
it 'transports that to the params (Regression #44248)' do
expect(subject[:includeSubprojects]).to be true
end
end
context 'with include_subprojects false' do
let(:params) { { include_subprojects: false } }
it 'transports that to the params' do
expect(subject.keys).to include :includeSubprojects
expect(subject[:includeSubprojects]).to be false
end
end
end
end

@ -121,6 +121,7 @@ describe ::API::V3::Queries::QueryRepresenter do
offset: 1,
showSums: false,
showHierarchies: false,
includeSubprojects: true,
pageSize: Setting.per_page_options_array.first,
filters: []
}
@ -153,6 +154,7 @@ describe ::API::V3::Queries::QueryRepresenter do
pageSize: Setting.per_page_options_array.first,
showSums: false,
showHierarchies: false,
includeSubprojects: true,
filters: []
}
"#{api_v3_paths.work_packages}?#{non_empty_to_query(params)}"
@ -341,6 +343,7 @@ describe ::API::V3::Queries::QueryRepresenter do
filters: JSON::dump([{ subject: { operator: '~', values: ['bogus'] } }]),
showSums: false,
showHierarchies: false,
includeSubprojects: true,
groupBy: 'author',
sortBy: JSON::dump([%w[assignee asc], %w[type desc]])
}
@ -367,6 +370,7 @@ describe ::API::V3::Queries::QueryRepresenter do
pageSize: 25,
showSums: false,
showHierarchies: false,
includeSubprojects: true,
filters: []
}

Loading…
Cancel
Save