diff --git a/app/models/assignment.rb b/app/models/assignment.rb index 6803a2df..985dd969 100644 --- a/app/models/assignment.rb +++ b/app/models/assignment.rb @@ -63,42 +63,12 @@ def notifications def create_missing_notifications!(mark_as_read: false) assigned_users.each do |user| next if notifications.for_user(user).exists? - create_missing_notification(user: user, mark_as_read: mark_as_read) - end - end - - def create_missing_notification(user:, mark_as_read:) - Assigner.publish_topic_tracking_state(topic, user.id) - unless assigned_by_user == user || mark_as_read - PostAlerter.new(post).create_notification_alert( + DiscourseAssign::CreateNotification.call( + assignment: self, user: user, - post: post, - username: assigned_by_user.username, - notification_type: Notification.types[:assigned], - excerpt: - I18n.t( - excerpt_key, - title: topic.title, - group: assigned_to.name, - locale: user.effective_locale, - ), + mark_as_read: mark_as_read || assigned_by_user == user, ) end - notifications.create!( - created_at: created_at, - updated_at: updated_at, - user: user, - topic: topic, - post_number: post.post_number, - high_priority: true, - read: assigned_by_user == user || mark_as_read, - data: { - message: notification_message, - display_username: assigned_to_user? ? assigned_by_user.username : assigned_to.name, - topic_title: topic.title, - assignment_id: id, - }.to_json, - ) end private @@ -112,16 +82,6 @@ def validate_status errors.add(:status, :invalid) end end - - def excerpt_key - return "discourse_assign.topic_assigned_excerpt" if assigned_to_user? - "discourse_assign.topic_group_assigned_excerpt" - end - - def notification_message - return "discourse_assign.assign_notification" if assigned_to_user? - "discourse_assign.assign_group_notification" - end end # == Schema Information diff --git a/lib/discourse_assign/create_notification.rb b/lib/discourse_assign/create_notification.rb new file mode 100644 index 00000000..a1582749 --- /dev/null +++ b/lib/discourse_assign/create_notification.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +module DiscourseAssign + class CreateNotification + def self.call(...) + new(...).call + end + + attr_reader :assignment, :user, :mark_as_read + alias mark_as_read? mark_as_read + + delegate :topic, + :post, + :assigned_by_user, + :assigned_to, + :notifications, + :created_at, + :updated_at, + :assigned_to_user?, + :id, + to: :assignment, + private: true + + def initialize(assignment:, user:, mark_as_read:) + @assignment = assignment + @user = user + @mark_as_read = mark_as_read + end + + def call + Assigner.publish_topic_tracking_state(topic, user.id) + unless mark_as_read? + PostAlerter.new(post).create_notification_alert( + user: user, + post: post, + username: assigned_by_user.username, + notification_type: Notification.types[:assigned], + excerpt: + I18n.t( + excerpt_key, + title: topic.title, + group: assigned_to.name, + locale: user.effective_locale, + ), + ) + end + notifications.create!( + created_at: created_at, + updated_at: updated_at, + user: user, + topic: topic, + post_number: post.post_number, + high_priority: true, + read: mark_as_read?, + data: { + message: notification_message, + display_username: display_username, + topic_title: topic.title, + assignment_id: id, + }.to_json, + ) + end + + private + + def excerpt_key + return "discourse_assign.topic_assigned_excerpt" if assigned_to_user? + "discourse_assign.topic_group_assigned_excerpt" + end + + def notification_message + return "discourse_assign.assign_notification" if assigned_to_user? + "discourse_assign.assign_group_notification" + end + + def display_username + return assigned_by_user.username if assigned_to_user? + assigned_to.name + end + end +end diff --git a/plugin.rb b/plugin.rb index 3f36e847..3b5ad186 100644 --- a/plugin.rb +++ b/plugin.rb @@ -26,6 +26,7 @@ module ::DiscourseAssign require_relative "app/jobs/regular/unassign_notification" require_relative "app/jobs/scheduled/enqueue_reminders" require_relative "lib/assigner" + require_relative "lib/discourse_assign/create_notification" require_relative "lib/discourse_assign/discourse_calendar" require_relative "lib/discourse_assign/group_extension" require_relative "lib/discourse_assign/helpers" diff --git a/spec/lib/discourse_assign/create_notification_spec.rb b/spec/lib/discourse_assign/create_notification_spec.rb new file mode 100644 index 00000000..d866b0d8 --- /dev/null +++ b/spec/lib/discourse_assign/create_notification_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe DiscourseAssign::CreateNotification do + describe ".call" do + subject(:create_notification) do + described_class.call(assignment: assignment, user: user, mark_as_read: mark_as_read) + end + + let(:assignment) { Fabricate(:topic_assignment, topic: post.topic) } + let(:post) { Fabricate(:post) } + let(:user) { assignment.assigned_to } + let(:mark_as_read) { false } + let(:alerter) { stub_everything("alerter").responds_like_instance_of(PostAlerter) } + + before { PostAlerter.stubs(:new).returns(alerter) } + + it "publishes topic tracking state" do + Assigner.expects(:publish_topic_tracking_state).with(assignment.topic, user.id) + create_notification + end + + context "when `mark_as_read` is false" do + let(:excerpt) do + I18n.t( + "discourse_assign.topic_assigned_excerpt", + title: post.topic.title, + group: user.name, + locale: user.effective_locale, + ) + end + + it "creates a notification alert" do + alerter.expects(:create_notification_alert).with( + user: user, + post: post, + username: assignment.assigned_by_user.username, + notification_type: Notification.types[:assigned], + excerpt: excerpt, + ) + create_notification + end + end + + context "when `mark_as_read` is true" do + let(:mark_as_read) { true } + + it "does not create a notification alert" do + alerter.expects(:create_notification_alert).never + create_notification + end + end + + it "creates a notification" do + expect { create_notification }.to change { Notification.count }.by(1) + expect(Notification.assigned.last).to have_attributes( + created_at: assignment.created_at, + updated_at: assignment.updated_at, + user: user, + topic: post.topic, + post_number: post.post_number, + high_priority: true, + read: false, + data_hash: { + message: "discourse_assign.assign_notification", + display_username: assignment.assigned_by_user.username, + topic_title: post.topic.title, + assignment_id: assignment.id, + }, + ) + end + end +end diff --git a/spec/models/assignment_spec.rb b/spec/models/assignment_spec.rb index 0236e38e..d877fef5 100644 --- a/spec/models/assignment_spec.rb +++ b/spec/models/assignment_spec.rb @@ -93,14 +93,15 @@ end it "does nothing" do - assignment.expects(:create_missing_notification).never + DiscourseAssign::CreateNotification.expects(:call).never create_missing_notifications end end context "when notification does not exist yet" do it "creates the missing notification" do - assignment.expects(:create_missing_notification).with( + DiscourseAssign::CreateNotification.expects(:call).with( + assignment: assignment, user: assigned_to, mark_as_read: false, ) @@ -124,82 +125,17 @@ end it "creates missing notifications for group users" do - assignment - .expects(:create_missing_notification) - .with(user: users.first, mark_as_read: false) + DiscourseAssign::CreateNotification + .expects(:call) + .with(assignment: assignment, user: users.first, mark_as_read: false) .never - assignment.expects(:create_missing_notification).with(user: users.last, mark_as_read: false) - create_missing_notifications - end - end - end - - describe "#create_missing_notification" do - subject(:create_notification) do - assignment.create_missing_notification(user: user, mark_as_read: mark_as_read) - end - - let(:assignment) { Fabricate(:topic_assignment, topic: post.topic) } - let(:post) { Fabricate(:post) } - let(:user) { assignment.assigned_to } - let(:mark_as_read) { false } - let(:alerter) { stub_everything("alerter").responds_like_instance_of(PostAlerter) } - - before { PostAlerter.stubs(:new).returns(alerter) } - - it "publishes topic tracking state" do - Assigner.expects(:publish_topic_tracking_state).with(assignment.topic, user.id) - create_notification - end - - context "when `mark_as_read` is false" do - let(:excerpt) do - I18n.t( - "discourse_assign.topic_assigned_excerpt", - title: post.topic.title, - group: user.name, - locale: user.effective_locale, + DiscourseAssign::CreateNotification.expects(:call).with( + assignment: assignment, + user: users.last, + mark_as_read: false, ) + create_missing_notifications end - - it "creates a notification alert" do - alerter.expects(:create_notification_alert).with( - user: user, - post: post, - username: assignment.assigned_by_user.username, - notification_type: Notification.types[:assigned], - excerpt: excerpt, - ) - create_notification - end - end - - context "when `mark_as_read` is true" do - let(:mark_as_read) { true } - - it "does not create a notification alert" do - alerter.expects(:create_notification_alert).never - create_notification - end - end - - it "creates a notification" do - expect { create_notification }.to change { Notification.count }.by(1) - expect(Notification.assigned.last).to have_attributes( - created_at: assignment.created_at, - updated_at: assignment.updated_at, - user: user, - topic: post.topic, - post_number: post.post_number, - high_priority: true, - read: false, - data_hash: { - message: "discourse_assign.assign_notification", - display_username: assignment.assigned_by_user.username, - topic_title: post.topic.title, - assignment_id: assignment.id, - }, - ) end end end