Skip to content

Commit

Permalink
Merge branch 'release/14.6' into task/58111-146-documentation-add-to-…
Browse files Browse the repository at this point in the history
…connection-validation-that-managed-directory-is-empty-for-nextcloud-storages
  • Loading branch information
MayaBerd authored Oct 8, 2024
2 parents f0e23d0 + ed73e01 commit d03d607
Show file tree
Hide file tree
Showing 205 changed files with 2,080 additions and 1,104 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -399,4 +399,4 @@ end

gem "openproject-octicons", "~>19.18.0"
gem "openproject-octicons_helper", "~>19.18.0"
gem "openproject-primer_view_components", "~>0.47.0"
gem "openproject-primer_view_components", "~>0.47.1"
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ GEM
actionview
openproject-octicons (= 19.18.0)
railties
openproject-primer_view_components (0.47.0)
openproject-primer_view_components (0.47.1)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
openproject-octicons (>= 19.17.0)
Expand Down Expand Up @@ -1303,7 +1303,7 @@ DEPENDENCIES
openproject-octicons (~> 19.18.0)
openproject-octicons_helper (~> 19.18.0)
openproject-openid_connect!
openproject-primer_view_components (~> 0.47.0)
openproject-primer_view_components (~> 0.47.1)
openproject-recaptcha!
openproject-reporting!
openproject-storages!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,8 @@ def create
create_service.on_success { render_project_list(url_for_action: :index) }

