From 5f0d4df485bf99e0c9672ddb802ac2fd08e8a237 Mon Sep 17 00:00:00 2001 From: ulferts Date: Thu, 21 Jan 2021 10:36:23 +0100 Subject: [PATCH 01/24] Bumped version to 11.1.3 [ci skip] --- lib/open_project/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/open_project/version.rb b/lib/open_project/version.rb index eee4238ee9..01aea555e0 100644 --- a/lib/open_project/version.rb +++ b/lib/open_project/version.rb @@ -34,7 +34,7 @@ module OpenProject module VERSION #:nodoc: MAJOR = 11 MINOR = 1 - PATCH = 2 + PATCH = 3 TINY = PATCH # Redmine compat class << self From 8af2d6e5825b3f1a473eaece8a1569be7c498d45 Mon Sep 17 00:00:00 2001 From: ulferts Date: Thu, 21 Jan 2021 14:07:12 +0100 Subject: [PATCH 02/24] fix version links on roadmap (#8936) * adds an id to the version link to be anchorable * adds an achor element to the link in the version list * whitelists the possible filter parameters for the version list links The solution has an insufficiency in that the browser unnecessarily reloads the page if the user had filtered before and then clicks on a link. I find that acceptable. --- app/helpers/versions_helper.rb | 6 ++++++ app/views/versions/_roadmap_filter.html.erb | 1 - .../versions/_roadmap_version_links.html.erb | 5 ++++- app/views/versions/index.html.erb | 2 +- spec/helpers/versions_helper_spec.rb | 18 ++++++++++-------- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/app/helpers/versions_helper.rb b/app/helpers/versions_helper.rb index 3a483924b4..4e066603fa 100644 --- a/app/helpers/versions_helper.rb +++ b/app/helpers/versions_helper.rb @@ -41,6 +41,8 @@ module VersionsHelper def link_to_version(version, html_options = {}, options = {}) return '' unless version&.is_a?(Version) + html_options = html_options.merge(id: link_to_version_id(version)) + link_name = options[:before_text].to_s.html_safe + format_version_name(version, options[:project] || @project) link_to_if version.visible?, link_name, @@ -48,6 +50,10 @@ module VersionsHelper html_options end + def link_to_version_id(version) + ERB::Util.url_encode("version-#{version.name}") + end + def format_version_name(version, project = @project) h(version.to_s_for_project(project)) end diff --git a/app/views/versions/_roadmap_filter.html.erb b/app/views/versions/_roadmap_filter.html.erb index 981484787d..8420936c5b 100644 --- a/app/views/versions/_roadmap_filter.html.erb +++ b/app/views/versions/_roadmap_filter.html.erb @@ -21,7 +21,6 @@ <% if @project.descendants.active.any? %>
- <%= hidden_field_tag 'with_subprojects', 0 %>
<%= styled_label_tag "with-subprojects", t(:label_subproject_plural) %> diff --git a/app/views/versions/_roadmap_version_links.html.erb b/app/views/versions/_roadmap_version_links.html.erb index cbb415e44d..68c3b6814c 100644 --- a/app/views/versions/_roadmap_version_links.html.erb +++ b/app/views/versions/_roadmap_version_links.html.erb @@ -1,5 +1,8 @@

<%= t(:label_version_plural) %>

<% @versions.each do |version| %> - <%= link_to format_version_name(version), "#{project_roadmap_url}##{version.name}" %>
+ <%= link_to format_version_name(version), + project_roadmap_path({ anchor: link_to_version_id(version) }.merge(params.permit(:completed, + :with_subprojects, + type_ids: []).to_h)) %>
<% end %> diff --git a/app/views/versions/index.html.erb b/app/views/versions/index.html.erb index 974a2ae7cf..a7224a31eb 100644 --- a/app/views/versions/index.html.erb +++ b/app/views/versions/index.html.erb @@ -45,7 +45,7 @@ See docs/COPYRIGHT.rdoc for more details.
<% @versions.each do |version| %>

- <%= link_to_version version, name: h(version.name) %> + <%= link_to_version(version, name: h(version.name), id: "version-#{version.name}") %>

