Skip to content

Commit

Permalink
Merge pull request #17229 from opf/implementation/59433-define-databa…
Browse files Browse the repository at this point in the history
…se-model-for-reminders

[#59436] Set reminders for work packages to automatically generate date alert notifications (backend services)
  • Loading branch information
akabiru authored Dec 4, 2024
2 parents cc72da4 + 5079bf7 commit 300ce15
Show file tree
Hide file tree
Showing 35 changed files with 1,597 additions and 9 deletions.
82 changes: 82 additions & 0 deletions app/contracts/reminders/base_contract.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2024 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module Reminders
class BaseContract < ::ModelContract
MAX_NOTE_CHARS_LENGTH = 80

attribute :creator_id
attribute :remindable_id
attribute :remindable_type
attribute :remind_at
attribute :note

validate :validate_creator_exists
validate :validate_acting_user
validate :validate_remindable_exists
validate :validate_manage_reminders_permissions
validate :validate_remind_at_is_in_future
validate :validate_note_length

def self.model = Reminder

private

def validate_creator_exists
errors.add :creator, :not_found unless User.exists?(model.creator_id)
end

def validate_acting_user
errors.add :creator, :invalid unless model.creator_id == user.id
end

def validate_remindable_exists
errors.add :remindable, :not_found if model.remindable.blank?
end

def validate_remind_at_is_in_future
if model.remind_at.present? && model.remind_at < Time.current
errors.add :remind_at, :datetime_must_be_in_future
end
end

def validate_note_length
if model.note.present? && model.note.length > MAX_NOTE_CHARS_LENGTH
errors.add :note, :too_long, count: MAX_NOTE_CHARS_LENGTH
end
end

def validate_manage_reminders_permissions
return if errors.added?(:remindable, :not_found)

unless user.allowed_in_project?(:manage_own_reminders, model.remindable.project)
errors.add :base, :error_unauthorized
end
end
end
end
32 changes: 32 additions & 0 deletions app/contracts/reminders/create_contract.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2024 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module Reminders
class CreateContract < BaseContract
end
end
36 changes: 36 additions & 0 deletions app/contracts/reminders/delete_contract.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2024 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module Reminders
class DeleteContract < ::DeleteContract
delete_permission -> {
# The user can delete the reminder if they created it
model.creator_id == user.id
}
end
end
41 changes: 41 additions & 0 deletions app/contracts/reminders/update_contract.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2024 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module Reminders
class UpdateContract < BaseContract
validate :unchangeable_attributes

private

def unchangeable_attributes
if model.remindable_changed? || model.creator_id_changed?
errors.add(:base, :unchangeable)
end
end
end
end
35 changes: 35 additions & 0 deletions app/models/concerns/remindable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2024 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module Remindable
extend ActiveSupport::Concern

included do
has_many :reminders, as: :remindable, dependent: :destroy
end
end
9 changes: 6 additions & 3 deletions app/models/notification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,20 @@ class Notification < ApplicationRecord
responsible: 9,
date_alert_start_date: 10,
date_alert_due_date: 11,
shared: 12
shared: 12,
reminder: 13
}.freeze

enum reason: REASONS,
_prefix: true
enum :reason, REASONS, prefix: true

belongs_to :recipient, class_name: "User"
belongs_to :actor, class_name: "User"
belongs_to :journal
belongs_to :resource, polymorphic: true

has_one :reminder_notification, dependent: :destroy
has_one :reminder, through: :reminder_notification

include Scopes::Scoped
scopes :unsent_reminders_before,
:mail_reminder_unsent,
Expand Down
51 changes: 51 additions & 0 deletions app/models/reminder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2024 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 Reminder < ApplicationRecord
belongs_to :remindable, polymorphic: true
belongs_to :creator, class_name: "User"

has_many :reminder_notifications, dependent: :destroy
has_many :notifications, through: :reminder_notifications

def unread_notifications?
unread_notifications.exists?
end

def unread_notifications
notifications.where(read_ian: [false, nil])
end

def completed?
completed_at.present?
end

def scheduled?
job_id.present? && !completed?
end
end
4 changes: 4 additions & 0 deletions app/models/reminder_notification.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class ReminderNotification < ApplicationRecord
belongs_to :reminder
belongs_to :notification
end
1 change: 1 addition & 0 deletions app/models/work_package.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class WorkPackage < ApplicationRecord
include WorkPackages::Relations
include ::Scopes::Scoped
include HasMembers
include Remindable

include OpenProject::Journal::AttachmentHelper

Expand Down
57 changes: 57 additions & 0 deletions app/services/concerns/reminders/service_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++

module Reminders
module ServiceHelpers
extend ActiveSupport::Concern

def reschedule_reminder(reminder)
destroy_scheduled_reminder_job(reminder)
mark_unread_notifications_as_read_for(reminder)
schedule_new_reminder_job(reminder)
end

def schedule_new_reminder_job(reminder)
job = Reminders::ScheduleReminderJob.schedule(reminder)
reminder.update_columns(job_id: job.job_id)
end

def destroy_scheduled_reminder_job(reminder)
return unless reminder.scheduled?
return unless job = GoodJob::Job.find_by(id: reminder.job_id)

job.destroy unless job.finished?
end

def mark_unread_notifications_as_read_for(reminder)
return unless reminder.unread_notifications?

reminder.unread_notifications.update_all(read_ian: true, updated_at: Time.zone.now)
end
end
end
Loading

0 comments on commit 300ce15

Please sign in to comment.