create_service.on_failure do
update_flash_message_via_turbo_stream(
message: join_flash_messages(create_service.errors),
full: true, dismiss_scheme: :hide, scheme: :danger
render_error_flash_message_via_turbo_stream(
message: join_flash_messages(create_service.errors)
)
end

Expand All @@ -82,9 +81,8 @@ def destroy
delete_service.on_success { render_project_list(url_for_action: :index) }

delete_service.on_failure do
update_flash_message_via_turbo_stream(
message: join_flash_messages(delete_service.errors.full_messages),
full: true, dismiss_scheme: :hide, scheme: :danger
render_error_flash_message_via_turbo_stream(
message: join_flash_messages(delete_service.errors.full_messages)
)
end

Expand Down Expand Up @@ -139,15 +137,6 @@ def find_custom_field_project_to_destroy
respond_with_project_not_found_turbo_streams
end

def update_project_list_via_turbo_stream(url_for_action: action_name)
update_via_turbo_stream(
component: Admin::CustomFields::CustomFieldProjects::TableComponent.new(
query: available_custom_fields_projects_query,
params: { custom_field: @custom_field, url_for_action: }
)
)
end

def available_custom_fields_projects_query
@available_custom_fields_projects_query = ProjectQuery.new(
name: "custom-fields-projects-#{@custom_field.id}"
Expand All @@ -166,9 +155,8 @@ def initialize_custom_field_project
end

def respond_with_project_not_found_turbo_streams
update_flash_message_via_turbo_stream message: t(:notice_project_not_found), full: true, dismiss_scheme: :hide,
scheme: :danger
update_project_list_via_turbo_stream
render_error_flash_message_via_turbo_stream message: t(:notice_project_not_found)
render_project_list(url_for_action: :index)

respond_with_turbo_streams
end
Expand Down
27 changes: 8 additions & 19 deletions app/controllers/admin/settings/project_custom_fields_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,8 @@ def link
create_service.on_success { render_project_list(url_for_action: :project_mappings) }

create_service.on_failure do
update_flash_message_via_turbo_stream(
message: join_flash_messages(create_service.errors),
full: true, dismiss_scheme: :hide, scheme: :danger
render_error_flash_message_via_turbo_stream(
message: join_flash_messages(create_service.errors)
)
end

Expand All @@ -106,9 +105,8 @@ def unlink
delete_service.on_success { render_project_list(url_for_action: :project_mappings) }

delete_service.on_failure do
update_flash_message_via_turbo_stream(
message: join_flash_messages(delete_service.errors.full_messages),
full: true, dismiss_scheme: :hide, scheme: :danger
render_error_flash_message_via_turbo_stream(
message: join_flash_messages(delete_service.errors.full_messages)
)
end

Expand Down Expand Up @@ -184,15 +182,8 @@ def find_unlink_project_custom_field_mapping
project_id: permitted_params.project_custom_field_project_mapping[:project_id]
)
rescue ActiveRecord::RecordNotFound
update_flash_message_via_turbo_stream(
message: t(:notice_file_not_found), full: true, dismiss_scheme: :hide, scheme: :danger
)
replace_via_turbo_stream(
component: Settings::ProjectCustomFields::ProjectCustomFieldMapping::TableComponent.new(
query: project_custom_field_mappings_query,
params: { custom_field: @custom_field }
)
)
render_error_flash_message_via_turbo_stream(message: t(:notice_file_not_found))
render_project_list(url_for_action: :project_mappings)

respond_with_turbo_streams
end
Expand All @@ -213,10 +204,8 @@ def find_custom_field_projects_to_link
false
end
rescue ActiveRecord::RecordNotFound
update_flash_message_via_turbo_stream(
message: t(:notice_project_not_found), full: true, dismiss_scheme: :hide, scheme: :danger
)
render_project_list
render_error_flash_message_via_turbo_stream(message: t(:notice_project_not_found))
render_project_list(url_for_action: :project_mappings)

respond_with_turbo_streams
end
Expand Down
6 changes: 0 additions & 6 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,6 @@ def labeled_check_box_tags(name, collection, options = {})
end.join.html_safe
end

def html_hours(text)
html_safe_gsub(text,
%r{(\d+)\.(\d+)},
'<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
end

def html_safe_gsub(string, *gsub_args, &)
html_safe = string.html_safe?
result = string.gsub(*gsub_args, &)
Expand Down
2 changes: 1 addition & 1 deletion app/models/status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class Status < ApplicationRecord
uniqueness: { case_sensitive: false },
length: { maximum: 256 }

validates :default_done_ratio, inclusion: { in: 0..100, allow_nil: true }
validates :default_done_ratio, inclusion: { in: 0..100, allow_nil: false }

validate :default_status_must_not_be_readonly

Expand Down
1 change: 1 addition & 0 deletions app/views/custom_styles/_primer_color_mapping.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
--controlKnob-borderColor-checked: var(--control-checked-color) !important;
--button-primary-fgColor-rest: var(--button--primary-font-color) !important;
--button-primary-bgColor-rest: var(--button--primary-background-color) !important;
--button-primary-bgColor-active: var(--button--primary-background-active-color) !important;
--button-primary-bgColor-hover: var(--button--primary-background-hover-color) !important;
--button-primary-bgColor-disabled: var(--button--primary-background-disabled-color) !important;
--button-primary-borderColor-disabled: var(--button--primary-border-disabled-color) !important;
Expand Down
2 changes: 1 addition & 1 deletion app/views/statuses/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ See COPYRIGHT and LICENSE files for more details.

<section class="form--section">
<div class="form--field -required"><%= f.text_field "name", required: true, container_class: "-middle" %></div>
<div class="form--field"><%= f.number_field "default_done_ratio", min: 0, max: 100, container_class: "-xslim" %></div>
<div class="form--field -required"><%= f.number_field "default_done_ratio", required: true, min: 0, max: 100, container_class: "-xslim" %></div>
<div class="form--field"><%= f.check_box "is_closed" %></div>
<% unless @status.is_default? %>
<div class="form--field"><%= f.check_box "is_default" %></div>
Expand Down
4 changes: 2 additions & 2 deletions app/views/versions/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ See COPYRIGHT and LICENSE files for more details.
<table>
<tr>
<td width="130px" align="right"><%= Version.human_attribute_name(:estimated_hours) %></td>
<td width="240px" class="total-hours" align="right"><%= html_hours(l_hours(@version.estimated_hours)) %></td>
<td width="240px" class="total-hours" align="right"><%= l_hours(@version.estimated_hours) %></td>
</tr>
<% if User.current.allowed_in_project?(:view_time_entries, @project) %>
<tr>
<td width="130px" align="right"><%= t(:label_spent_time) %></td>
<td width="240px" class="total-hours" align="right"><%= html_hours(l_hours(@version.spent_hours)) %></td>
<td width="240px" class="total-hours" align="right"><%= l_hours(@version.spent_hours) %></td>
</tr>
<% end %>
</table>
Expand Down
46 changes: 1 addition & 45 deletions app/workers/application_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,7 @@

class ApplicationJob < ActiveJob::Base
include ::JobStatus::ApplicationJobWithStatus

##
# By default, do not log the arguments of a background job
# to avoid leaking sensitive information to logs
self.log_arguments = false

around_perform :prepare_job_context
include SharedJobSetup

##
# Return a priority number on the given payload
Expand Down Expand Up @@ -65,45 +59,7 @@ def self.queue_with_priority(value = :default)
end
end

# Resets the thread local request store.
# This should be done, because normal application code expects the RequestStore to be
# invalidated between multiple requests and does usually not care whether it is executed
# from a request or from a delayed job.
# For a delayed job, each job execution is the thing that comes closest to
# the concept of a new request.
def with_clean_request_store
store = RequestStore.store

begin
RequestStore.clear!
yield
ensure
# Reset to previous value
RequestStore.clear!
RequestStore.store.merge! store
end
end

# Reloads the thread local ActionMailer configuration.
# Since the email configuration is now done in the web app, we need to
# make sure that any changes to the configuration is correctly picked up
# by the background jobs at runtime.
def reload_mailer_settings!
Setting.reload_mailer_settings!
end

def job_scheduled_at
GoodJob::Job.where(id: job_id).pick(:scheduled_at)
end

private

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

yield
end
end
end
70 changes: 34 additions & 36 deletions app/workers/mails/mailer_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,46 +26,44 @@
# See COPYRIGHT and LICENSE files for more details.
#++

##
# This job gets called when internally using
# OpenProject is configured to use this job when sending emails like this:
#
# ```
# UserMailer.some_mail("some param").deliver_later
# ```
#
# because we want to have the sending of the email run in an `ApplicationJob`
# as opposed to using `ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper`.
# We want it to run in an `ApplicationJob` because of the shared setup required
# such as reloading the mailer configuration and resetting the request store.
class Mails::MailerJob < ApplicationJob
queue_as { ActionMailer::Base.deliver_later_queue_name }

# Retry mailing jobs three times with polinomial backoff
retry_on StandardError, wait: :polynomially_longer, attempts: 3

# If exception is handled in mail handler
# retry_on will be ignored
rescue_from StandardError, with: :handle_exception_with_mailer_class

def perform(mailer, mail_method, delivery, args:)
mailer.constantize.public_send(mail_method, *args).send(delivery)
end

private

# "Deserialize" the mailer class name by hand in case another argument
# (like a Global ID reference) raised DeserializationError.
def mailer_class
if mailer = Array(@serialized_arguments).first || Array(arguments).first
mailer.constantize
end
end
# This job is used because all our `XxxMailer` classes inherit from
# `ApplicationMailer`, and `ApplicationMailer.delivery_job` is set to
# `::Mails::MailerJob`.
#
# The `delivery_job` is customized to add the shared job setup required for
# OpenProject such as reloading the mailer configuration and resetting the
# request store on each job execution.
#
# It also adds retry logic to the job.
class Mails::MailerJob < ActionMailer::MailDeliveryJob
include SharedJobSetup

def handle_exception_with_mailer_class(exception)
if klass = mailer_class
klass.handle_exception exception
else
raise exception
end
end
# Retry mailing jobs 14 times with polynomial backoff (retries for ~ 1.5 days).
#
# with polynomial backoff, the formula to get wait_duration is:
#
# ((executions**4) + (Kernel.rand * (executions**4) * jitter)) + 2
#
# as the default jitter is 0.0, the formula becomes:
#
# ((executions**4) + 2)
#
# To get the numbers, run this:
#
# (1..20).reduce(0) do |total_wait, i|
# wait = (i**4) + 2
# total_wait += wait
# puts "Execution #{i} waits #{wait} secs. Total wait: #{total_wait} secs"
# total_wait
# end
#
# We set attemps to 14 to have it retry for 127715 seconds which is more than
# 1 day (~= 1 day 11 hours 30 min)
retry_on StandardError, wait: :polynomially_longer, attempts: 14
end
Loading

0 comments on commit d03d607

Please sign in to comment.