feature/42358-standardise-date-pickers-drop-modal-portal
commit
d67d18c8f5
@ -0,0 +1,98 @@ |
||||
#-- 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. |
||||
#++ |
||||
|
||||
class Settings::WorkingDaysUpdateService < Settings::UpdateService |
||||
def call(params) |
||||
params = params.to_h.deep_symbolize_keys |
||||
self.non_working_days_params = params.delete(:non_working_days) || [] |
||||
super |
||||
end |
||||
|
||||
def validate_params(params) |
||||
contract = Settings::WorkingDaysParamsContract.new(model, user, params:) |
||||
ServiceResult.new success: contract.valid?, |
||||
errors: contract.errors, |
||||
result: model |
||||
end |
||||
|
||||
def persist(call) |
||||
results = call |
||||
ActiveRecord::Base.transaction do |
||||
# The order of merging the service is important to preserve |
||||
# the errors model's base object, which is a NonWorkingDay |
||||
results = persist_non_working_days |
||||
results.merge!(super) if results.success? |
||||
|
||||
raise ActiveRecord::Rollback if results.failure? |
||||
end |
||||
|
||||
results |
||||
end |
||||
|
||||
private |
||||
|
||||
attr_accessor :non_working_days_params |
||||
|
||||
def persist_non_working_days |
||||
# We don't support update for now |
||||
to_create, to_delete = attributes_to_create_and_delete |
||||
results = destroy_records(to_delete) |
||||
create_results = create_records(to_create) |
||||
results.merge!(create_results) |
||||
results.result = Array(results.result) + Array(create_results.result) |
||||
results |
||||
end |
||||
|
||||
def attributes_to_create_and_delete |
||||
non_working_days_params.reduce([[], []]) do |results, nwd| |
||||
results.first << nwd if !nwd[:id] |
||||
results.last << nwd[:id] if nwd[:_destroy] && nwd[:id] |
||||
results |
||||
end |
||||
end |
||||
|
||||
def create_records(attributes) |
||||
wrap_result(attributes.map { |attrs| NonWorkingDay.create(attrs) }) |
||||
end |
||||
|
||||
def destroy_records(ids) |
||||
wrap_result NonWorkingDay.where(id: ids).destroy_all |
||||
end |
||||
|
||||
def wrap_result(result) |
||||
model = NonWorkingDay.new |
||||
errors = model.errors.tap do |err| |
||||
result.each do |r| |
||||
err.merge!(r.errors) |
||||
end |
||||
end |
||||
success = model.errors.empty? |
||||
|
||||
ServiceResult.new(success:, errors:, result:) |
||||
end |
||||
end |
@ -0,0 +1,63 @@ |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2023 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. |
||||
#++ |
||||
|
||||
module Notifications |
||||
# Creates date alert jobs for users whose local time is 1:00 am. |
||||
class ScheduleDateAlertsNotificationsJob < Cron::CronJob |
||||
# runs every quarter of an hour, so 00:00, 00:15,..., 15:30, 15:45, 16:00, ... |
||||
self.cron_expression = '*/15 * * * *' |
||||
|
||||
def perform |
||||
return unless EnterpriseToken.allows_to?(:date_alerts) |
||||
|
||||
service = Service.new(times_from_scheduled_to_execution) |
||||
service.call |
||||
end |
||||
|
||||
# Returns times from scheduled execution time to current time in 15 minutes |
||||
# steps. |
||||
# |
||||
# As scheduled execution time can be different from current time by more |
||||
# than 15 minutes when workers are busy, all times at 15 minutes interval |
||||
# between scheduled time and current time need to be considered to match |
||||
# with 1:00am in a time zone. |
||||
def times_from_scheduled_to_execution |
||||
time = scheduled_time |
||||
times = [] |
||||
begin |
||||
times << time |
||||
time += 15.minutes |
||||
end while time < Time.current |
||||
times |
||||
end |
||||
|
||||
def scheduled_time |
||||
self.class.delayed_job.run_at.then { |t| t.change(min: t.min / 15 * 15) } |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,74 @@ |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2023 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. |
||||
#++ |
||||
|
||||
# Creates date alerts notifications for users whose local time is 1am for the |
||||
# given run_times. |
||||
class Notifications::ScheduleDateAlertsNotificationsJob::Service |
||||
attr_reader :run_times |
||||
|
||||
# @param run_times [Array<DateTime>] the times for which the service is run. |
||||
# Must be multiple of 15 minutes (xx:00, xx:15, xx:30, or xx:45). |
||||
def initialize(run_times) |
||||
@run_times = run_times |
||||
end |
||||
|
||||
def call |
||||
return unless EnterpriseToken.allows_to?(:date_alerts) |
||||
|
||||
users_at_1am_with_notification_settings.find_each do |user| |
||||
Notifications::CreateDateAlertsNotificationsJob.perform_later(user) |
||||
end |
||||
end |
||||
|
||||
private |
||||
|
||||
def time_zones_covering_1am_local_time |
||||
UserPreferences::UpdateContract |
||||
.assignable_time_zones |
||||
.select { |time_zone| executing_at_1am_for_timezone?(time_zone) } |
||||
.map { |time_zone| time_zone.tzinfo.canonical_zone.name } |
||||
end |
||||
|
||||
def executing_at_1am_for_timezone?(time_zone) |
||||
run_times.any? { |time| is_1am?(time, time_zone) } |
||||
end |
||||
|
||||
def is_1am?(time, time_zone) |
||||
local_time = time.in_time_zone(time_zone) |
||||
local_time.strftime('%H:%M') == '01:00' |
||||
end |
||||
|
||||
def users_at_1am_with_notification_settings |
||||
User |
||||
.with_time_zone(time_zones_covering_1am_local_time) |
||||
.not_locked |
||||
.where("EXISTS (SELECT 1 FROM notification_settings " \ |
||||
"WHERE user_id = users.id AND " \ |
||||
"(overdue IS NOT NULL OR start_date IS NOT NULL OR due_date IS NOT NULL))") |
||||
end |
||||
end |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue