Add automation observers for the task [SCI-11930]

This commit is contained in:
Andrej 2025-08-06 12:52:24 +02:00
parent f4bf6fcf6d
commit 0f5cf347ef
14 changed files with 159 additions and 2 deletions

View file

@ -8,6 +8,7 @@ class Asset < ApplicationRecord
include ActiveStorageConcerns include ActiveStorageConcerns
include ActiveStorageHelper include ActiveStorageHelper
include VersionedAttachments include VersionedAttachments
include ObservableModel
require 'tempfile' require 'tempfile'
# Lock duration set to 30 minutes # Lock duration set to 30 minutes
@ -475,4 +476,8 @@ class Asset < ApplicationRecord
def reset_file_processing def reset_file_processing
self.file_processing = false self.file_processing = false
end end
def run_observers
AutomationObservers::ProtocolContentChangedAutomationObserver.new(step, last_modified_by || created_by).call
end
end end

View file

@ -1,5 +1,6 @@
class Checklist < ApplicationRecord class Checklist < ApplicationRecord
include SearchableModel include SearchableModel
include ObservableModel
auto_strip_attributes :name, nullify: false auto_strip_attributes :name, nullify: false
validates :name, validates :name,
@ -57,4 +58,10 @@ class Checklist < ApplicationRecord
new_checklist new_checklist
end end
end end
private
def run_observers
AutomationObservers::ProtocolContentChangedAutomationObserver.new(step, last_modified_by || created_by).call
end
end end

View file

@ -1,4 +1,5 @@
class ChecklistItem < ApplicationRecord class ChecklistItem < ApplicationRecord
include ObservableModel
attr_accessor :with_paragraphs attr_accessor :with_paragraphs
@ -22,6 +23,7 @@ class ChecklistItem < ApplicationRecord
class_name: 'User', class_name: 'User',
optional: true optional: true
after_create :run_observers
# conditional touch excluding checked updates # conditional touch excluding checked updates
after_destroy :touch_checklist after_destroy :touch_checklist
after_save :touch_checklist after_save :touch_checklist
@ -76,4 +78,8 @@ class ChecklistItem < ApplicationRecord
checklist.touch checklist.touch
# rubocop:enable Rails/SkipsModelValidations # rubocop:enable Rails/SkipsModelValidations
end end
def run_observers
AutomationObservers::ProtocolContentChangedAutomationObserver.new(checklist.step, last_modified_by || created_by).call
end
end end

View file

@ -1,6 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class FormFieldValue < ApplicationRecord class FormFieldValue < ApplicationRecord
include ObservableModel
belongs_to :form_response belongs_to :form_response
belongs_to :form_field belongs_to :form_field
belongs_to :created_by, class_name: 'User' belongs_to :created_by, class_name: 'User'
@ -44,4 +46,8 @@ class FormFieldValue < ApplicationRecord
errors.add(:value, :not_unique_latest) errors.add(:value, :not_unique_latest)
end end
def run_observers
AutomationObservers::ProtocolContentChangedAutomationObserver.new(form_response.step, created_by).call
end
end end

View file