<%= render partial: 'versions/overview', locals: {version: version} %> <%= render(partial: "wiki/content", locals: {content: version.wiki_page.content}) if version.wiki_page %> diff --git a/spec/helpers/versions_helper_spec.rb b/spec/helpers/versions_helper_spec.rb index e566bc846c..dab981f94f 100644 --- a/spec/helpers/versions_helper_spec.rb +++ b/spec/helpers/versions_helper_spec.rb @@ -59,7 +59,8 @@ describe VersionsHelper, type: :helper do context 'a version' do context 'with being allowed to see the version' do it 'does not create a link, without permission' do - expect(link_to_version(version)).to eq("#{test_project.name} - #{version.name}") + expect(link_to_version(version)) + .to eq("#{test_project.name} - #{version.name}") end end @@ -71,21 +72,22 @@ describe VersionsHelper, type: :helper do end it 'generates a link' do - expect(link_to_version(version)).to eq("#{test_project.name} - #{version.name}") + expect(link_to_version(version)) + .to be_html_eql("#{test_project.name} - #{version.name}") end it 'generates a link within a project' do @project = test_project - expect(link_to_version(version)).to eq("#{version.name}") + expect(link_to_version(version)) + .to be_html_eql("#{version.name}") end end end - describe 'an invalid version' do - let(:version) { Object } - - it 'does not generate a link' do - expect(link_to_version(Object)).to be_empty + describe '#link_to_version_id' do + it 'generates an escaped id' do + expect(link_to_version_id(version)) + .to eql("version-#{ERB::Util.url_encode(version.name)}") end end end From a4daa3d361183f65f5c3f3b79367e8c4e84e09de Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Sat, 23 Jan 2021 09:48:23 +0000 Subject: [PATCH 03/24] update locales from crowdin [ci skip] --- modules/bim/config/locales/crowdin/uk.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/bim/config/locales/crowdin/uk.yml b/modules/bim/config/locales/crowdin/uk.yml index 7ec9d2ed68..33a9a86438 100644 --- a/modules/bim/config/locales/crowdin/uk.yml +++ b/modules/bim/config/locales/crowdin/uk.yml @@ -43,8 +43,8 @@ uk: invalid_statuses_found: 'Invalid status names found' invalid_priorities_found: 'Invalid priority names found' invalid_emails_found: 'Invalid email addresses found' - unknown_emails_found: 'Unknown email addresses found' - unknown_property: 'Unknown property' + unknown_emails_found: 'Знайдено невідомі адреси електронної пошти' + unknown_property: 'Невідома властивість' non_members_found: 'Non project members found' import_types_as: 'Set all these types to' import_statuses_as: 'Set all these statuses to' From 51a40c97eb0315fd2a5dd86dfd7333f9d8d15d92 Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Mon, 25 Jan 2021 09:33:05 +0000 Subject: [PATCH 04/24] set content type of attachments in S3 (#8938) * set content type of attachments in S3 * refactoring to allow amending and reading given metadata more easily * confirm attachment content type is sent to S3 --- app/uploaders/direct_fog_uploader.rb | 99 ++++++++++++------- app/uploaders/fog_file_uploader.rb | 10 ++ .../attachments_by_budget_resource_spec.rb | 10 +- .../attachments_by_documents_resource_spec.rb | 10 +- .../attachment_resource_shared_examples.rb | 39 +++++--- spec/requests/api/v3/attachments_spec.rb | 4 +- 6 files changed, 112 insertions(+), 60 deletions(-) diff --git a/app/uploaders/direct_fog_uploader.rb b/app/uploaders/direct_fog_uploader.rb index 037a3cea8b..a40748d279 100644 --- a/app/uploaders/direct_fog_uploader.rb +++ b/app/uploaders/direct_fog_uploader.rb @@ -3,50 +3,79 @@ require_relative 'fog_file_uploader' class DirectFogUploader < FogFileUploader include CarrierWaveDirect::Uploader - def self.for_attachment(attachment) - for_uploader attachment.file + ## + # This needs to be true so that the necessary condition is included + # in S3 upload policy (only relevant for direct uploads). + def will_include_content_type + true end - def self.for_uploader(fog_file_uploader) - raise ArgumentError, "FogFileUploader expected" unless fog_file_uploader.is_a? FogFileUploader + class << self + def for_attachment(attachment) + for_uploader attachment.file + end - uploader = self.new + def for_uploader(fog_file_uploader) + raise ArgumentError, "FogFileUploader expected" unless fog_file_uploader.is_a? FogFileUploader - uploader.instance_variable_set "@file", fog_file_uploader.file - uploader.instance_variable_set "@key", fog_file_uploader.path + uploader = self.new - uploader - end + uploader.instance_variable_set "@file", fog_file_uploader.file + uploader.instance_variable_set "@key", fog_file_uploader.path + uploader.instance_variable_set "@model", fog_file_uploader.model - ## - # Generates the direct upload form for the given attachment. - # - # @param attachment [Attachment] The attachment for which a file is to be uploaded. - # @param success_action_redirect [String] URL to redirect to if successful (none by default, using status). - # @param success_action_status [String] The HTTP status to return on success (201 by default). - # @param max_file_size [Integer] The maximum file size to be allowed in bytes. - def self.direct_fog_hash( - attachment:, - success_action_redirect: nil, - success_action_status: "201", - max_file_size: Setting.attachment_max_size * 1024 - ) - uploader = for_attachment attachment - - if success_action_redirect.present? - uploader.success_action_redirect = success_action_redirect - uploader.use_action_status = false - else - uploader.success_action_status = success_action_status - uploader.use_action_status = true + uploader + end + + ## + # Generates the direct upload form for the given attachment. + # + # @param attachment [Attachment] The attachment for which a file is to be uploaded. + # @param success_action_redirect [String] URL to redirect to if successful (none by default, using status). + # @param success_action_status [String] The HTTP status to return on success (201 by default). + # @param max_file_size [Integer] The maximum file size to be allowed in bytes. + def direct_fog_hash( + attachment:, + success_action_redirect: nil, + success_action_status: "201", + max_file_size: Setting.attachment_max_size * 1024 + ) + uploader = direct_fog_hash_uploader attachment, success_action_redirect, success_action_status + hash = uploader + .direct_fog_hash(enforce_utf8: false, max_file_size: max_file_size) + .merge(extra_fog_hash_attributes(uploader: uploader)) + + if success_action_redirect.present? + hash.merge(success_action_redirect: success_action_redirect) + else + hash.merge(success_action_status: success_action_status) + end + end + + def extra_fog_hash_attributes(uploader:) + return {} unless include_content_type?(uploader) + + { + "Content-Type": uploader.fog_attributes[:"Content-Type"] + } end - hash = uploader.direct_fog_hash(enforce_utf8: false, max_file_size: max_file_size) + private + + def include_content_type?(uploader) + uploader.will_include_content_type && uploader.fog_attributes.include?(:"Content-Type") + end - if success_action_redirect.present? - hash.merge(success_action_redirect: success_action_redirect) - else - hash.merge(success_action_status: success_action_status) + def direct_fog_hash_uploader(attachment, success_action_redirect, success_action_status) + for_attachment(attachment).tap do |uploader| + if success_action_redirect.present? + uploader.success_action_redirect = success_action_redirect + uploader.use_action_status = false + else + uploader.success_action_status = success_action_status + uploader.use_action_status = true + end + end end end end diff --git a/app/uploaders/fog_file_uploader.rb b/app/uploaders/fog_file_uploader.rb index ecff0bca84..253339de01 100644 --- a/app/uploaders/fog_file_uploader.rb +++ b/app/uploaders/fog_file_uploader.rb @@ -57,6 +57,16 @@ class FogFileUploader < CarrierWave::Uploader::Base super end + ## + # This is necessary for carrierwave to set the Content-Type in the S3 metadata for instance. + def fog_attributes + content_type = model.content_type + + return super if content_type.blank? + + super.merge "Content-Type": content_type + end + ## # Generates a download URL for this file. # diff --git a/modules/costs/spec/requests/api/attachments/attachments_by_budget_resource_spec.rb b/modules/costs/spec/requests/api/attachments/attachments_by_budget_resource_spec.rb index 911c3958c9..207eb52a2a 100644 --- a/modules/costs/spec/requests/api/attachments/attachments_by_budget_resource_spec.rb +++ b/modules/costs/spec/requests/api/attachments/attachments_by_budget_resource_spec.rb @@ -68,8 +68,8 @@ describe 'API v3 Attachments by budget resource', type: :request do let(:permissions) { %i[view_budgets edit_budgets] } let(:request_path) { api_v3_paths.attachments_by_budget budget.id } - let(:request_parts) { { metadata: metadata, file: file } } - let(:metadata) { { fileName: 'cat.png' }.to_json } + let(:request_parts) { { metadata: metadata.to_json, file: file } } + let(:metadata) { { fileName: 'cat.png' } } let(:file) { mock_uploaded_file(name: 'original-filename.txt') } let(:max_file_size) { 1 } # given in kiB @@ -99,19 +99,19 @@ describe 'API v3 Attachments by budget resource', type: :request do context 'file section is missing' do # rack-test won't send a multipart request without a file being present # however as long as we depend on correctly named sections this test should do just fine - let(:request_parts) { { metadata: metadata, wrongFileSection: file } } + let(:request_parts) { { metadata: metadata.to_json, wrongFileSection: file } } it_behaves_like 'invalid request body', I18n.t('api_v3.errors.multipart_body_error') end context 'metadata section is no valid JSON' do - let(:metadata) { '"fileName": "cat.png"' } + let(:request_parts) { { metadata: '"fileName": "cat.png"', file: file } } it_behaves_like 'parse error' end context 'metadata is missing the fileName' do - let(:metadata) { Hash.new.to_json } + let(:metadata) { Hash.new } it_behaves_like 'constraint violation' do let(:message) { "fileName #{I18n.t('activerecord.errors.messages.blank')}" } diff --git a/modules/documents/spec/requests/api/v3/attachments/attachments_by_documents_resource_spec.rb b/modules/documents/spec/requests/api/v3/attachments/attachments_by_documents_resource_spec.rb index 5d842fb594..9d331d7926 100644 --- a/modules/documents/spec/requests/api/v3/attachments/attachments_by_documents_resource_spec.rb +++ b/modules/documents/spec/requests/api/v3/attachments/attachments_by_documents_resource_spec.rb @@ -69,8 +69,8 @@ describe 'API v3 Attachments by document resource', type: :request do let(:permissions) { %i[view_documents manage_documents] } let(:request_path) { api_v3_paths.attachments_by_document document.id } - let(:request_parts) { { metadata: metadata, file: file } } - let(:metadata) { { fileName: 'cat.png' }.to_json } + let(:request_parts) { { metadata: metadata.to_json, file: file } } + let(:metadata) { { fileName: 'cat.png' } } let(:file) { mock_uploaded_file(name: 'original-filename.txt') } let(:max_file_size) { 1 } # given in kiB @@ -100,19 +100,19 @@ describe 'API v3 Attachments by document resource', type: :request do context 'file section is missing' do # rack-test won't send a multipart request without a file being present # however as long as we depend on correctly named sections this test should do just fine - let(:request_parts) { { metadata: metadata, wrongFileSection: file } } + let(:request_parts) { { metadata: metadata.to_json, wrongFileSection: file } } it_behaves_like 'invalid request body', I18n.t('api_v3.errors.multipart_body_error') end context 'metadata section is no valid JSON' do - let(:metadata) { '"fileName": "cat.png"' } + let(:request_parts) { { metadata: '"fileName": "cat.png"', file: file } } it_behaves_like 'parse error' end context 'metadata is missing the fileName' do - let(:metadata) { Hash.new.to_json } + let(:metadata) { Hash.new } it_behaves_like 'constraint violation' do let(:message) { "fileName #{I18n.t('activerecord.errors.messages.blank')}" } diff --git a/spec/requests/api/v3/attachments/attachment_resource_shared_examples.rb b/spec/requests/api/v3/attachments/attachment_resource_shared_examples.rb index cf4a6fbb82..1f3a1af56c 100644 --- a/spec/requests/api/v3/attachments/attachment_resource_shared_examples.rb +++ b/spec/requests/api/v3/attachments/attachment_resource_shared_examples.rb @@ -42,8 +42,8 @@ shared_examples 'it supports direct uploads' do end describe 'POST /prepare', with_settings: { attachment_max_size: 512 } do - let(:request_parts) { { metadata: metadata, file: file } } - let(:metadata) { { fileName: 'cat.png', fileSize: file.size }.to_json } + let(:request_parts) { { metadata: metadata.to_json, file: file } } + let(:metadata) { { fileName: 'cat.png', fileSize: file.size, contentType: 'image/png' } } let(:file) { mock_uploaded_file(name: 'original-filename.txt') } def request! @@ -68,7 +68,7 @@ shared_examples 'it supports direct uploads' do end context 'with no filesize metadata' do - let(:metadata) { { fileName: 'cat.png' }.to_json } + let(:metadata) { { fileName: 'cat.png' } } it 'should respond with 422 due to missing file size metadata' do expect(subject.status).to eq(422) @@ -125,8 +125,21 @@ shared_examples 'it supports direct uploads' do "success_action_status" ) + expect(fields["Content-Type"]).to eq metadata[:contentType] + expect(fields["key"]).to end_with "cat.png" end + + it 'should also include the content type and the necessary policy in the form fields' do + fields = link["form_fields"] + + expect(fields).to include("policy", "Content-Type") + expect(fields["Content-Type"]).to eq metadata[:contentType] + + policy = Base64.decode64 fields["policy"] + + expect(policy).to include '["starts-with","$Content-Type",""]' + end end end end @@ -214,8 +227,8 @@ shared_examples 'an APIv3 attachment resource', type: :request, content_type: :j let(:permissions) { Array(update_permission) } let(:request_path) { api_v3_paths.attachments } - let(:request_parts) { { metadata: metadata, file: file } } - let(:metadata) { { fileName: 'cat.png' }.to_json } + let(:request_parts) { { metadata: metadata.to_json, file: file } } + let(:metadata) { { fileName: 'cat.png' } } let(:file) { mock_uploaded_file(name: 'original-filename.txt') } let(:max_file_size) { 1 } # given in kiB @@ -248,19 +261,19 @@ shared_examples 'an APIv3 attachment resource', type: :request, content_type: :j context 'file section is missing' do # rack-test won't send a multipart request without a file being present # however as long as we depend on correctly named sections this test should do just fine - let(:request_parts) { { metadata: metadata, wrongFileSection: file } } + let(:request_parts) { { metadata: metadata.to_json, wrongFileSection: file } } it_behaves_like 'invalid request body', I18n.t('api_v3.errors.multipart_body_error') end context 'metadata section is no valid JSON' do - let(:metadata) { '"fileName": "cat.png"' } + let(:request_parts) { { metadata: '"fileName": "cat.png"', file: file } } it_behaves_like 'parse error' end context 'metadata is missing the fileName' do - let(:metadata) { Hash.new.to_json } + let(:metadata) { Hash.new } it_behaves_like 'constraint violation' do let(:message) { "fileName #{I18n.t('activerecord.errors.messages.blank')}" } @@ -496,8 +509,8 @@ shared_examples 'an APIv3 attachment resource', type: :request, content_type: :j describe '#post' do let(:request_path) { api_v3_paths.send "attachments_by_#{attachment_type}", container.id } - let(:request_parts) { { metadata: metadata, file: file } } - let(:metadata) { { fileName: 'cat.png' }.to_json } + let(:request_parts) { { metadata: metadata.to_json, file: file } } + let(:metadata) { { fileName: 'cat.png' } } let(:file) { mock_uploaded_file(name: 'original-filename.txt') } let(:max_file_size) { 1 } # given in kiB @@ -527,19 +540,19 @@ shared_examples 'an APIv3 attachment resource', type: :request, content_type: :j context 'file section is missing' do # rack-test won't send a multipart request without a file being present # however as long as we depend on correctly named sections this test should do just fine - let(:request_parts) { { metadata: metadata, wrongFileSection: file } } + let(:request_parts) { { metadata: metadata.to_json, wrongFileSection: file } } it_behaves_like 'invalid request body', I18n.t('api_v3.errors.multipart_body_error') end context 'metadata section is no valid JSON' do - let(:metadata) { '"fileName": "cat.png"' } + let(:request_parts) { { metadata: '"fileName": "cat.png"', file: file } } it_behaves_like 'parse error' end context 'metadata is missing the fileName' do - let(:metadata) { Hash.new.to_json } + let(:metadata) { Hash.new } it_behaves_like 'constraint violation' do let(:message) { "fileName #{I18n.t('activerecord.errors.messages.blank')}" } diff --git a/spec/requests/api/v3/attachments_spec.rb b/spec/requests/api/v3/attachments_spec.rb index 3940f03423..dd1f7c4eb1 100644 --- a/spec/requests/api/v3/attachments_spec.rb +++ b/spec/requests/api/v3/attachments_spec.rb @@ -50,8 +50,8 @@ describe API::V3::Attachments::AttachmentsAPI, type: :request do let(:permissions) { [] } let(:request_path) { api_v3_paths.prepare_new_attachment_upload } - let(:request_parts) { { metadata: metadata, file: file } } - let(:metadata) { { fileName: 'cat.png' }.to_json } + let(:request_parts) { { metadata: metadata.to_json, file: file } } + let(:metadata) { { fileName: 'cat.png' } } let(:file) { mock_uploaded_file(name: 'original-filename.txt') } before do From 371afb4a1ed41fd34a4d6b24a14990846e48e1ee Mon Sep 17 00:00:00 2001 From: ulferts Date: Mon, 25 Jan 2021 15:31:17 +0100 Subject: [PATCH 05/24] fix example request on memberships create --- docs/api/apiv3/endpoints/members.apib | 28 ++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/api/apiv3/endpoints/members.apib b/docs/api/apiv3/endpoints/members.apib index 332f8684a1..f8bf53e19c 100644 --- a/docs/api/apiv3/endpoints/members.apib +++ b/docs/api/apiv3/endpoints/members.apib @@ -113,20 +113,22 @@ You can use the form and schema to be retrieve the valid attribute values and by + Body { - "project": { - "href": "/api/v3/projects/1" - }, - "principal": { - "href": "/api/v3/users/5" - }, - "roles": [ - { - "href": "/api/v3/roles/5" - }, - { - "href": "/api/v3/roles/8" + "_links": { + "project": { + "href": "/api/v3/projects/1" + }, + "principal": { + "href": "/api/v3/users/5" + }, + "roles": [ + { + "href": "/api/v3/roles/5" + }, + { + "href": "/api/v3/roles/8" + } + ] } - ] } + Response 201 From af48244ffd735cc82b99b6302b3f39072aa95404 Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Mon, 25 Jan 2021 10:06:28 +0000 Subject: [PATCH 06/24] make download URL expiry configurable, use safer default --- app/uploaders/fog_file_uploader.rb | 3 +-- .../configuration/README.md | 16 ++++++++++++++++ lib/open_project/configuration.rb | 1 + spec/models/attachment_spec.rb | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/app/uploaders/fog_file_uploader.rb b/app/uploaders/fog_file_uploader.rb index 253339de01..bde1916211 100644 --- a/app/uploaders/fog_file_uploader.rb +++ b/app/uploaders/fog_file_uploader.rb @@ -114,8 +114,7 @@ class FogFileUploader < CarrierWave::Uploader::Base def set_expires_at!(url_options, options:) if options[:expires_in].present? - # AWS allows at max < 604800 expires time - expires = [options[:expires_in], 604799].min + expires = [options[:expires_in], OpenProject::Configuration.fog_download_url_expires_in].min url_options[:expire_at] = ::Fog::Time.now + expires end diff --git a/docs/installation-and-operations/configuration/README.md b/docs/installation-and-operations/configuration/README.md index c8af4b70bc..d47c8e23d1 100644 --- a/docs/installation-and-operations/configuration/README.md +++ b/docs/installation-and-operations/configuration/README.md @@ -39,6 +39,7 @@ Configuring OpenProject through environment variables is detailed [in this separ * [`disable_password_login`](#disable-password-login) (default: false) * [`attachments_storage`](#attachments-storage) (default: file) * [`direct_uploads`](#direct-uploads) (default: true) +* [`fog_download_url_expires_in`](#fog-download-url-expires-in) (default: 21600) * [`hidden_menu_items`](#hidden-menu-items) (default: {}) * [`disabled_modules`](#disabled-modules) (default: []) * [`blacklisted_routes`](#blacklisted-routes) (default: []) @@ -188,6 +189,21 @@ to the remote storage in an extra step. **Note**: This only works for S3 right now. When using fog with another provider this configuration will be `false`. The same goes for when no fog storage is configured. +### fog download url expires in + +*default: 21600* + +Example: + + fog_download_url_expires_in: 60 + +When using remote storage for attachments via fog - usually S3 (see [`attachments_storage`](#attachments-storage) option) - +each attachment download will generate a temporary URL. +This option determines how long these links will be valid. + +The default is 21600 seconds, that is 6 hours, which is the maximum expiry time +allowed by S3 when using IAM roles for authentication. + ### Overriding the help link You can override the default help menu of OpenProject by specifying a `force_help_link` option to diff --git a/lib/open_project/configuration.rb b/lib/open_project/configuration.rb index 63b664b6b7..ed240d13f8 100644 --- a/lib/open_project/configuration.rb +++ b/lib/open_project/configuration.rb @@ -50,6 +50,7 @@ module OpenProject # which will be uploaded directly to the cloud storage rather than via OpenProject's # server process. 'direct_uploads' => true, + 'fog_download_url_expires_in' => 21600, # 6h by default as 6 hours is max in S3 when using IAM roles 'show_community_links' => true, 'log_level' => 'info', 'scm_git_command' => nil, diff --git a/spec/models/attachment_spec.rb b/spec/models/attachment_spec.rb index 4993ad7944..6dc4c1971e 100644 --- a/spec/models/attachment_spec.rb +++ b/spec/models/attachment_spec.rb @@ -318,7 +318,7 @@ describe Attachment, type: :model do let(:url_options) { { expires_in: 1.year } } it "uses the allowed max" do - expect(query).to include "X-Amz-Expires=604799" + expect(query).to include "X-Amz-Expires=#{OpenProject::Configuration.fog_download_url_expires_in}" end end end From 7a05dfd56f14d819ea2d83fc749538f94e7f1f25 Mon Sep 17 00:00:00 2001 From: ML-OpenP Date: Tue, 26 Jan 2021 11:20:13 +0100 Subject: [PATCH 07/24] add behavior of default settings in filtered work packages lists [ci skip] --- .../work-packages/work-package-table-configuration/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/user-guide/work-packages/work-package-table-configuration/README.md b/docs/user-guide/work-packages/work-package-table-configuration/README.md index b327d68086..6d3c69d046 100644 --- a/docs/user-guide/work-packages/work-package-table-configuration/README.md +++ b/docs/user-guide/work-packages/work-package-table-configuration/README.md @@ -73,6 +73,10 @@ The results will be displayed accordingly in the work package list. ![filter-text](filter-text.png) + + ## Sort the work package list ### Automatic sorting of the work package list From b04bdca413994a04a071f02b1643be67cde4b193 Mon Sep 17 00:00:00 2001 From: ML-OpenP Date: Tue, 26 Jan 2021 11:29:28 +0100 Subject: [PATCH 08/24] add info for unlocking users and small additions [ci skip] --- .../users-permissions/users/README.md | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/docs/system-admin-guide/users-permissions/users/README.md b/docs/system-admin-guide/users-permissions/users/README.md index dbaacf7bf7..d59fd0197a 100644 --- a/docs/system-admin-guide/users-permissions/users/README.md +++ b/docs/system-admin-guide/users-permissions/users/README.md @@ -4,7 +4,7 @@ sidebar_navigation: priority: 990 description: Manage users in OpenProject. robots: index, follow -keywords: manage users +keywords: manage users, lock, unlock, invite, language --- # Manage Users @@ -16,14 +16,14 @@ The users list provides an overview of all users in OpenProject. You can create
-| Topic | Content | -| --------------------------------------------- | ------------------------------------------------------------ | -| [User list](#user-list) | Manage all users in OpenProject. | -| [Lock users](#lock-users) | Block a user permanently in the system. | -| [Filter users](#filter-users) | Filter users in the list. | -| [Invite new users](#invite-new-users) | Add new users to your OpenProject and invite them via email. Resend and delete user invitations. | -| [Manage user settings](#manage-user-settings) | Manage user settings, e.g. language, projects, groups, global roles, rate history, avatar, two-factor authentication. | -| [Delete users](#delete-users) | Delete a user from the system. | +| Topic | Content | +| ----------------------------------------------- | ------------------------------------------------------------ | +| [User list](#user-list) | Manage all users in OpenProject. | +| [Lock and unlock users](#lock-and-unlock-users) | Block a user permanently in the system or unlock a user. | +| [Filter users](#filter-users) | Filter users in the list. | +| [Invite new users](#invite-new-users) | Add new users to your OpenProject and invite them via email. Resend and delete user invitations. | +| [Manage user settings](#manage-user-settings) | Manage user settings, e.g. language, projects, groups, global roles, rate history, avatar, two-factor authentication. | +| [Delete users](#delete-users) | Delete a user from the system. | ## User list @@ -35,18 +35,21 @@ Also, you get the information when the user has been created, and when the user ![user list](image-20200211141841492.png) -## Lock users +## Lock and unlock users If you want to **block users permanently** in the system, you can click the **Lock permanently** link next to a user. -If you are using the [OpenProject Cloud Edition](../../../cloud-edition-guide), you will then have a new user available to add to the system within your booked plan. +If you are using [Enterprise cloud](../../../cloud-edition-guide) or [Enterprise on-premises](../../../enterprise-edition-guide) you will then have a new user available to add to the system within your booked plan. ![System-admin-guide_lock-users](System-admin-guide_lock-users.png) +The way to unlock users is basically the same. Use the **Unlock** link at the right. +Here you can also **unlock users who have been locked temporarily due to multiple failed login attempts**. + ## Filter users Especiall if you have a very long user list, it is essential to filter in this list. From 8656ae3987297f1f6e91ed07a67e454b30d5efd7 Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Wed, 27 Jan 2021 11:22:37 +0000 Subject: [PATCH 09/24] clarification for external ssl termination --- docs/installation-and-operations/configuration/ssl/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/installation-and-operations/configuration/ssl/README.md b/docs/installation-and-operations/configuration/ssl/README.md index 6b164379f1..5743f900ac 100644 --- a/docs/installation-and-operations/configuration/ssl/README.md +++ b/docs/installation-and-operations/configuration/ssl/README.md @@ -63,7 +63,7 @@ This will execute `certbot renew` every day at 1am. The command checks if the ce ## External SSL termination -If you terminate SSL externally before the request hits the OpenProject server, you need to let the OpenProject server know that the request being handled is https, even though SSL was terminated before. This is the most common source in problems in OpenProject when using an external server that terminates SSL. +If you terminate SSL externally1 before the request hits the OpenProject server, you need to let the OpenProject server know that the request being handled is https, even though SSL was terminated before. This is the most common source in problems in OpenProject when using an external server that terminates SSL. Please ensure that if you're proxying to the openproject server, you set the HOST header to the internal server. This ensures that the host name of the outer request gets forwarded to the internal server. Otherwise you might see redirects in your browser to the internal host that OpenProject is running on. @@ -83,3 +83,6 @@ If you're terminating SSL on the outer server, you need to set the `X-Forwarded- Finally, to let OpenProject know that it should create links with 'https' when no request is available (for example, when sending emails), you need to set the Protocol setting of OpenProject to `https`. You will find this setting on your system settings or via the rails console with `Setting.protocol = 'https'` + + +_1 In the packaged installation this means you selected "no" when asked for SSL in the configuration wizard but at the same time take care of SSL termination elsewhere. This can be a manual Apache setup on the same server (not recommended) or an external server, for instance._ From 434fec7f19ef4a7c22ad16de4d98c9bf29d9edd5 Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Wed, 27 Jan 2021 14:31:07 +0000 Subject: [PATCH 10/24] emphasize that you have to configure before configure to switch to BIM after an upgrade --- .../changing-to-bim-edition/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/installation-and-operations/changing-to-bim-edition/README.md b/docs/installation-and-operations/changing-to-bim-edition/README.md index c30c0158b5..b2a8852ea6 100644 --- a/docs/installation-and-operations/changing-to-bim-edition/README.md +++ b/docs/installation-and-operations/changing-to-bim-edition/README.md @@ -19,6 +19,7 @@ when you activate the "BCF" module a project's settings. ### Backup and upgrade First, backup your data and update your installation to the latest OpenProject version as described in [Upgrading](../operation/upgrading). +Make sure that you not only install the new package but also run `sudo openproject configure` as described before proceeding. ### Switching to BIM Edition From 03d97cb678eea95f0eba793e2f1e11d5a4ae0c01 Mon Sep 17 00:00:00 2001 From: ML-OpenP Date: Wed, 27 Jan 2021 15:34:23 +0100 Subject: [PATCH 11/24] added link to choose BIM during installation [ci skip] --- .../changing-to-bim-edition/README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/installation-and-operations/changing-to-bim-edition/README.md b/docs/installation-and-operations/changing-to-bim-edition/README.md index b2a8852ea6..deef3d3ea0 100644 --- a/docs/installation-and-operations/changing-to-bim-edition/README.md +++ b/docs/installation-and-operations/changing-to-bim-edition/README.md @@ -6,13 +6,11 @@ sidebar_navigation: # Changing to BIM Edition -An existing OpenProject on-premises (self hosted) installation can easily be switched to the BIM Edition. -The BIM Edition extends the capabilities of a normal OpenProject installation with special features -for the construction industry. +An existing OpenProject on-premises (self hosted) installation can easily be switched to the BIM Edition. The BIM Edition extends the capabilities of a normal OpenProject installation with special features for the construction industry. -Switching to the BIM Edition will not affect your existing data. Your team will be able to continue -working just as before. By switching to the BIM edition additional features will become available -when you activate the "BCF" module a project's settings. +Switching to the BIM Edition will not affect your existing data. Your team will be able to continue working just as before. By switching to the BIM edition additional features will become available when you activate the "BCF" module in the [project's settings](../../user-guide/projects/project-settings/modules). + +To choose the BIM edition during installation use [this instruction](../installation/packaged/#step-1-select-your-openproject-edition). ## Instructions From 5a2982bed6a2f3fdf2f88e81a9d6c04de46fcf33 Mon Sep 17 00:00:00 2001 From: ulferts Date: Thu, 28 Jan 2021 09:08:04 +0100 Subject: [PATCH 12/24] add delimiter to specified content type --- docs/api/apiv3/endpoints/attachments.apib | 8 ++++---- docs/api/apiv3/forms.apib | 1 - docs/api/apiv3/index.apib | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/api/apiv3/endpoints/attachments.apib b/docs/api/apiv3/endpoints/attachments.apib index e2edceb74d..6e1ca66d2b 100644 --- a/docs/api/apiv3/endpoints/attachments.apib +++ b/docs/api/apiv3/endpoints/attachments.apib @@ -49,7 +49,7 @@ The body *must* be the raw content of the file. Note that a `filename` *must* be indicated in the `Content-Disposition` of this part, although it will be ignored. Instead the `fileName` inside the JSON of the metadata part will be used. -+ Request (multipart/form-data) ++ Request (multipart/form-data; boundary=boundary-delimiter) --boundary-delimiter Content-Disposition: form-data; name="metadata" @@ -332,7 +332,7 @@ See [the general specification for uploading attachments](#attachments-attachmen + Parameters + id (required, integer, `1`) ... ID of the post to receive the attachment -+ Request (multipart/form-data) ++ Request (multipart/form-data; boundary=boundary-delimiter) --boundary-delimiter Content-Disposition: form-data; name="metadata" @@ -613,7 +613,7 @@ See [the general specification for uploading attachments](#attachments-attachmen + Parameters + id (required, integer, `1`) ... ID of the wiki page to receive the attachment -+ Request (multipart/form-data) ++ Request (multipart/form-data; boundary=boundary-delimiter) --boundary-delimiter Content-Disposition: form-data; name="metadata" @@ -924,7 +924,7 @@ Instead the `fileName` inside the JSON of the metadata part will be used. + Parameters + id (required, integer, `1`) ... ID of the work package to receive the attachment -+ Request (multipart/form-data) ++ Request (multipart/form-data; boundary=boundary-delimiter) --boundary-delimiter Content-Disposition: form-data; name="metadata" diff --git a/docs/api/apiv3/forms.apib b/docs/api/apiv3/forms.apib index 6a4df00906..034ce2d7a1 100644 --- a/docs/api/apiv3/forms.apib +++ b/docs/api/apiv3/forms.apib @@ -1,4 +1,3 @@ - # Group Forms This API provides forms as a concept to aid in editing or creating resources. The goal of forms is to: diff --git a/docs/api/apiv3/index.apib b/docs/api/apiv3/index.apib index fb3e594dcb..577ecd185f 100644 --- a/docs/api/apiv3/index.apib +++ b/docs/api/apiv3/index.apib @@ -1,7 +1,8 @@ - + + @@ -11,7 +12,6 @@ - From 1c8aaf031f392266e1f733feda2f44e10512e7b3 Mon Sep 17 00:00:00 2001 From: Markus Kahl Date: Thu, 28 Jan 2021 12:39:38 +0000 Subject: [PATCH 13/24] Maintenance: ruby patch level update to 2.7.2 (#8951) * Update ruby to 2.7.2 * make sure to pull latest base image * minor comment update --- .github/workflows/docker.yml | 2 ++ .ruby-version | 2 +- .travis.yml | 2 +- Gemfile | 2 +- Gemfile.lock | 2 +- app/models/work_package/exporter/csv.rb | 2 +- docker/dev/backend/Dockerfile | 2 +- docker/prod/Dockerfile | 2 +- docs/development/development-environment-osx/README.md | 8 ++++---- docs/development/development-environment-ubuntu/README.md | 8 ++++---- .../installation/manual/README.md | 6 +++--- 11 files changed, 20 insertions(+), 18 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 548195018b..9589629cb4 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,6 +12,8 @@ jobs: # restrict this job to base repo for now if: github.repository == 'opf/openproject' runs-on: ubuntu-latest + env: + INPUT_BUILDOPTIONS: --pull steps: - uses: actions/checkout@master - name: Prepare docker files diff --git a/.ruby-version b/.ruby-version index 860487ca19..37c2961c24 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.1 +2.7.2 diff --git a/.travis.yml b/.travis.yml index 9c5450b24f..640b3be621 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ language: ruby rvm: - - 2.7.1 + - 2.7.2 sudo: required dist: xenial diff --git a/Gemfile b/Gemfile index c71a816429..4da6b15c17 100644 --- a/Gemfile +++ b/Gemfile @@ -28,7 +28,7 @@ source 'https://rubygems.org' -ruby '~> 2.7.1' +ruby '~> 2.7.2' gem 'actionpack-xml_parser', '~> 2.0.0' gem 'activemodel-serializers-xml', '~> 1.0.1' diff --git a/Gemfile.lock b/Gemfile.lock index 06c68660dd..6b49a3af29 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1081,7 +1081,7 @@ DEPENDENCIES with_advisory_lock (~> 4.6.0) RUBY VERSION - ruby 2.7.1p83 + ruby 2.7.2p137 BUNDLED WITH 2.1.4 diff --git a/app/models/work_package/exporter/csv.rb b/app/models/work_package/exporter/csv.rb index 7656b4611f..262d779e57 100644 --- a/app/models/work_package/exporter/csv.rb +++ b/app/models/work_package/exporter/csv.rb @@ -118,7 +118,7 @@ class WorkPackage::Exporter::CSV < WorkPackage::Exporter::Base when Time format_time(value) when nil - # ruby 2.7.1 will return a frozen string for nil.to_s which will cause an error when e.g. trying to + # ruby >=2.7.1 will return a frozen string for nil.to_s which will cause an error when e.g. trying to # force an encoding '' else diff --git a/docker/dev/backend/Dockerfile b/docker/dev/backend/Dockerfile index 6da9945ee6..0061587acb 100644 --- a/docker/dev/backend/Dockerfile +++ b/docker/dev/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.7.1-buster as develop +FROM ruby:2.7.2-buster as develop MAINTAINER operations@openproject.com ARG DEV_UID=1000 diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index 6d3d85e2c0..c438633667 100644 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.7.1-buster +FROM ruby:2.7.2-buster MAINTAINER operations@openproject.com # Allow platform-specific additions. Valid values are: on-prem,saas,bahn diff --git a/docs/development/development-environment-osx/README.md b/docs/development/development-environment-osx/README.md index ba0dc50615..9a7a4a6d41 100644 --- a/docs/development/development-environment-osx/README.md +++ b/docs/development/development-environment-osx/README.md @@ -32,20 +32,20 @@ $ rbenv init **Installing ruby-2.7** With both installed, we can now install the actual ruby version 2.7. You can check available ruby versions with `rbenv install --list`. -At the time of this writing, the latest stable version is `2.7.1`, which we also require. +At the time of this writing, the latest stable version is `2.7.2`, which we also require. We suggest you install the version we require in the [Gemfile](https://github.com/opf/openproject/blob/dev/Gemfile). Search for the `ruby '~> X.Y.Z'` line and install that version. ```bash # Install the required version as read from the Gemfile -rbenv install 2.7.1 +rbenv install 2.7.2 ``` This might take a while depending on whether ruby is built from source. After it is complete, you need to tell rbenv to globally activate this version ```bash -rbenv global 2.7.1 +rbenv global 2.7.2 ``` You also need to install [bundler](https://github.com/bundler/bundler/), the ruby gem bundler. @@ -110,7 +110,7 @@ You should now have an active ruby and node installation. Verify that it works w ```bash $ ruby --version -ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin16] +ruby 2.7.2p137 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin16] $ bundler --version Bundler version 2.0.2 diff --git a/docs/development/development-environment-ubuntu/README.md b/docs/development/development-environment-ubuntu/README.md index e19fc76189..e804c9f2e6 100644 --- a/docs/development/development-environment-ubuntu/README.md +++ b/docs/development/development-environment-ubuntu/README.md @@ -54,20 +54,20 @@ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build **Installing ruby-2.7** With both installed, we can now install the actual ruby version 2.7. You can check available ruby versions with `rbenv install --list`. -At the time of this writing, the latest stable version is `2.7.1`, which we also require. +At the time of this writing, the latest stable version is `2.7.2`, which we also require. We suggest you install the version we require in the [Gemfile](https://github.com/opf/openproject/blob/dev/Gemfile). Search for the `ruby '~> X.Y.Z'` line and install that version. ```bash # Install the required version as read from the Gemfile -rbenv install 2.7.1 +rbenv install 2.7.2 ``` This might take a while depending on whether ruby is built from source. After it is complete, you need to tell rbenv to globally activate this version ```bash -rbenv global 2.7.1 +rbenv global 2.7.2 rbenv rehash ``` @@ -149,7 +149,7 @@ You should now have an active ruby and node installation. Verify that it works w ```bash ruby --version -ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux] +ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-linux] bundler --version Bundler version 2.0.2 diff --git a/docs/installation-and-operations/installation/manual/README.md b/docs/installation-and-operations/installation/manual/README.md index 5cd78d8d02..9b07dbce57 100644 --- a/docs/installation-and-operations/installation/manual/README.md +++ b/docs/installation-and-operations/installation/manual/README.md @@ -106,16 +106,16 @@ time to finish. [openproject@host] source ~/.profile [openproject@host] git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build -[openproject@host] rbenv install 2.7.1 +[openproject@host] rbenv install 2.7.2 [openproject@host] rbenv rehash -[openproject@host] rbenv global 2.7.1 +[openproject@host] rbenv global 2.7.2 ``` To check our Ruby installation we run `ruby --version`. It should output something very similar to: ``` -ruby 2.7.1pXYZ (....) [x86_64-linux] +ruby 2.7.2pXYZ (....) [x86_64-linux] ``` ## Installation of Node From ef948465a14f1cf1edf8c73aa81128a7465db942 Mon Sep 17 00:00:00 2001 From: ulferts Date: Fri, 29 Jan 2021 15:47:19 +0100 Subject: [PATCH 14/24] fix atom export (#8952) The feed is opened in a new window so that the url can then be copied into a client while the original view persisted. The solution is not optimal as it requires to call the backend twice but as this function should be used very little, it should be enough --- .../export-modal/wp-table-export.modal.ts | 19 ++++++++++--- spec/features/work_packages/export_spec.rb | 27 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/components/modals/export-modal/wp-table-export.modal.ts b/frontend/src/app/components/modals/export-modal/wp-table-export.modal.ts index 8d5e650f8b..0df2460b2a 100644 --- a/frontend/src/app/components/modals/export-modal/wp-table-export.modal.ts +++ b/frontend/src/app/components/modals/export-modal/wp-table-export.modal.ts @@ -8,7 +8,7 @@ import {HalLink} from "core-app/modules/hal/hal-link/hal-link"; import {I18nService} from "core-app/modules/common/i18n/i18n.service"; import {OpModalLocalsToken} from "core-components/op-modals/op-modal.service"; import * as URI from 'urijs'; -import {HttpClient} from '@angular/common/http'; +import {HttpClient, HttpErrorResponse} from '@angular/common/http'; import {LoadingIndicatorService} from "core-app/modules/common/loading-indicator/loading-indicator.service"; import {Observable} from 'rxjs'; import {NotificationsService} from "core-app/modules/common/notifications/notifications.service"; @@ -105,8 +105,21 @@ export class WpTableExportModal extends OpModalComponent implements OnInit { this.service.show(JobStatusModal, 'global', { jobId: jobId }); } - private handleError(error:string) { - this.notifications.addError(error || this.I18n.t('js.error.internal')); + private handleError(error:HttpErrorResponse) { + // There was an error but the status code is actually a 200. + // If that is the case the response's content-type probably does not match + // the expected type (json). + // Currently this happens e.g. when exporting Atom which actually is not an export + // but rather a feed to follow. + if (error.status === 200 && error.url) { + window.open(error.url); + } else { + this.showError(error); + } + } + + private showError(error:HttpErrorResponse) { + this.notifications.addError(error.message || this.I18n.t('js.error.internal')); } private addColumnsToHref(href:string) { diff --git a/spec/features/work_packages/export_spec.rb b/spec/features/work_packages/export_spec.rb index ed43210cdb..0e8e6a653b 100644 --- a/spec/features/work_packages/export_spec.rb +++ b/spec/features/work_packages/export_spec.rb @@ -242,4 +242,31 @@ describe 'work package export', type: :feature do end end end + + # Atom exports are not downloaded. In fact, it is not even a download but rather + # a feed one can follow. + context 'Atom export', js: true do + let(:export_type) { 'Atom' } + context 'with default filter' do + before do + work_packages_page.visit_index + filters.expect_filter_count 1 + filters.open + end + + it 'shows an xml with work packages' do + settings_menu.open_and_choose 'Export ...' + + # The feed is opened in a new tab + new_window = window_opened_by { click_on export_type } + + within_window new_window do + expect(page).to have_text(wp_1.description) + expect(page).to have_text(wp_2.description) + expect(page).to have_text(wp_3.description) + expect(page).to have_text(wp_4.description) + end + end + end + end end From e4c9506e563c4fbee95b77e6fd34438a112cc8d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Mon, 1 Feb 2021 09:27:39 +0100 Subject: [PATCH 15/24] [36081] Increase max lengths of user/group names (#8948) * Unset DB limits for user attributes * Validate groups in synchronized groups * Extend limitations and fix specs --- app/models/group.rb | 2 +- app/models/user.rb | 4 +-- ...134438_alter_user_attributes_max_length.rb | 13 +++++++++ .../models/ldap_groups/synchronized_group.rb | 1 + .../ldap_groups/synchronize_filter.rb | 2 +- spec/models/group_spec.rb | 23 +++++++++++++++ spec/models/user_spec.rb | 28 +++++++++++++++++++ spec_legacy/unit/mail_handler_spec.rb | 7 ++--- 8 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 db/migrate/20210127134438_alter_user_attributes_max_length.rb diff --git a/app/models/group.rb b/app/models/group.rb index 9913ca005c..a0f683a359 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -40,7 +40,7 @@ class Group < Principal alias_attribute(:groupname, :lastname) validates_presence_of :groupname validate :uniqueness_of_groupname - validates_length_of :groupname, maximum: 30 + validates_length_of :groupname, maximum: 256 # HACK: We want to have the :preference association on the Principal to allow # for eager loading preferences. diff --git a/app/models/user.rb b/app/models/user.rb index 482bc585d6..7634246024 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -129,9 +129,9 @@ class User < Principal # Login must contain letters, numbers, underscores only validates_format_of :login, with: /\A[a-z0-9_\-@\.+ ]*\z/i validates_length_of :login, maximum: 256 - validates_length_of :firstname, :lastname, maximum: 30 + validates_length_of :firstname, :lastname, maximum: 256 validates_format_of :mail, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, allow_blank: true - validates_length_of :mail, maximum: 60, allow_nil: true + validates_length_of :mail, maximum: 256, allow_nil: true validates_confirmation_of :password, allow_nil: true validates_inclusion_of :mail_notification, in: MAIL_NOTIFICATION_OPTIONS.map(&:first), allow_blank: true diff --git a/db/migrate/20210127134438_alter_user_attributes_max_length.rb b/db/migrate/20210127134438_alter_user_attributes_max_length.rb new file mode 100644 index 0000000000..58cacd3b33 --- /dev/null +++ b/db/migrate/20210127134438_alter_user_attributes_max_length.rb @@ -0,0 +1,13 @@ +class AlterUserAttributesMaxLength < ActiveRecord::Migration[6.0] + def up + change_column :users, :firstname, :string, limit: nil + change_column :users, :lastname, :string, limit: nil + change_column :users, :mail, :string, limit: nil + end + + def down + change_column :users, :firstname, :string, limit: 30 + change_column :users, :lastname, :string, limit: 30 + change_column :users, :mail, :string, limit: 60 + end +end diff --git a/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb b/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb index 5720516c16..e6a23fda46 100644 --- a/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb +++ b/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb @@ -18,6 +18,7 @@ module LdapGroups validates_presence_of :dn validates_presence_of :group + validates_associated :group validates_presence_of :auth_source before_destroy :remove_all_members diff --git a/modules/ldap_groups/lib/open_project/ldap_groups/synchronize_filter.rb b/modules/ldap_groups/lib/open_project/ldap_groups/synchronize_filter.rb index 9e3f897d82..42b27a8bd9 100644 --- a/modules/ldap_groups/lib/open_project/ldap_groups/synchronize_filter.rb +++ b/modules/ldap_groups/lib/open_project/ldap_groups/synchronize_filter.rb @@ -77,7 +77,7 @@ module OpenProject::LdapGroups Group.where(id: sync.group_id).update_all(lastname: name) else # Create an OpenProject group - sync.group = Group.find_or_initialize_by(groupname: name) + sync.group = Group.find_or_create_by!(groupname: name) end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 5f6fe622c5..031f963749 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -49,6 +49,29 @@ describe Group, type: :model do expect(g.save).to eq true end + describe 'with long but allowed attributes' do + it 'is valid' do + group.groupname = 'a' * 256 + expect(group).to be_valid + expect(group.save).to be_truthy + end + end + + describe 'with a name too long' do + it 'is invalid' do + group.groupname = 'a' * 257 + expect(group).not_to be_valid + expect(group.save).to be_falsey + end + end + + describe 'a user with and overly long firstname (> 256 chars)' do + it 'is invalid' do + user.firstname = 'a' * 257 + expect(user).not_to be_valid + expect(user.save).to be_falsey + end + end describe 'from legacy specs' do let!(:roles) { FactoryBot.create_list :role, 2 } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index c76fde65ea..1a967ce1c0 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -98,6 +98,34 @@ describe User, type: :model do end end + describe 'with long but allowed attributes' do + it 'is valid' do + user.firstname = 'a' * 256 + user.lastname = 'b' * 256 + user.mail = 'fo' + ('o' * 237) + '@mail.example.com' + expect(user).to be_valid + expect(user.save).to be_truthy + end + end + + + describe 'a user with and overly long firstname (> 256 chars)' do + it 'is invalid' do + user.firstname = 'a' * 257 + expect(user).not_to be_valid + expect(user.save).to be_falsey + end + end + + describe 'a user with and overly long lastname (> 256 chars)' do + it 'is invalid' do + user.lastname = 'a' * 257 + expect(user).not_to be_valid + expect(user.save).to be_falsey + end + end + + describe 'login whitespace' do before do user.login = login diff --git a/spec_legacy/unit/mail_handler_spec.rb b/spec_legacy/unit/mail_handler_spec.rb index ee4e756c73..a880dffff2 100644 --- a/spec_legacy/unit/mail_handler_spec.rb +++ b/spec_legacy/unit/mail_handler_spec.rb @@ -386,11 +386,8 @@ describe MailHandler, type: :model do ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'], ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'], ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'], - # TODO: implement https://github.com/redmine/redmine/commit/a00f04886fac78e489bb030d20414ebdf10841e3 - # ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'], - # ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh'] - ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', '-', 'Smith'], - ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', '-'] + ['jsmith@example.net', 'AVeryLongFirstnameThatNoLongerExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatNoLongerExceedsTheMaximumLength', 'Smith'], + ['jsmith@example.net', 'John AVeryLongLastnameThatNoLongerExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatNoLongerExceedsTheMaximumLength'] } to_test.each do |attrs, expected| From 4d17b197835fab82dc7613af9a945f3f74a21b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Mon, 1 Feb 2021 07:29:18 +0100 Subject: [PATCH 16/24] [36026] Ensure project filter only searches for active projects https://community.openproject.com/wp/36026 --- .../work_packages/filter/project_filter.rb | 2 +- .../project_filter_dependency_representer.rb | 5 +- ...ject_filter_dependency_representer_spec.rb | 3 +- .../filter/project_filter_instance_spec.rb | 53 +++++++++++++++++++ .../filter/project_filter_spec.rb | 8 +-- 5 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 spec/models/queries/work_packages/filter/project_filter_instance_spec.rb diff --git a/app/models/queries/work_packages/filter/project_filter.rb b/app/models/queries/work_packages/filter/project_filter.rb index c64cca1c39..c858bc810f 100644 --- a/app/models/queries/work_packages/filter/project_filter.rb +++ b/app/models/queries/work_packages/filter/project_filter.rb @@ -68,6 +68,6 @@ class Queries::WorkPackages::Filter::ProjectFilter < Queries::WorkPackages::Filt private def visible_projects - @visible_projects ||= Project.visible + @visible_projects ||= Project.visible.active end end diff --git a/lib/api/v3/queries/schemas/project_filter_dependency_representer.rb b/lib/api/v3/queries/schemas/project_filter_dependency_representer.rb index b8b768d925..398ad22e63 100644 --- a/lib/api/v3/queries/schemas/project_filter_dependency_representer.rb +++ b/lib/api/v3/queries/schemas/project_filter_dependency_representer.rb @@ -35,7 +35,10 @@ module API FilterDependencyRepresenter def href_callback - api_v3_paths.projects + params = [active: { operator: '=', values: ['t'] }] + escaped = CGI.escape(::JSON.dump(params)) + + "#{api_v3_paths.projects}?filters=#{escaped}" end def type diff --git a/spec/lib/api/v3/queries/schemas/project_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/project_filter_dependency_representer_spec.rb index 93ce5b6a03..9371d24cd6 100644 --- a/spec/lib/api/v3/queries/schemas/project_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/project_filter_dependency_representer_spec.rb @@ -47,7 +47,8 @@ describe ::API::V3::Queries::Schemas::ProjectFilterDependencyRepresenter, clear_ describe 'values' do let(:path) { 'values' } let(:type) { '[]Project' } - let(:href) { api_v3_paths.projects } + let(:filters) { "?filters=%5B%7B%22active%22%3A%7B%22operator%22%3A%22%3D%22%2C%22values%22%3A%5B%22t%22%5D%7D%7D%5D" } + let(:href) { api_v3_paths.projects + filters} context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } diff --git a/spec/models/queries/work_packages/filter/project_filter_instance_spec.rb b/spec/models/queries/work_packages/filter/project_filter_instance_spec.rb new file mode 100644 index 0000000000..a1427c31ec --- /dev/null +++ b/spec/models/queries/work_packages/filter/project_filter_instance_spec.rb @@ -0,0 +1,53 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2021 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 docs/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe Queries::WorkPackages::Filter::ProjectFilter, type: :model do + let(:query) { FactoryBot.build :query } + let(:instance) do + described_class.create!(name: 'project', context: query, operator: '=', values: []) + end + + describe '#allowed_values' do + let!(:project) { FactoryBot.create :project } + let!(:archived_project) { FactoryBot.create :project, active: false } + + let(:user) { FactoryBot.create(:user, member_in_projects: [project, archived_project], member_through_role: role) } + let(:role) { FactoryBot.create :role, permissions: %i(view_work_packages) } + + before do + login_as user + end + + it 'does not include the archived project (Regression #36026)' do + expect(instance.allowed_values) + .to match_array [[project.name, project.id.to_s]] + end + end +end diff --git a/spec/models/queries/work_packages/filter/project_filter_spec.rb b/spec/models/queries/work_packages/filter/project_filter_spec.rb index 3864298a57..da33b2b003 100644 --- a/spec/models/queries/work_packages/filter/project_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/project_filter_spec.rb @@ -45,7 +45,7 @@ describe Queries::WorkPackages::Filter::ProjectFilter, type: :model do it 'is true if the user can see project' do allow(Project) - .to receive_message_chain(:visible, :exists?) + .to receive_message_chain(:visible, :active, :exists?) .and_return(true) expect(instance).to be_available @@ -53,7 +53,7 @@ describe Queries::WorkPackages::Filter::ProjectFilter, type: :model do it 'is true if the user can not see project' do allow(Project) - .to receive_message_chain(:visible, :exists?) + .to receive_message_chain(:visible, :active, :exists?) .and_return(false) expect(instance).to_not be_available @@ -71,7 +71,7 @@ describe Queries::WorkPackages::Filter::ProjectFilter, type: :model do visible_projects = [parent, child] allow(Project) - .to receive(:visible) + .to receive_message_chain(:visible, :active) .and_return(visible_projects) allow(Project) @@ -99,7 +99,7 @@ describe Queries::WorkPackages::Filter::ProjectFilter, type: :model do before do allow(Project) - .to receive(:visible) + .to receive_message_chain(:visible, :active) .and_return([project, project2]) instance.values = [project.id.to_s] From a8175c6c87eec795e930a57bedd40aea4d71649f Mon Sep 17 00:00:00 2001 From: Aleix Suau Date: Mon, 4 Jan 2021 18:51:34 +0100 Subject: [PATCH 17/24] Removed meanless? .textarea-wrapper class --- .../edit/field-types/multi-select-edit-field.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/modules/fields/edit/field-types/multi-select-edit-field.component.html b/frontend/src/app/modules/fields/edit/field-types/multi-select-edit-field.component.html index 8f55882471..b336117316 100644 --- a/frontend/src/app/modules/fields/edit/field-types/multi-select-edit-field.component.html +++ b/frontend/src/app/modules/fields/edit/field-types/multi-select-edit-field.component.html @@ -1,4 +1,4 @@ -
+
Date: Mon, 11 Jan 2021 12:08:34 +0100 Subject: [PATCH 18/24] Removed useless div --- .../multi-select-edit-field.component.html | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/frontend/src/app/modules/fields/edit/field-types/multi-select-edit-field.component.html b/frontend/src/app/modules/fields/edit/field-types/multi-select-edit-field.component.html index b336117316..6687e7d1f7 100644 --- a/frontend/src/app/modules/fields/edit/field-types/multi-select-edit-field.component.html +++ b/frontend/src/app/modules/fields/edit/field-types/multi-select-edit-field.component.html @@ -1,31 +1,29 @@ -
- - + + - - -
+ + From 1cd0300e3279649a022cda2a68024a075951974c Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Thu, 4 Feb 2021 09:58:49 +0000 Subject: [PATCH 19/24] update locales from crowdin [ci skip] --- config/locales/crowdin/js-tr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/crowdin/js-tr.yml b/config/locales/crowdin/js-tr.yml index 592e00c8f9..b50a2dd516 100644 --- a/config/locales/crowdin/js-tr.yml +++ b/config/locales/crowdin/js-tr.yml @@ -940,8 +940,8 @@ tr: other: "%{count} alt iş paketi" hour: zero: "0 s" - one: "%{count} 1 saat" - other: "%{count} 1 saat" + one: "1 saat" + other: "%{count} saat" zen_mode: button_activate: 'Zen modunu etkinleştir' button_deactivate: 'Zen modunu devre dışı bırak' From 637306edfa6d7fbf712b65f912123dd3696b8437 Mon Sep 17 00:00:00 2001 From: Aleix Suau Date: Mon, 1 Feb 2021 11:05:10 +0100 Subject: [PATCH 20/24] Open pdf exports in new tab --- .../modules/job-status/job-status-modal/job-status.modal.html | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/app/modules/job-status/job-status-modal/job-status.modal.html b/frontend/src/app/modules/job-status/job-status-modal/job-status.modal.html index 7e87bcd58a..fe45cd1a84 100644 --- a/frontend/src/app/modules/job-status/job-status-modal/job-status.modal.html +++ b/frontend/src/app/modules/job-status/job-status-modal/job-status.modal.html @@ -25,6 +25,7 @@ {{ text.download_starts }} From 35add6e5e1a99512ed55cfe52171a667fdcbdb7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Tue, 9 Feb 2021 13:45:36 +0100 Subject: [PATCH 21/24] Add note regarding LDAP group sync member/memberof [ci skip] --- .../ldap-authentication/ldap-group-synchronization/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/system-admin-guide/authentication/ldap-authentication/ldap-group-synchronization/README.md b/docs/system-admin-guide/authentication/ldap-authentication/ldap-group-synchronization/README.md index 7d1945c283..c4ec1c53b8 100644 --- a/docs/system-admin-guide/authentication/ldap-authentication/ldap-group-synchronization/README.md +++ b/docs/system-admin-guide/authentication/ldap-authentication/ldap-group-synchronization/README.md @@ -16,6 +16,10 @@ In OpenProject EE, you can synchronize LDAP group memberships defined through th - - have at least one group defined in OpenProject (See the “[Managing groups](../../../users-permissions/groups/)” guide for more information on how to create and edit groups), - have set up your LDAP authentication source (See the “[Manage LDAP authentication](../../ldap-authentication/)” guide) - have at least one LDAP entry with a *groupOfNames* object class and at least one *member* reference to an entry within your base DN of your LDAP authentication source. We use the inverse *memberOf* filter to determine the members of a group entry. + + For the sake of simplicity, we assume that in this guide, your LDAP structure looks like the following: From f55609f3b1e684bf3f0b50a7f79b620f012390d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Wed, 10 Feb 2021 06:59:59 +0100 Subject: [PATCH 22/24] Update README.md --- docs/user-guide/repository/README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/user-guide/repository/README.md b/docs/user-guide/repository/README.md index 67af4e4be0..d2c4e46a73 100644 --- a/docs/user-guide/repository/README.md +++ b/docs/user-guide/repository/README.md @@ -35,18 +35,23 @@ You can create a comparison of two versions to see the changes made for specific -## Working with an SVN client +## Working with an SVN or Git client -The data contained in a project repository can be downloaded to your computer using one of several clients, for example [Tortoise SVN](https://tortoisesvn.net/). +The data contained in a project repository can be downloaded to your computer using one of several clients, for example [Tortoise SVN](https://tortoisesvn.net/) for Subversion, and the [git client](https://git-scm.com/) or [one of the recommended GUI clients](https://git-scm.com/downloads/guis) for Git. + +The specifics of working of the selected version control client may vary. Please refer to the documentation of your version control software client for more information. +If you choose to use Tortoise SVN, you will find a good guide [here](http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug.html). +For Git, we recommend the [Pro Git guide](https://git-scm.com/book/en/v2). The specifics of working of the selected version control client may vary. Please refer to the documentation of your version control software client for more information. If you choose to use Tortoise SVN, you will find a good guide [here](http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug.html). +## Referencing work packages + In the commit message you can reference a workpackge ID (e.g. #1234). In the repository settings (Administration -> System settings -> Repository) you can define keywords that change the status of the referenced work package (e.g. fixes #1234 or closes #1234). In any textile field you can reference revisions by putting an "r" in front of the revision number (e.g. r123). - ## Configure Repositories in OpenProject Please see our system admin guide [how to configure repositories in OpenProject](../../system-admin-guide/system-settings/repositories/). @@ -55,4 +60,4 @@ Please see our system admin guide [how to configure repositories in OpenProject] ## Repository integration -See our Installation and operations guide how to [integrate repositories in Openproject](../../installation-and-operations/configuration/repositories/#repository-integration-in-openproject). \ No newline at end of file +See our Installation and operations guide how to [integrate repositories in Openproject](../../installation-and-operations/configuration/repositories/#repository-integration-in-openproject). From 3cb2b30a6d1691aaa50d3815fc7d1f174d26a4ae Mon Sep 17 00:00:00 2001 From: ulferts Date: Thu, 11 Feb 2021 10:51:30 +0100 Subject: [PATCH 23/24] bump rails to 6.0.3.5 (#8996) --- Gemfile | 2 +- Gemfile.lock | 104 +++++++++++++++++++++++++-------------------------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/Gemfile b/Gemfile index 4da6b15c17..2f9a94dd63 100644 --- a/Gemfile +++ b/Gemfile @@ -34,7 +34,7 @@ gem 'actionpack-xml_parser', '~> 2.0.0' gem 'activemodel-serializers-xml', '~> 1.0.1' gem 'activerecord-import', '~> 1.0.2' gem 'activerecord-session_store', '~> 1.1.0' -gem 'rails', '~> 6.0.3.2' +gem 'rails', '~> 6.0.3.5' gem 'responders', '~> 3.0' gem 'rdoc', '>= 2.4.2' diff --git a/Gemfile.lock b/Gemfile.lock index 6b49a3af29..5f98de482a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -183,26 +183,26 @@ GEM remote: https://rubygems.org/ specs: Ascii85 (1.0.3) - actioncable (6.0.3.4) - actionpack (= 6.0.3.4) + actioncable (6.0.3.5) + actionpack (= 6.0.3.5) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.4) - actionpack (= 6.0.3.4) - activejob (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + actionmailbox (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) mail (>= 2.7.1) - actionmailer (6.0.3.4) - actionpack (= 6.0.3.4) - actionview (= 6.0.3.4) - activejob (= 6.0.3.4) + actionmailer (6.0.3.5) + actionpack (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.4) - actionview (= 6.0.3.4) - activesupport (= 6.0.3.4) + actionpack (6.0.3.5) + actionview (= 6.0.3.5) + activesupport (= 6.0.3.5) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) @@ -210,30 +210,30 @@ GEM actionpack-xml_parser (2.0.1) actionpack (>= 5.0) railties (>= 5.0) - actiontext (6.0.3.4) - actionpack (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + actiontext (6.0.3.5) + actionpack (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) nokogiri (>= 1.8.5) - actionview (6.0.3.4) - activesupport (= 6.0.3.4) + actionview (6.0.3.5) + activesupport (= 6.0.3.5) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.4) - activesupport (= 6.0.3.4) + activejob (6.0.3.5) + activesupport (= 6.0.3.5) globalid (>= 0.3.6) - activemodel (6.0.3.4) - activesupport (= 6.0.3.4) + activemodel (6.0.3.5) + activesupport (= 6.0.3.5) activemodel-serializers-xml (1.0.2) activemodel (> 5.x) activesupport (> 5.x) builder (~> 3.1) - activerecord (6.0.3.4) - activemodel (= 6.0.3.4) - activesupport (= 6.0.3.4) + activerecord (6.0.3.5) + activemodel (= 6.0.3.5) + activesupport (= 6.0.3.5) activerecord-import (1.0.7) activerecord (>= 3.2) activerecord-nulldb-adapter (0.5.1) @@ -244,12 +244,12 @@ GEM multi_json (~> 1.11, >= 1.11.2) rack (>= 1.5.2, < 3) railties (>= 4.0) - activestorage (6.0.3.4) - actionpack (= 6.0.3.4) - activejob (= 6.0.3.4) - activerecord (= 6.0.3.4) + activestorage (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) marcel (~> 0.3.1) - activesupport (6.0.3.4) + activesupport (6.0.3.5) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -694,20 +694,20 @@ GEM rack_session_access (0.2.0) builder (>= 2.0.0) rack (>= 1.0.0) - rails (6.0.3.4) - actioncable (= 6.0.3.4) - actionmailbox (= 6.0.3.4) - actionmailer (= 6.0.3.4) - actionpack (= 6.0.3.4) - actiontext (= 6.0.3.4) - actionview (= 6.0.3.4) - activejob (= 6.0.3.4) - activemodel (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + rails (6.0.3.5) + actioncable (= 6.0.3.5) + actionmailbox (= 6.0.3.5) + actionmailer (= 6.0.3.5) + actionpack (= 6.0.3.5) + actiontext (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) + activemodel (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) bundler (>= 1.3.0) - railties (= 6.0.3.4) + railties (= 6.0.3.5) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) @@ -721,15 +721,15 @@ GEM rails-i18n (6.0.0) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 7) - railties (6.0.3.4) - actionpack (= 6.0.3.4) - activesupport (= 6.0.3.4) + railties (6.0.3.5) + actionpack (= 6.0.3.5) + activesupport (= 6.0.3.5) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) rainbow (3.0.0) raindrops (0.19.1) - rake (13.0.1) + rake (13.0.3) rb-fsevent (0.10.4) rb-inotify (0.10.1) ffi (~> 1.0) @@ -1032,7 +1032,7 @@ DEPENDENCIES rack-protection (~> 2.1.0) rack-test (~> 1.1.0) rack_session_access - rails (~> 6.0.3.2) + rails (~> 6.0.3.5) rails-controller-testing (~> 1.0.2) rails-i18n (~> 6.0.0) rdoc (>= 2.4.2) From 108e5d4c0414fb3e2bcd324b3105fdf92001996d Mon Sep 17 00:00:00 2001 From: ulferts Date: Thu, 11 Feb 2021 11:02:09 +0100 Subject: [PATCH 24/24] Add release-notes file --- docs/release-notes/11-1-3/README.md | 28 ++++++++++++++++++++++++++++ docs/release-notes/README.md | 7 +++++++ 2 files changed, 35 insertions(+) create mode 100644 docs/release-notes/11-1-3/README.md diff --git a/docs/release-notes/11-1-3/README.md b/docs/release-notes/11-1-3/README.md new file mode 100644 index 0000000000..ead072b84b --- /dev/null +++ b/docs/release-notes/11-1-3/README.md @@ -0,0 +1,28 @@ +--- +title: OpenProject 11.1.3 +sidebar_navigation: + title: 11.1.3 +release_version: 11.1.3 +release_date: 2021-02-11 +--- + +# OpenProject 11.1.3 + +We released [OpenProject 11.1.3](https://community.openproject.com/versions/1469). +The release contains several bug fixes and we recommend updating to the newest version. + + +#### Bug fixes and changes + +- Fixed: Filter gets removed (ERIK@Staging) \[[#34003](https://community.openproject.com/wp/34003)\] +- Fixed: S3 presigned URL cached for 7 days does not work with IAM roles and is a security issue \[[#35739](https://community.openproject.com/wp/35739)\] +- Fixed: Images directly uploaded to s3 are not displayed within new tab \[[#36018](https://community.openproject.com/wp/36018)\] +- Fixed: Selecting "Atom" in export menu throws cryptic error \[[#36052](https://community.openproject.com/wp/36052)\] +- Fixed: Creating new synchronized groups from filters raises error if group name too long \[[#36081](https://community.openproject.com/wp/36081)\] + +#### Contributions +A big thanks to community members for reporting bugs and helping us identifying and providing fixes. + +Special thanks for reporting and finding bugs go to + +Florian Stoyadin, Andreas Wittig diff --git a/docs/release-notes/README.md b/docs/release-notes/README.md index 8b30ab4711..1b797f9106 100644 --- a/docs/release-notes/README.md +++ b/docs/release-notes/README.md @@ -12,6 +12,13 @@ Stay up to date and get an overview of the new features included in the releases +## 11.1.3 + +Release date: 2021-02-11 + +[Release Notes](11-1-3/) + + ## 11.1.2 Release date: 2021-01-21