@ -44,6 +44,8 @@ class Result < ApplicationRecord
CleanupUserSettingsJob.perform_later('result_states', id) CleanupUserSettingsJob.perform_later('result_states', id)
end end
after_create :run_observers
def self.search(user, def self.search(user,
include_archived, include_archived,
query = nil, query = nil,
@ -196,4 +198,10 @@ class Result < ApplicationRecord
def delete_step_results def delete_step_results
step_results.destroy_all step_results.destroy_all
end end
private
def run_observers
AutomationObservers::ResultCreateAutomationObserver.new(my_module, user).call
end
end end

View file

@ -22,6 +22,7 @@ class Step < ApplicationRecord
before_validation :set_completed_on, if: :completed_changed? before_validation :set_completed_on, if: :completed_changed?
before_save :set_last_modified_by before_save :set_last_modified_by
after_create :run_observers
before_destroy :cascade_before_destroy before_destroy :cascade_before_destroy
after_destroy :adjust_positions_after_destroy, unless: -> { skip_position_adjust } after_destroy :adjust_positions_after_destroy, unless: -> { skip_position_adjust }
@ -187,7 +188,14 @@ class Step < ApplicationRecord
private private
def run_observers def run_observers
AutomationObservers::AllCheckedStepsAutomationObserver.new(my_module, last_modified_by).call if saved_change_to_completed? && completed return unless protocol.in_module?
if saved_change_to_completed?
AutomationObservers::CompletedStepChangeAutomationObserver.new(my_module, last_modified_by).call if completed
AutomationObservers::AllCompletedStepsAutomationObserver.new(my_module, last_modified_by).call
end
AutomationObservers::ProtocolContentChangedAutomationObserver.new(self, last_modified_by).call
end end
def duplicate_table(new_step, user, table) def duplicate_table(new_step, user, table)

View file

@ -1,7 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
class StepComment < Comment class StepComment < Comment
include ObservableModel
before_create :fill_unseen_by before_create :fill_unseen_by
after_create :run_observers
belongs_to :step, foreign_key: :associated_id, inverse_of: :step_comments belongs_to :step, foreign_key: :associated_id, inverse_of: :step_comments
@ -16,4 +19,8 @@ class StepComment < Comment
def fill_unseen_by def fill_unseen_by
self.unseen_by += step.protocol.my_module.experiment.project.users.where.not(id: user.id).pluck(:id) self.unseen_by += step.protocol.my_module.experiment.project.users.where.not(id: user.id).pluck(:id)
end end
def run_observers
AutomationObservers::ProtocolContentChangedAutomationObserver.new(step, last_modified_by || user).call
end
end end

View file

@ -4,6 +4,7 @@ class StepOrderableElement < ApplicationRecord
validates :position, uniqueness: { scope: :step } validates :position, uniqueness: { scope: :step }
validate :check_step_relations validate :check_step_relations
after_create :run_observers
around_destroy :decrement_following_elements_positions around_destroy :decrement_following_elements_positions
belongs_to :step, inverse_of: :step_orderable_elements, touch: true belongs_to :step, inverse_of: :step_orderable_elements, touch: true
@ -26,4 +27,8 @@ class StepOrderableElement < ApplicationRecord
step.normalize_elements_position step.normalize_elements_position
end end
end end
def run_observers
AutomationObservers::ProtocolContentChangedAutomationObserver.new(step, step.last_modified_by).call
end
end end

View file

@ -3,6 +3,7 @@
class StepText < ApplicationRecord class StepText < ApplicationRecord
include TinyMceImages include TinyMceImages
include ActionView::Helpers::TextHelper include ActionView::Helpers::TextHelper
include ObservableModel
auto_strip_attributes :name, nullify: false auto_strip_attributes :name, nullify: false
validates :name, length: { maximum: Constants::NAME_MAX_LENGTH } validates :name, length: { maximum: Constants::NAME_MAX_LENGTH }
@ -38,4 +39,10 @@ class StepText < ApplicationRecord
new_step_text new_step_text
end end
end end
private
def run_observers
AutomationObservers::ProtocolContentChangedAutomationObserver.new(step, step.last_modified_by).call
end
end end

View file

@ -3,6 +3,7 @@
class Table < ApplicationRecord class Table < ApplicationRecord
include SearchableModel include SearchableModel
include TableHelper include TableHelper
include ObservableModel
auto_strip_attributes :name, nullify: false auto_strip_attributes :name, nullify: false
validates :name, validates :name,
@ -102,4 +103,8 @@ class Table < ApplicationRecord
end end
end end
end end
def run_observers
AutomationObservers::ProtocolContentChangedAutomationObserver.new(step, step&.last_modified_by).call
end
end end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
module AutomationObservers module AutomationObservers
class AllCheckedStepsAutomationObserver class AllCompletedStepsAutomationObserver
def initialize(my_module, user) def initialize(my_module, user)
@my_module = my_module @my_module = my_module
@user = user @user = user

View file

@ -0,0 +1,30 @@
# frozen_string_literal: true
module AutomationObservers
class CompletedStepChangeAutomationObserver
def initialize(my_module, user)
@my_module = my_module
@user = user
end
def call
return unless @my_module.team.settings.dig('team_automation_settings', 'step_marked_as_completed')
return unless @my_module.my_module_status.initial_status?
previous_status_id = @my_module.my_module_status.id
@my_module.update!(my_module_status: @my_module.my_module_status.next_status)
Activities::CreateActivityService
.call(activity_type: :automation_task_status_changed,
owner: @user,
team: @my_module.team,
project: @my_module.project,
subject: @my_module,
message_items: {
my_module: @my_module.id,
my_module_status_old: previous_status_id,
my_module_status_new: @my_module.my_module_status.id
})
end
end
end

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
module AutomationObservers
class ProtocolContentChangedAutomationObserver
def initialize(step, user)
@step = step
@my_module = step&.my_module
@user = user
end
def call
return if @step.blank?
return unless @step.protocol.in_module?
return unless @my_module.team.settings.dig('team_automation_settings', 'protocol_content_added')
return unless @my_module.my_module_status.initial_status?
previous_status_id = @my_module.my_module_status.id
@my_module.update!(my_module_status: @my_module.my_module_status.next_status)
Activities::CreateActivityService
.call(activity_type: :automation_task_status_changed,
owner: @user,
team: @my_module.team,
project: @my_module.project,
subject: @my_module,
message_items: {
my_module: @my_module.id,
my_module_status_old: previous_status_id,
my_module_status_new: @my_module.my_module_status.id
})
end
end
end

View file

@ -0,0 +1,30 @@
# frozen_string_literal: true
module AutomationObservers
class ResultCreateAutomationObserver
def initialize(my_module, user)
@my_module = my_module
@user = user
end
def call
return @my_module.team.settings.dig('team_automation_settings', 'task_result_added') unless @my_module.team.settings.dig('team_automation_settings', 'task_result_added')
return unless @my_module.my_module_status.initial_status?
previous_status_id = @my_module.my_module_status.id
@my_module.update!(my_module_status: @my_module.my_module_status.next_status)
Activities::CreateActivityService
.call(activity_type: :automation_task_status_changed,
owner: @user,
team: @my_module.team,
project: @my_module.project,
subject: @my_module,
message_items: {
my_module: @my_module.id,
my_module_status_old: previous_status_id,
my_module_status_new: @my_module.my_module_status.id
})
end
end
end