From 6116f2664278ca270e3efbc803223b1ed3579cdf Mon Sep 17 00:00:00 2001 From: Rafael dos Santos Silva Date: Mon, 25 Jul 2022 14:45:41 -0300 Subject: [PATCH] DEV: Apply syntax_tree formatting --- Gemfile | 2 +- .../discourse_assign/assign_controller.rb | 187 ++++--- app/mailers/assign_mailer.rb | 10 +- app/models/assign_mailer_site_settings.rb | 12 +- app/models/assignment.rb | 13 +- .../remind_assigns_frequency_site_settings.rb | 32 +- app/serializers/assigned_topic_serializer.rb | 7 +- .../group_user_assigned_serializer.rb | 5 +- ...190422200243_add_last_reminded_at_index.rb | 7 +- ...5428_add_reminds_assign_frequency_index.rb | 7 +- ...22_set_assign_allowed_on_groups_default.rb | 14 +- ...41_add_index_to_assigned_to_id_and_type.rb | 2 +- ...0211006223156_add_target_to_assignments.rb | 7 +- ...signments_from_custom_fields_to_a_table.rb | 1 - jobs/regular/assign_notification.rb | 44 +- jobs/regular/remind_user.rb | 2 +- jobs/regular/unassign_notification.rb | 24 +- jobs/scheduled/enqueue_reminders.rb | 13 +- lib/assigner.rb | 211 ++++---- lib/discourse_assign/helpers.rb | 38 +- lib/pending_assigns_reminder.rb | 103 ++-- lib/random_assign_utils.rb | 111 ++-- lib/topic_assigner.rb | 6 +- plugin.rb | 474 ++++++++++-------- spec/components/search_spec.rb | 57 ++- spec/components/topic_query_spec.rb | 131 ++--- spec/components/topics_bulk_action_spec.rb | 49 +- spec/fabricators/assign_hook_fabricator.rb | 6 +- spec/integration/assign_spec.rb | 50 +- spec/jobs/regular/assign_notification_spec.rb | 156 ++++-- spec/jobs/regular/remind_user_spec.rb | 8 +- .../regular/unassign_notification_spec.rb | 75 ++- spec/jobs/scheduled/enqueue_reminders_spec.rb | 31 +- spec/lib/assigner_spec.rb | 247 +++++---- spec/lib/pending_assigns_reminder_spec.rb | 63 ++- spec/lib/random_assign_utils_spec.rb | 215 +++++--- spec/lib/topic_query_spec.rb | 26 +- spec/models/group_spec.rb | 27 +- spec/models/reviewable_spec.rb | 22 +- spec/models/topic_spec.rb | 20 +- spec/models/user_custom_field_spec.rb | 8 +- spec/plugin_spec.rb | 12 +- spec/requests/assign_controller_spec.rb | 259 ++++++---- spec/requests/list_controller_spec.rb | 184 ++++--- .../flagged_topic_serializer_spec.rb | 55 +- .../serializers/group_show_serializer_spec.rb | 2 +- spec/serializers/post_serializer_spec.rb | 6 +- .../suggested_topic_serializer_spec.rb | 2 +- .../serializers/topic_list_serializer_spec.rb | 82 ++- .../serializers/topic_view_serializer_spec.rb | 14 +- .../user_bookmark_base_serializer_spec.rb | 6 +- spec/support/assign_allowed_group.rb | 10 +- 52 files changed, 1871 insertions(+), 1284 deletions(-) diff --git a/Gemfile b/Gemfile index e54add51..3142de0a 100644 --- a/Gemfile +++ b/Gemfile @@ -5,4 +5,4 @@ source "https://rubygems.org" group :development do gem "rubocop-discourse", git: "https://github.com/discourse/rubocop-discourse/", branch: "stree" gem "syntax_tree" -end \ No newline at end of file +end diff --git a/app/controllers/discourse_assign/assign_controller.rb b/app/controllers/discourse_assign/assign_controller.rb index 436943e2..6de8740f 100644 --- a/app/controllers/discourse_assign/assign_controller.rb +++ b/app/controllers/discourse_assign/assign_controller.rb @@ -7,9 +7,10 @@ class AssignController < ApplicationController def suggestions users = [current_user] - users += User - .where('users.id <> ?', current_user.id) - .joins(<<~SQL + users += + User + .where("users.id <> ?", current_user.id) + .joins(<<~SQL) JOIN( SELECT assigned_to_id user_id, MAX(created_at) last_assigned FROM assignments @@ -18,16 +19,22 @@ def suggestions HAVING COUNT(*) < #{SiteSetting.max_assigned_topics} ) as X ON X.user_id = users.id SQL - ) - .assign_allowed - .order('X.last_assigned DESC') - .limit(6) + .assign_allowed + .order("X.last_assigned DESC") + .limit(6) render json: { - assign_allowed_on_groups: Group.visible_groups(current_user).assign_allowed_groups.pluck(:name), - assign_allowed_for_groups: Group.visible_groups(current_user).assignable(current_user).pluck(:name), - suggestions: ActiveModel::ArraySerializer.new(users, scope: guardian, each_serializer: BasicUserSerializer), - } + assign_allowed_on_groups: + Group.visible_groups(current_user).assign_allowed_groups.pluck(:name), + assign_allowed_for_groups: + Group.visible_groups(current_user).assignable(current_user).pluck(:name), + suggestions: + ActiveModel::ArraySerializer.new( + users, + scope: guardian, + each_serializer: BasicUserSerializer, + ), + } end def unassign @@ -46,11 +53,18 @@ def unassign def assign target_id = params.require(:target_id) target_type = params.require(:target_type) - username = params.permit(:username)['username'] - group_name = params.permit(:group_name)['group_name'] - note = params.permit(:note)['note'].presence - - assign_to = username.present? ? User.find_by(username_lower: username.downcase) : Group.where("LOWER(name) = ?", group_name.downcase).first + username = params.permit(:username)["username"] + group_name = params.permit(:group_name)["group_name"] + note = params.permit(:note)["note"].presence + + assign_to = + ( + if username.present? + User.find_by(username_lower: username.downcase) + else + Group.where("LOWER(name) = ?", group_name.downcase).first + end + ) raise Discourse::NotFound unless assign_to raise Discourse::NotFound if !Assignment.valid_type?(target_type) @@ -72,23 +86,31 @@ def assigned offset = (params[:offset] || 0).to_i limit = (params[:limit] || 100).to_i - topics = Topic - .includes(:tags) - .includes(:user) - .joins("JOIN assignments a ON a.target_id = topics.id AND a.target_type = 'Topic' AND a.assigned_to_id IS NOT NULL") - .order("a.assigned_to_id, topics.bumped_at desc") - .offset(offset) - .limit(limit) + topics = + Topic + .includes(:tags) + .includes(:user) + .joins( + "JOIN assignments a ON a.target_id = topics.id AND a.target_type = 'Topic' AND a.assigned_to_id IS NOT NULL", + ) + .order("a.assigned_to_id, topics.bumped_at desc") + .offset(offset) + .limit(limit) Topic.preload_custom_fields(topics, TopicList.preloaded_custom_fields) - topic_assignments = Assignment.where(target_id: topics.map(&:id), target_type: 'Topic', active: true).pluck(:target_id, :assigned_to_id).to_h + topic_assignments = + Assignment + .where(target_id: topics.map(&:id), target_type: "Topic", active: true) + .pluck(:target_id, :assigned_to_id) + .to_h - users = User - .where("users.id IN (?)", topic_assignments.values.uniq) - .joins("join user_emails on user_emails.user_id = users.id AND user_emails.primary") - .select(UserLookup.lookup_columns) - .to_a + users = + User + .where("users.id IN (?)", topic_assignments.values.uniq) + .joins("join user_emails on user_emails.user_id = users.id AND user_emails.primary") + .select(UserLookup.lookup_columns) + .to_a User.preload_custom_fields(users, User.allowed_user_custom_fields(guardian)) @@ -114,41 +136,41 @@ def group_members guardian.ensure_can_see_group_members!(group) - members = User - .joins("LEFT OUTER JOIN group_users g ON g.user_id = users.id") - .joins("LEFT OUTER JOIN assignments a ON a.assigned_to_id = users.id AND a.assigned_to_type = 'User'") - .joins("LEFT OUTER JOIN topics t ON t.id = a.target_id AND a.target_type = 'Topic'") - .where("g.group_id = ? AND users.id > 0 AND t.deleted_at IS NULL", group.id) - .where("a.assigned_to_id IS NOT NULL AND a.active") - .order('COUNT(users.id) DESC') - .group('users.id') - .select('users.*, COUNT(users.id) as "assignments_count"') - .limit(limit) - .offset(offset) - - if params[:filter] - members = members.where(<<~SQL, pattern: "%#{params[:filter]}%") + members = + User + .joins("LEFT OUTER JOIN group_users g ON g.user_id = users.id") + .joins( + "LEFT OUTER JOIN assignments a ON a.assigned_to_id = users.id AND a.assigned_to_type = 'User'", + ) + .joins("LEFT OUTER JOIN topics t ON t.id = a.target_id AND a.target_type = 'Topic'") + .where("g.group_id = ? AND users.id > 0 AND t.deleted_at IS NULL", group.id) + .where("a.assigned_to_id IS NOT NULL AND a.active") + .order("COUNT(users.id) DESC") + .group("users.id") + .select('users.*, COUNT(users.id) as "assignments_count"') + .limit(limit) + .offset(offset) + + members = members.where(<<~SQL, pattern: "%#{params[:filter]}%") if params[:filter] users.name ILIKE :pattern OR users.username_lower ILIKE :pattern SQL - end - group_assignments = Topic - .joins("JOIN assignments a ON a.topic_id = topics.id") - .where(<<~SQL, group_id: group.id) + group_assignments = + Topic + .joins("JOIN assignments a ON a.topic_id = topics.id") + .where(<<~SQL, group_id: group.id) a.assigned_to_id = :group_id AND a.assigned_to_type = 'Group' AND a.active SQL - .pluck(:topic_id) + .pluck(:topic_id) - assignments = TopicQuery - .new(current_user) - .group_topics_assigned_results(group) - .pluck('topics.id') + assignments = + TopicQuery.new(current_user).group_topics_assigned_results(group).pluck("topics.id") render json: { - members: serialize_data(members, GroupUserAssignedSerializer), - assignment_count: (assignments | group_assignments).count, - group_assignment_count: group_assignments.count - } + members: serialize_data(members, GroupUserAssignedSerializer), + assignment_count: (assignments | group_assignments).count, + group_assignment_count: group_assignments.count, + } end private @@ -156,26 +178,59 @@ def group_members def translate_failure(reason, assign_to) case reason when :already_assigned - { error: I18n.t('discourse_assign.already_assigned', username: assign_to.username) } + { error: I18n.t("discourse_assign.already_assigned", username: assign_to.username) } when :forbidden_assign_to - { error: I18n.t('discourse_assign.forbidden_assign_to', username: assign_to.username) } + { error: I18n.t("discourse_assign.forbidden_assign_to", username: assign_to.username) } when :forbidden_assignee_not_pm_participant - { error: I18n.t('discourse_assign.forbidden_assignee_not_pm_participant', username: assign_to.username) } + { + error: + I18n.t( + "discourse_assign.forbidden_assignee_not_pm_participant", + username: assign_to.username, + ), + } when :forbidden_assignee_cant_see_topic - { error: I18n.t('discourse_assign.forbidden_assignee_cant_see_topic', username: assign_to.username) } + { + error: + I18n.t( + "discourse_assign.forbidden_assignee_cant_see_topic", + username: assign_to.username, + ), + } when :group_already_assigned - { error: I18n.t('discourse_assign.group_already_assigned', group: assign_to.name) } + { error: I18n.t("discourse_assign.group_already_assigned", group: assign_to.name) } when :forbidden_group_assign_to - { error: I18n.t('discourse_assign.forbidden_group_assign_to', group: assign_to.name) } + { error: I18n.t("discourse_assign.forbidden_group_assign_to", group: assign_to.name) } when :forbidden_group_assignee_not_pm_participant - { error: I18n.t('discourse_assign.forbidden_group_assignee_not_pm_participant', group: assign_to.name) } + { + error: + I18n.t( + "discourse_assign.forbidden_group_assignee_not_pm_participant", + group: assign_to.name, + ), + } when :forbidden_group_assignee_cant_see_topic - { error: I18n.t('discourse_assign.forbidden_group_assignee_cant_see_topic', group: assign_to.name) } + { + error: + I18n.t( + "discourse_assign.forbidden_group_assignee_cant_see_topic", + group: assign_to.name, + ), + } when :too_many_assigns_for_topic - { error: I18n.t('discourse_assign.too_many_assigns_for_topic', limit: Assigner::ASSIGNMENTS_PER_TOPIC_LIMIT) } + { + error: + I18n.t( + "discourse_assign.too_many_assigns_for_topic", + limit: Assigner::ASSIGNMENTS_PER_TOPIC_LIMIT, + ), + } else max = SiteSetting.max_assigned_topics - { error: I18n.t('discourse_assign.too_many_assigns', username: assign_to.username, max: max) } + { + error: + I18n.t("discourse_assign.too_many_assigns", username: assign_to.username, max: max), + } end end diff --git a/app/mailers/assign_mailer.rb b/app/mailers/assign_mailer.rb index 7d89575b..82ab16b8 100644 --- a/app/mailers/assign_mailer.rb +++ b/app/mailers/assign_mailer.rb @@ -1,23 +1,21 @@ # frozen_string_literal: true -require_dependency 'email/message_builder' +require_dependency "email/message_builder" class AssignMailer < ActionMailer::Base include Email::BuildEmailHelper def self.levels - @levels ||= Enum.new(never: 'never', - different_users: 'different_users', - always: 'always') + @levels ||= Enum.new(never: "never", different_users: "different_users", always: "always") end def send_assignment(to_address, topic, assigned_by) opts = { - template: 'assign_mailer', + template: "assign_mailer", topic_title: topic.title, assignee_name: assigned_by.username, topic_excerpt: topic.excerpt, - topic_link: topic.url + topic_link: topic.url, } build_email(to_address, opts) end diff --git a/app/models/assign_mailer_site_settings.rb b/app/models/assign_mailer_site_settings.rb index 83238a87..78f751e0 100644 --- a/app/models/assign_mailer_site_settings.rb +++ b/app/models/assign_mailer_site_settings.rb @@ -1,18 +1,20 @@ # frozen_string_literal: true -require_dependency 'enum_site_setting' +require_dependency "enum_site_setting" class AssignMailerSiteSettings < EnumSiteSetting - def self.valid_value?(val) values.any? { |v| v[:value].to_s == val.to_s } end def self.values @values ||= [ - { name: 'discourse_assign.assign_mailer.never', value: AssignMailer.levels[:never] }, - { name: 'discourse_assign.assign_mailer.different_users', value: AssignMailer.levels[:different_users] }, - { name: 'discourse_assign.assign_mailer.always', value: AssignMailer.levels[:always] } + { name: "discourse_assign.assign_mailer.never", value: AssignMailer.levels[:never] }, + { + name: "discourse_assign.assign_mailer.different_users", + value: AssignMailer.levels[:different_users], + }, + { name: "discourse_assign.assign_mailer.always", value: AssignMailer.levels[:always] }, ] end diff --git a/app/models/assignment.rb b/app/models/assignment.rb index 48d2c182..a2eb8fe8 100644 --- a/app/models/assignment.rb +++ b/app/models/assignment.rb @@ -1,25 +1,30 @@ # frozen_string_literal: true class Assignment < ActiveRecord::Base - VALID_TYPES = %w(topic post).freeze + VALID_TYPES = %w[topic post].freeze belongs_to :topic belongs_to :assigned_to, polymorphic: true belongs_to :assigned_by_user, class_name: "User" belongs_to :target, polymorphic: true - scope :joins_with_topics, -> { joins("INNER JOIN topics ON topics.id = assignments.target_id AND assignments.target_type = 'Topic' AND topics.deleted_at IS NULL") } + scope :joins_with_topics, + -> { + joins( + "INNER JOIN topics ON topics.id = assignments.target_id AND assignments.target_type = 'Topic' AND topics.deleted_at IS NULL", + ) + } def self.valid_type?(type) VALID_TYPES.include?(type.downcase) end def assigned_to_user? - assigned_to_type == 'User' + assigned_to_type == "User" end def assigned_to_group? - assigned_to_type == 'Group' + assigned_to_type == "Group" end end diff --git a/app/models/remind_assigns_frequency_site_settings.rb b/app/models/remind_assigns_frequency_site_settings.rb index 305d43a9..c806b8da 100644 --- a/app/models/remind_assigns_frequency_site_settings.rb +++ b/app/models/remind_assigns_frequency_site_settings.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true -require_dependency 'enum_site_setting' +require_dependency "enum_site_setting" class RemindAssignsFrequencySiteSettings < EnumSiteSetting - def self.valid_value?(val) - val.to_i.to_s == val.to_s && - values.any? { |v| v[:value] == val.to_i } + val.to_i.to_s == val.to_s && values.any? { |v| v[:value] == val.to_i } end DAILY_MINUTES = 24 * 60 * 1 @@ -16,25 +14,11 @@ def self.valid_value?(val) def self.values @values ||= [ - { - name: 'discourse_assign.reminders_frequency.never', value: 0 - }, - { - name: 'discourse_assign.reminders_frequency.daily', - value: DAILY_MINUTES - }, - { - name: 'discourse_assign.reminders_frequency.weekly', - value: WEEKLY_MINUTES - }, - { - name: 'discourse_assign.reminders_frequency.monthly', - value: MONTHLY_MINUTES - }, - { - name: 'discourse_assign.reminders_frequency.quarterly', - value: QUARTERLY_MINUTES - } + { name: "discourse_assign.reminders_frequency.never", value: 0 }, + { name: "discourse_assign.reminders_frequency.daily", value: DAILY_MINUTES }, + { name: "discourse_assign.reminders_frequency.weekly", value: WEEKLY_MINUTES }, + { name: "discourse_assign.reminders_frequency.monthly", value: MONTHLY_MINUTES }, + { name: "discourse_assign.reminders_frequency.quarterly", value: QUARTERLY_MINUTES }, ] end @@ -45,7 +29,7 @@ def self.translate_names? def self.frequency_for(minutes) value = values.detect { |v| v[:value] == minutes } - raise Discourse::InvalidParameters(:task_reminders_frequency) if value.nil? + raise Discourse.InvalidParameters(:task_reminders_frequency) if value.nil? I18n.t(value[:name]) end diff --git a/app/serializers/assigned_topic_serializer.rb b/app/serializers/assigned_topic_serializer.rb index 80b08947..20ceebbb 100644 --- a/app/serializers/assigned_topic_serializer.rb +++ b/app/serializers/assigned_topic_serializer.rb @@ -3,12 +3,7 @@ class AssignedTopicSerializer < BasicTopicSerializer include TopicTagsMixin - attributes :excerpt, - :category_id, - :created_at, - :updated_at, - :assigned_to_user, - :assigned_to_group + attributes :excerpt, :category_id, :created_at, :updated_at, :assigned_to_user, :assigned_to_group has_one :user, serializer: BasicUserSerializer, embed: :objects diff --git a/app/serializers/group_user_assigned_serializer.rb b/app/serializers/group_user_assigned_serializer.rb index b670e5c6..41c2e01b 100644 --- a/app/serializers/group_user_assigned_serializer.rb +++ b/app/serializers/group_user_assigned_serializer.rb @@ -1,12 +1,9 @@ # frozen_string_literal: true class GroupUserAssignedSerializer < BasicUserSerializer - - attributes :assignments_count, - :username_lower + attributes :assignments_count, :username_lower def include_assignments_count object.can_assign? end - end diff --git a/db/migrate/20190422200243_add_last_reminded_at_index.rb b/db/migrate/20190422200243_add_last_reminded_at_index.rb index e322f740..36583c93 100644 --- a/db/migrate/20190422200243_add_last_reminded_at_index.rb +++ b/db/migrate/20190422200243_add_last_reminded_at_index.rb @@ -2,7 +2,10 @@ class AddLastRemindedAtIndex < ActiveRecord::Migration[5.2] def change - add_index :user_custom_fields, %i[name user_id], name: :idx_user_custom_fields_last_reminded_at, - unique: true, where: "name = 'last_reminded_at'" + add_index :user_custom_fields, + %i[name user_id], + name: :idx_user_custom_fields_last_reminded_at, + unique: true, + where: "name = 'last_reminded_at'" end end diff --git a/db/migrate/20190503145428_add_reminds_assign_frequency_index.rb b/db/migrate/20190503145428_add_reminds_assign_frequency_index.rb index 1cdf2a54..edfec1d4 100644 --- a/db/migrate/20190503145428_add_reminds_assign_frequency_index.rb +++ b/db/migrate/20190503145428_add_reminds_assign_frequency_index.rb @@ -2,7 +2,10 @@ class AddRemindsAssignFrequencyIndex < ActiveRecord::Migration[5.2] def change - add_index :user_custom_fields, %i[name user_id], name: :idx_user_custom_fields_remind_assigns_frequency, - unique: true, where: "name = 'remind_assigns_frequency'" + add_index :user_custom_fields, + %i[name user_id], + name: :idx_user_custom_fields_remind_assigns_frequency, + unique: true, + where: "name = 'remind_assigns_frequency'" end end diff --git a/db/migrate/20190718144722_set_assign_allowed_on_groups_default.rb b/db/migrate/20190718144722_set_assign_allowed_on_groups_default.rb index 004402e8..1a62fb38 100644 --- a/db/migrate/20190718144722_set_assign_allowed_on_groups_default.rb +++ b/db/migrate/20190718144722_set_assign_allowed_on_groups_default.rb @@ -2,15 +2,19 @@ class SetAssignAllowedOnGroupsDefault < ActiveRecord::Migration[5.2] def up - current_values = DB.query_single("SELECT value FROM site_settings WHERE name = 'assign_allowed_on_groups'").first + current_values = + DB.query_single( + "SELECT value FROM site_settings WHERE name = 'assign_allowed_on_groups'", + ).first # Dynamically sets the default value, supports older versions. if current_values.nil? min_version = 201_907_171_337_43 - migrated_site_setting = DB.query_single( - "SELECT schema_migrations.version FROM schema_migrations WHERE schema_migrations.version = '#{min_version}'" - ).first - default = migrated_site_setting.present? ? Group::AUTO_GROUPS[:staff] : 'staff' + migrated_site_setting = + DB.query_single( + "SELECT schema_migrations.version FROM schema_migrations WHERE schema_migrations.version = '#{min_version}'", + ).first + default = migrated_site_setting.present? ? Group::AUTO_GROUPS[:staff] : "staff" execute "INSERT INTO site_settings (name, data_type, value, created_at, updated_at) VALUES ('assign_allowed_on_groups', #{SiteSettings::TypeSupervisor.types[:group_list]}, '#{default}', now(), now())" diff --git a/db/migrate/20210908060141_add_index_to_assigned_to_id_and_type.rb b/db/migrate/20210908060141_add_index_to_assigned_to_id_and_type.rb index d11dfc86..bde5074e 100644 --- a/db/migrate/20210908060141_add_index_to_assigned_to_id_and_type.rb +++ b/db/migrate/20210908060141_add_index_to_assigned_to_id_and_type.rb @@ -2,6 +2,6 @@ class AddIndexToAssignedToIdAndType < ActiveRecord::Migration[6.1] def change - add_index :assignments, [:assigned_to_id, :assigned_to_type] + add_index :assignments, %i[assigned_to_id assigned_to_type] end end diff --git a/db/migrate/20211006223156_add_target_to_assignments.rb b/db/migrate/20211006223156_add_target_to_assignments.rb index b6d45d25..00555f82 100644 --- a/db/migrate/20211006223156_add_target_to_assignments.rb +++ b/db/migrate/20211006223156_add_target_to_assignments.rb @@ -14,8 +14,11 @@ def up change_column :assignments, :target_id, :integer, null: false change_column :assignments, :target_type, :string, null: false - add_index :assignments, [:target_id, :target_type], unique: true - add_index :assignments, [:assigned_to_id, :assigned_to_type, :target_id, :target_type], unique: true, name: 'unique_target_and_assigned' + add_index :assignments, %i[target_id target_type], unique: true + add_index :assignments, + %i[assigned_to_id assigned_to_type target_id target_type], + unique: true, + name: "unique_target_and_assigned" end def down diff --git a/db/post_migrate/20210714173022_correctly_move_assignments_from_custom_fields_to_a_table.rb b/db/post_migrate/20210714173022_correctly_move_assignments_from_custom_fields_to_a_table.rb index 616f7c54..5bf6ce09 100644 --- a/db/post_migrate/20210714173022_correctly_move_assignments_from_custom_fields_to_a_table.rb +++ b/db/post_migrate/20210714173022_correctly_move_assignments_from_custom_fields_to_a_table.rb @@ -41,7 +41,6 @@ def up ORDER BY assigned_by.created_at DESC ON CONFLICT DO NOTHING SQL - else execute <<~SQL INSERT INTO assignments (assigned_to_id, assigned_by_user_id, topic_id, created_at, updated_at) diff --git a/jobs/regular/assign_notification.rb b/jobs/regular/assign_notification.rb index 4c3770c8..1bacfdfe 100644 --- a/jobs/regular/assign_notification.rb +++ b/jobs/regular/assign_notification.rb @@ -8,12 +8,21 @@ def execute(args) raise Discourse::InvalidParameters.new(:assigned_to_id) if args[:assigned_to_id].nil? raise Discourse::InvalidParameters.new(:assigned_to_type) if args[:assigned_to_type].nil? raise Discourse::InvalidParameters.new(:assigned_by_id) if args[:assigned_by_id].nil? - raise Discourse::InvalidParameters.new(:skip_small_action_post) if args[:skip_small_action_post].nil? + if args[:skip_small_action_post].nil? + raise Discourse::InvalidParameters.new(:skip_small_action_post) + end topic = Topic.find(args[:topic_id]) post = Post.find(args[:post_id]) assigned_by = User.find(args[:assigned_by_id]) - assigned_to = args[:assigned_to_type] == "User" ? User.find(args[:assigned_to_id]) : Group.find(args[:assigned_to_id]) + assigned_to = + ( + if args[:assigned_to_type] == "User" + User.find(args[:assigned_to_id]) + else + Group.find(args[:assigned_to_id]) + end + ) assigned_to_users = args[:assigned_to_type] == "User" ? [assigned_to] : assigned_to.users assigned_to_users.each do |user| @@ -29,12 +38,18 @@ def execute(args) username: assigned_by.username, notification_type: Notification.types[:assigned] || Notification.types[:custom], excerpt: - I18n.t( - (assigned_to_user ? "discourse_assign.topic_assigned_excerpt" : "discourse_assign.topic_group_assigned_excerpt"), - title: topic.title, - group: assigned_to.name, - locale: user.effective_locale - ) + I18n.t( + ( + if assigned_to_user + "discourse_assign.topic_assigned_excerpt" + else + "discourse_assign.topic_group_assigned_excerpt" + end + ), + title: topic.title, + group: assigned_to.name, + locale: user.effective_locale, + ), ) next if args[:skip_small_action_post] @@ -45,10 +60,17 @@ def execute(args) post_number: post.post_number, high_priority: true, data: { - message: assigned_to_user ? 'discourse_assign.assign_notification' : 'discourse_assign.assign_group_notification', + message: + ( + if assigned_to_user + "discourse_assign.assign_notification" + else + "discourse_assign.assign_group_notification" + end + ), display_username: assigned_to_user ? assigned_by.username : assigned_to.name, - topic_title: topic.title - }.to_json + topic_title: topic.title, + }.to_json, ) end end diff --git a/jobs/regular/remind_user.rb b/jobs/regular/remind_user.rb index bbcbffa8..e8c4b6cc 100644 --- a/jobs/regular/remind_user.rb +++ b/jobs/regular/remind_user.rb @@ -2,7 +2,7 @@ module Jobs class RemindUser < ::Jobs::Base - sidekiq_options queue: 'low' + sidekiq_options queue: "low" def execute(args) user = User.find_by(id: args[:user_id]) diff --git a/jobs/regular/unassign_notification.rb b/jobs/regular/unassign_notification.rb index f33dc563..cdbe4cf7 100644 --- a/jobs/regular/unassign_notification.rb +++ b/jobs/regular/unassign_notification.rb @@ -8,16 +8,28 @@ def execute(args) raise Discourse::InvalidParameters.new(:assigned_to_type) if args[:assigned_to_type].nil? topic = Topic.find(args[:topic_id]) - assigned_to_users = args[:assigned_to_type] == "User" ? [User.find(args[:assigned_to_id])] : Group.find(args[:assigned_to_id]).users + assigned_to_users = + ( + if args[:assigned_to_type] == "User" + [User.find(args[:assigned_to_id])] + else + Group.find(args[:assigned_to_id]).users + end + ) assigned_to_users.each do |user| Assigner.publish_topic_tracking_state(topic, user.id) - Notification.where( - notification_type: Notification.types[:assigned] || Notification.types[:custom], - user_id: user.id, - topic_id: topic.id, - ).where("data like '%discourse_assign.assign_notification%' OR data like '%discourse_assign.assign_group_notification%'").destroy_all + Notification + .where( + notification_type: Notification.types[:assigned] || Notification.types[:custom], + user_id: user.id, + topic_id: topic.id, + ) + .where( + "data like '%discourse_assign.assign_notification%' OR data like '%discourse_assign.assign_group_notification%'", + ) + .destroy_all end end end diff --git a/jobs/scheduled/enqueue_reminders.rb b/jobs/scheduled/enqueue_reminders.rb index dc6756ad..c5cb59ed 100644 --- a/jobs/scheduled/enqueue_reminders.rb +++ b/jobs/scheduled/enqueue_reminders.rb @@ -12,18 +12,22 @@ def execute(_args) private def skip_enqueue? - SiteSetting.remind_assigns_frequency.nil? || !SiteSetting.assign_enabled? || SiteSetting.assign_allowed_on_groups.blank? + SiteSetting.remind_assigns_frequency.nil? || !SiteSetting.assign_enabled? || + SiteSetting.assign_allowed_on_groups.blank? end def allowed_group_ids - Group.assign_allowed_groups.pluck(:id).join(',') + Group.assign_allowed_groups.pluck(:id).join(",") end def user_ids global_frequency = SiteSetting.remind_assigns_frequency - frequency = ActiveRecord::Base.sanitize_sql("COALESCE(user_frequency.value, '#{global_frequency}')::INT") + frequency = + ActiveRecord::Base.sanitize_sql( + "COALESCE(user_frequency.value, '#{global_frequency}')::INT", + ) - DB.query_single(<<~SQL + DB.query_single(<<~SQL) SELECT assignments.assigned_to_id FROM assignments @@ -50,7 +54,6 @@ def user_ids GROUP BY assignments.assigned_to_id HAVING COUNT(assignments.assigned_to_id) > 1 SQL - ) end end end diff --git a/lib/assigner.rb b/lib/assigner.rb index baf4a1e5..4de3fbc0 100644 --- a/lib/assigner.rb +++ b/lib/assigner.rb @@ -1,17 +1,18 @@ # frozen_string_literal: true -require 'email/sender' -require 'nokogiri' +require "email/sender" +require "nokogiri" class ::Assigner ASSIGNMENTS_PER_TOPIC_LIMIT = 5 def self.backfill_auto_assign - staff_mention = User - .assign_allowed - .pluck('username') - .map { |name| "p.cooked ILIKE '%mention%@#{name}%'" } - .join(' OR ') + staff_mention = + User + .assign_allowed + .pluck("username") + .map { |name| "p.cooked ILIKE '%mention%@#{name}%'" } + .join(" OR ") sql = <<~SQL SELECT p.topic_id, MAX(post_number) post_number @@ -29,11 +30,16 @@ def self.backfill_auto_assign puts assigned = 0 - ActiveRecord::Base.connection.raw_connection.exec(sql).to_a.each do |row| - post = Post.find_by(post_number: row["post_number"].to_i, topic_id: row["topic_id"].to_i) - assigned += 1 if post && auto_assign(post) - putc "." - end + ActiveRecord::Base + .connection + .raw_connection + .exec(sql) + .to_a + .each do |row| + post = Post.find_by(post_number: row["post_number"].to_i, topic_id: row["topic_id"].to_i) + assigned += 1 if post && auto_assign(post) + putc "." + end puts puts "#{assigned} topics where automatically assigned to staff members" @@ -41,13 +47,23 @@ def self.backfill_auto_assign def self.assigned_self?(text) return false if text.blank? || SiteSetting.assign_self_regex.blank? - regex = Regexp.new(SiteSetting.assign_self_regex) rescue nil + regex = + begin + Regexp.new(SiteSetting.assign_self_regex) + rescue StandardError + nil + end !!(regex && text[regex]) end def self.assigned_other?(text) return false if text.blank? || SiteSetting.assign_other_regex.blank? - regex = Regexp.new(SiteSetting.assign_other_regex) rescue nil + regex = + begin + Regexp.new(SiteSetting.assign_other_regex) + rescue StandardError + nil + end !!(regex && text[regex]) end @@ -78,7 +94,7 @@ def self.auto_assign(post, force: false) end def self.is_last_staff_post?(post) - allowed_user_ids = User.assign_allowed.pluck(:id).join(',') + allowed_user_ids = User.assign_allowed.pluck(:id).join(",") sql = <<~SQL SELECT 1 @@ -90,10 +106,7 @@ def self.is_last_staff_post?(post) HAVING MAX(post_number) = :post_number SQL - args = { - topic_id: post.topic_id, - post_number: post.post_number - } + args = { topic_id: post.topic_id, post_number: post.post_number } DB.exec(sql, args) == 1 end @@ -101,20 +114,13 @@ def self.is_last_staff_post?(post) def self.mentioned_staff(post) mentions = post.raw_mentions if mentions.present? - User.human_users - .assign_allowed - .where('username_lower IN (?)', mentions.map(&:downcase)) - .first + User.human_users.assign_allowed.where("username_lower IN (?)", mentions.map(&:downcase)).first end end def self.publish_topic_tracking_state(topic, user_id) if topic.private_message? - MessageBus.publish( - "/private-messages/assigned", - { topic_id: topic.id }, - user_ids: [user_id] - ) + MessageBus.publish("/private-messages/assigned", { topic_id: topic.id }, user_ids: [user_id]) end end @@ -135,11 +141,12 @@ def can_assign_to?(assign_to) return true if assign_to.is_a?(Group) return true if @assigned_by.id == assign_to.id - assigned_total = Assignment - .joins_with_topics - .where(topics: { deleted_at: nil }) - .where(assigned_to_id: assign_to.id, active: true) - .count + assigned_total = + Assignment + .joins_with_topics + .where(topics: { deleted_at: nil }) + .where(assigned_to_id: assign_to.id, active: true) + .count assigned_total < SiteSetting.max_assigned_topics end @@ -165,7 +172,10 @@ def private_message_allowed_user_ids end def can_assignee_see_target?(assignee) - return false if (topic_target? || post_target?) && topic.private_message? && !private_message_allowed_user_ids.include?(assignee.id) + if (topic_target? || post_target?) && topic.private_message? && + !private_message_allowed_user_ids.include?(assignee.id) + return false + end return Guardian.new(assignee).can_see_topic?(@target) if topic_target? return Guardian.new(assignee).can_see_post?(@target) if post_target? @@ -188,9 +198,17 @@ def first_post def forbidden_reasons(assign_to:, type:, note:) case when assign_to.is_a?(User) && !can_assignee_see_target?(assign_to) - topic.private_message? ? :forbidden_assignee_not_pm_participant : :forbidden_assignee_cant_see_topic + if topic.private_message? + :forbidden_assignee_not_pm_participant + else + :forbidden_assignee_cant_see_topic + end when assign_to.is_a?(Group) && assign_to.users.any? { |user| !can_assignee_see_target?(user) } - topic.private_message? ? :forbidden_group_assignee_not_pm_participant : :forbidden_group_assignee_cant_see_topic + if topic.private_message? + :forbidden_group_assignee_not_pm_participant + else + :forbidden_group_assignee_cant_see_topic + end when !can_be_assigned?(assign_to) assign_to.is_a?(User) ? :forbidden_assign_to : :forbidden_group_assign_to when topic_same_assignee_and_note(assign_to, type, note) @@ -240,7 +258,14 @@ def assign(assign_to, note: nil, skip_small_action_post: false) @target.assignment&.destroy! - assignment = @target.create_assignment!(assigned_to_id: assign_to.id, assigned_to_type: assigned_to_type, assigned_by_user_id: @assigned_by.id, topic_id: topic.id, note: note) + assignment = + @target.create_assignment!( + assigned_to_id: assign_to.id, + assigned_to_type: assigned_to_type, + assigned_by_user_id: @assigned_by.id, + topic_id: topic.id, + note: note, + ) first_post.publish_change_to_clients!(:revised, reload_topic: true) @@ -250,19 +275,23 @@ def assign(assign_to, note: nil, skip_small_action_post: false) if assignment.assigned_to_user? if !TopicUser.exists?( - user_id: assign_to.id, - topic_id: topic.id, - notification_level: TopicUser.notification_levels[:watching] - ) + user_id: assign_to.id, + topic_id: topic.id, + notification_level: TopicUser.notification_levels[:watching], + ) TopicUser.change( assign_to.id, topic.id, notification_level: TopicUser.notification_levels[:watching], - notifications_reason_id: TopicUser.notification_reasons[:plugin_changed] + notifications_reason_id: TopicUser.notification_reasons[:plugin_changed], ) end - if SiteSetting.assign_mailer == AssignMailer.levels[:always] || (SiteSetting.assign_mailer == AssignMailer.levels[:different_users] && @assigned_by.id != assign_to.id) + if SiteSetting.assign_mailer == AssignMailer.levels[:always] || + ( + SiteSetting.assign_mailer == AssignMailer.levels[:different_users] && + @assigned_by.id != assign_to.id + ) if !topic.muted?(assign_to) message = AssignMailer.send_assignment(assign_to.email, topic, @assigned_by) Email::Sender.new(message, :assign_message).send @@ -283,18 +312,14 @@ def assign(assign_to, note: nil, skip_small_action_post: false) topic_id: topic.id, topic_title: topic.title, assigned_by_id: @assigned_by.id, - assigned_by_username: @assigned_by.username + assigned_by_username: @assigned_by.username, } if assignment.assigned_to_user? - payload.merge!({ - assigned_to_id: assign_to.id, - assigned_to_username: assign_to.username, - }) + payload.merge!({ assigned_to_id: assign_to.id, assigned_to_username: assign_to.username }) else - payload.merge!({ - assigned_to_group_id: assign_to.id, - assigned_to_group_name: assign_to.name, - }) + payload.merge!( + { assigned_to_group_id: assign_to.id, assigned_to_group_name: assign_to.name }, + ) end WebHook.enqueue_assign_hooks(assigned_to_type, payload.to_json) end @@ -310,24 +335,25 @@ def unassign(silent: false, deactivate: false) first_post.publish_change_to_clients!(:revised, reload_topic: true) - Jobs.enqueue(:unassign_notification, - topic_id: topic.id, - assigned_to_id: assignment.assigned_to.id, - assigned_to_type: assignment.assigned_to_type) + Jobs.enqueue( + :unassign_notification, + topic_id: topic.id, + assigned_to_id: assignment.assigned_to.id, + assigned_to_type: assignment.assigned_to_type, + ) if assignment.assigned_to_user? if TopicUser.exists?( - user_id: assignment.assigned_to_id, - topic: topic, - notification_level: TopicUser.notification_levels[:watching], - notifications_reason_id: TopicUser.notification_reasons[:plugin_changed] - ) - + user_id: assignment.assigned_to_id, + topic: topic, + notification_level: TopicUser.notification_levels[:watching], + notifications_reason_id: TopicUser.notification_reasons[:plugin_changed], + ) TopicUser.change( assignment.assigned_to_id, topic.id, notification_level: TopicUser.notification_levels[:tracking], - notifications_reason_id: TopicUser.notification_reasons[:plugin_changed] + notifications_reason_id: TopicUser.notification_reasons[:plugin_changed], ) end end @@ -337,7 +363,9 @@ def unassign(silent: false, deactivate: false) if SiteSetting.unassign_creates_tracking_post && !silent post_type = SiteSetting.assigns_public ? Post.types[:small_action] : Post.types[:whisper] - custom_fields = { "action_code_who" => assigned_to.is_a?(User) ? assigned_to.username : assigned_to.name } + custom_fields = { + "action_code_who" => assigned_to.is_a?(User) ? assigned_to.username : assigned_to.name, + } if post_target? custom_fields.merge!("action_code_path" => "/p/#{@target.id}") @@ -345,7 +373,8 @@ def unassign(silent: false, deactivate: false) end topic.add_moderator_post( - @assigned_by, nil, + @assigned_by, + nil, bump: false, post_type: post_type, custom_fields: custom_fields, @@ -361,18 +390,16 @@ def unassign(silent: false, deactivate: false) topic_id: topic.id, topic_title: topic.title, unassigned_by_id: @assigned_by.id, - unassigned_by_username: @assigned_by.username + unassigned_by_username: @assigned_by.username, } if assignment.assigned_to_user? - payload.merge!({ - unassigned_to_id: assigned_to.id, - unassigned_to_username: assigned_to.username, - }) + payload.merge!( + { unassigned_to_id: assigned_to.id, unassigned_to_username: assigned_to.username }, + ) else - payload.merge!({ - unassigned_to_group_id: assigned_to.id, - unassigned_to_group_name: assigned_to.name, - }) + payload.merge!( + { unassigned_to_group_id: assigned_to.id, unassigned_to_group_name: assigned_to.name }, + ) end WebHook.enqueue_assign_hooks(type, payload.to_json) end @@ -380,14 +407,14 @@ def unassign(silent: false, deactivate: false) MessageBus.publish( "/staff/topic-assignment", { - type: 'unassigned', + type: "unassigned", topic_id: topic.id, post_id: post_target? && @target.id, post_number: post_target? && @target.post_number, assigned_type: assignment.assigned_to.is_a?(User) ? "User" : "Group", assignment_note: nil, }, - user_ids: allowed_user_ids + user_ids: allowed_user_ids, ) end end @@ -395,20 +422,26 @@ def unassign(silent: false, deactivate: false) private def queue_notification(assign_to, skip_small_action_post) - Jobs.enqueue(:assign_notification, + Jobs.enqueue( + :assign_notification, topic_id: topic.id, post_id: topic_target? ? first_post.id : @target.id, assigned_to_id: assign_to.id, assigned_to_type: assign_to.is_a?(User) ? "User" : "Group", assigned_by_id: @assigned_by.id, - skip_small_action_post: skip_small_action_post) + skip_small_action_post: skip_small_action_post, + ) end def add_small_action_post(action_code, assign_to, note) - custom_fields = { "action_code_who" => assign_to.is_a?(User) ? assign_to.username : assign_to.name } + custom_fields = { + "action_code_who" => assign_to.is_a?(User) ? assign_to.username : assign_to.name, + } if post_target? - custom_fields.merge!({ "action_code_path" => "/p/#{@target.id}", "action_code_post_id" => @target.id }) + custom_fields.merge!( + { "action_code_path" => "/p/#{@target.id}", "action_code_post_id" => @target.id }, + ) end topic.add_moderator_post( @@ -417,7 +450,7 @@ def add_small_action_post(action_code, assign_to, note) bump: false, post_type: SiteSetting.assigns_public ? Post.types[:small_action] : Post.types[:whisper], action_code: action_code, - custom_fields: custom_fields + custom_fields: custom_fields, ) end @@ -434,7 +467,7 @@ def publish_assignment(assignment, assign_to, note) assigned_to: serializer.new(assign_to, scope: Guardian.new, root: false).as_json, assignment_note: note, }, - user_ids: allowed_user_ids + user_ids: allowed_user_ids, ) end @@ -460,18 +493,18 @@ def moderator_post_unassign_action_code(assignment) def topic_same_assignee_and_note(assign_to, type, note) topic.assignment&.assigned_to_id == assign_to.id && - topic.assignment&.assigned_to_type == type && - topic.assignment.active == true && + topic.assignment&.assigned_to_type == type && topic.assignment.active == true && topic.assignment&.note == note end def post_same_assignee_and_note(assign_to, type, note) @target.is_a?(Topic) && - Assignment.where(topic_id: topic.id, target_type: "Post", active: true).any? do |assignment| - assignment.assigned_to_id == assign_to.id && - assignment.assigned_to_type == type && - assignment&.note == note - end + Assignment + .where(topic_id: topic.id, target_type: "Post", active: true) + .any? do |assignment| + assignment.assigned_to_id == assign_to.id && assignment.assigned_to_type == type && + assignment&.note == note + end end def no_assignee_change?(assignee) diff --git a/lib/discourse_assign/helpers.rb b/lib/discourse_assign/helpers.rb index cc44bf11..55288bbd 100644 --- a/lib/discourse_assign/helpers.rb +++ b/lib/discourse_assign/helpers.rb @@ -8,7 +8,7 @@ def self.build_assigned_to_user(user, topic) username: user.username, name: user.name, avatar_template: user.avatar_template, - assign_icon: 'user-plus', + assign_icon: "user-plus", assign_path: SiteSetting.assigns_user_url_path.gsub("{username}", user.username), } end @@ -22,23 +22,39 @@ def self.build_assigned_to_group(group, topic) flair_color: group.flair_color, flair_icon: group.flair_icon, flair_upload_id: group.flair_upload_id, - assign_icon: 'group-plus', + assign_icon: "group-plus", assign_path: "/g/#{group.name}/assigned/everyone", } end def self.build_indirectly_assigned_to(post_assignments, topic) - post_assignments.map do |post_id, assigned_map| - assigned_to = assigned_map[:assigned_to] - note = assigned_map[:assignment_note] - post_number = assigned_map[:post_number] + post_assignments + .map do |post_id, assigned_map| + assigned_to = assigned_map[:assigned_to] + note = assigned_map[:assignment_note] + post_number = assigned_map[:post_number] - if (assigned_to.is_a?(User)) - [post_id, { assigned_to: build_assigned_to_user(assigned_to, topic), post_number: post_number, assignment_note: note }] - elsif assigned_to.is_a?(Group) - [post_id, { assigned_to: build_assigned_to_group(assigned_to, topic), post_number: post_number, assignment_note: note }] + if (assigned_to.is_a?(User)) + [ + post_id, + { + assigned_to: build_assigned_to_user(assigned_to, topic), + post_number: post_number, + assignment_note: note, + }, + ] + elsif assigned_to.is_a?(Group) + [ + post_id, + { + assigned_to: build_assigned_to_group(assigned_to, topic), + post_number: post_number, + assignment_note: note, + }, + ] + end end - end.to_h + .to_h end end end diff --git a/lib/pending_assigns_reminder.rb b/lib/pending_assigns_reminder.rb index 741f822b..6f48faf6 100644 --- a/lib/pending_assigns_reminder.rb +++ b/lib/pending_assigns_reminder.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true class PendingAssignsReminder - REMINDED_AT = 'last_reminded_at' - REMINDERS_FREQUENCY = 'remind_assigns_frequency' - CUSTOM_FIELD_NAME = 'assigns_reminder' + REMINDED_AT = "last_reminded_at" + REMINDERS_FREQUENCY = "remind_assigns_frequency" + CUSTOM_FIELD_NAME = "assigns_reminder" REMINDER_THRESHOLD = 2 def remind(user) @@ -14,7 +14,7 @@ def remind(user) oldest_topics = assigned_topics(user, order: :asc).where.not(id: newest_topics.map(&:id)) assigned_topics_count = assigned_count_for(user) - title = I18n.t('pending_assigns_reminder.title', pending_assignments: assigned_topics_count) + title = I18n.t("pending_assigns_reminder.title", pending_assignments: assigned_topics_count) PostCreator.create!( Discourse.system_user, @@ -23,7 +23,9 @@ def remind(user) archetype: Archetype.private_message, subtype: TopicSubtype.system_message, target_usernames: user.username, - custom_fields: { CUSTOM_FIELD_NAME => true } + custom_fields: { + CUSTOM_FIELD_NAME => true, + }, ) update_last_reminded(user) @@ -32,38 +34,46 @@ def remind(user) private def delete_previous_reminders(user) - posts = Post - .joins(topic: { topic_allowed_users: :user }) - .where(topic: { - posts_count: 1, - user_id: Discourse.system_user, - archetype: Archetype.private_message, - subtype: TopicSubtype.system_message, - topic_allowed_users: { - users: { id: user.id } - } - }) - .joins(topic: :_custom_fields) - .where(topic_custom_fields: { - name: CUSTOM_FIELD_NAME - }) - - posts.find_each do |post| - PostDestroyer.new(Discourse.system_user, post).destroy - end + posts = + Post + .joins(topic: { topic_allowed_users: :user }) + .where( + topic: { + posts_count: 1, + user_id: Discourse.system_user, + archetype: Archetype.private_message, + subtype: TopicSubtype.system_message, + topic_allowed_users: { + users: { + id: user.id, + }, + }, + }, + ) + .joins(topic: :_custom_fields) + .where(topic_custom_fields: { name: CUSTOM_FIELD_NAME }) + + posts.find_each { |post| PostDestroyer.new(Discourse.system_user, post).destroy } end def assigned_count_for(user) - Assignment.joins_with_topics.where(assigned_to_id: user.id, assigned_to_type: 'User', active: true).count + Assignment + .joins_with_topics + .where(assigned_to_id: user.id, assigned_to_type: "User", active: true) + .count end def assigned_topics(user, order:) - secure = Topic.listable_topics.secured(Guardian.new(user)).or(Topic.private_messages_for_user(user)) + secure = + Topic.listable_topics.secured(Guardian.new(user)).or(Topic.private_messages_for_user(user)) Topic .joins(:assignment) - .select(:slug, :id, :title, :fancy_title, 'assignments.created_at AS assigned_at') - .where("assignments.assigned_to_id = ? AND assignments.assigned_to_type = 'User' AND assignments.active", user.id) + .select(:slug, :id, :title, :fancy_title, "assignments.created_at AS assigned_at") + .where( + "assignments.assigned_to_id = ? AND assignments.assigned_to_type = 'User' AND assignments.active", + user.id, + ) .merge(secure) .order("assignments.created_at #{order}") .limit(3) @@ -74,38 +84,47 @@ def reminder_body(user, assigned_topics_count, first_three_topics, last_three_to oldest_list = build_list_for(:oldest, last_three_topics) I18n.t( - 'pending_assigns_reminder.body', + "pending_assigns_reminder.body", pending_assignments: assigned_topics_count, assignments_link: "#{Discourse.base_url}/u/#{user.username_lower}/activity/assigned", newest_assignments: newest_list, oldest_assignments: oldest_list, - frequency: frequency_in_words(user) + frequency: frequency_in_words(user), ) end def build_list_for(key, topics) - return '' if topics.empty? - initial_list = { 'topic_0' => '', 'topic_1' => '', 'topic_2' => '' } - items = topics.each_with_index.reduce(initial_list) do |memo, (t, index)| - memo["topic_#{index}"] = "- [#{Emoji.gsub_emoji_to_unicode(t.fancy_title)}](#{t.relative_url}) - assigned #{time_in_words_for(t)}" - memo - end + return "" if topics.empty? + initial_list = { "topic_0" => "", "topic_1" => "", "topic_2" => "" } + items = + topics + .each_with_index + .reduce(initial_list) do |memo, (t, index)| + memo[ + "topic_#{index}" + ] = "- [#{Emoji.gsub_emoji_to_unicode(t.fancy_title)}](#{t.relative_url}) - assigned #{time_in_words_for(t)}" + memo + end I18n.t("pending_assigns_reminder.#{key}", items.symbolize_keys!) end def time_in_words_for(topic) FreedomPatches::Rails4.distance_of_time_in_words( - Time.zone.now, topic.assigned_at.to_time, false, scope: 'datetime.distance_in_words_verbose' + Time.zone.now, + topic.assigned_at.to_time, + false, + scope: "datetime.distance_in_words_verbose", ) end def frequency_in_words(user) - frequency = if user.custom_fields&.has_key?(REMINDERS_FREQUENCY) - user.custom_fields[REMINDERS_FREQUENCY] - else - SiteSetting.remind_assigns_frequency - end + frequency = + if user.custom_fields&.has_key?(REMINDERS_FREQUENCY) + user.custom_fields[REMINDERS_FREQUENCY] + else + SiteSetting.remind_assigns_frequency + end ::RemindAssignsFrequencySiteSettings.frequency_for(frequency) end diff --git a/lib/random_assign_utils.rb b/lib/random_assign_utils.rb index 620ca110..c7b92964 100644 --- a/lib/random_assign_utils.rb +++ b/lib/random_assign_utils.rb @@ -10,11 +10,9 @@ def self.log_info(automation, message) end def self.automation_script!(context, fields, automation) - unless SiteSetting.assign_enabled? - raise_error(automation, "discourse-assign is not enabled") - end + raise_error(automation, "discourse-assign is not enabled") unless SiteSetting.assign_enabled? - unless topic_id = fields.dig('assigned_topic', 'value') + unless topic_id = fields.dig("assigned_topic", "value") raise_error(automation, "`assigned_topic` not provided") end @@ -22,16 +20,17 @@ def self.automation_script!(context, fields, automation) raise_error(automation, "Topic(#{topic_id}) not found") end - min_hours = fields.dig('minimum_time_between_assignments', 'value').presence - if min_hours && TopicCustomField - .where(name: 'assigned_to_id', topic_id: topic_id) - .where('created_at < ?', min_hours.to_i.hours.ago) - .exists? + min_hours = fields.dig("minimum_time_between_assignments", "value").presence + if min_hours && + TopicCustomField + .where(name: "assigned_to_id", topic_id: topic_id) + .where("created_at < ?", min_hours.to_i.hours.ago) + .exists? log_info(automation, "Topic(#{topic_id}) has already been assigned recently") return end - unless group_id = fields.dig('assignees_group', 'value') + unless group_id = fields.dig("assignees_group", "value") raise_error(automation, "`assignees_group` not provided") end @@ -39,32 +38,35 @@ def self.automation_script!(context, fields, automation) raise_error(automation, "Group(#{group_id}) not found") end - users_on_holiday = Set.new( - User - .where(id: - UserCustomField - .where(name: 'on_holiday', value: 't') - .select(:user_id) - ).pluck(:id) - ) + users_on_holiday = + Set.new( + User.where( + id: UserCustomField.where(name: "on_holiday", value: "t").select(:user_id), + ).pluck(:id), + ) - group_users_ids = group - .group_users - .joins(:user) - .pluck('users.id') - .reject { |user_id| users_on_holiday.include?(user_id) } + group_users_ids = + group + .group_users + .joins(:user) + .pluck("users.id") + .reject { |user_id| users_on_holiday.include?(user_id) } if group_users_ids.empty? RandomAssignUtils.no_one!(topic_id, group.name) return end - max_recently_assigned_days = (fields.dig('max_recently_assigned_days', 'value').presence || 180).to_i.days.ago - last_assignees_ids = RandomAssignUtils.recently_assigned_users_ids(topic_id, max_recently_assigned_days) + max_recently_assigned_days = + (fields.dig("max_recently_assigned_days", "value").presence || 180).to_i.days.ago + last_assignees_ids = + RandomAssignUtils.recently_assigned_users_ids(topic_id, max_recently_assigned_days) users_ids = group_users_ids - last_assignees_ids if users_ids.blank? - min_recently_assigned_days = (fields.dig('min_recently_assigned_days', 'value').presence || 14).to_i.days.ago - recently_assigned_users_ids = RandomAssignUtils.recently_assigned_users_ids(topic_id, min_recently_assigned_days) + min_recently_assigned_days = + (fields.dig("min_recently_assigned_days", "value").presence || 14).to_i.days.ago + recently_assigned_users_ids = + RandomAssignUtils.recently_assigned_users_ids(topic_id, min_recently_assigned_days) users_ids = group_users_ids - recently_assigned_users_ids end @@ -73,10 +75,9 @@ def self.automation_script!(context, fields, automation) return end - if fields.dig('in_working_hours', 'value') - assign_to_user_id = users_ids.shuffle.find do |user_id| - RandomAssignUtils.in_working_hours?(user_id) - end + if fields.dig("in_working_hours", "value") + assign_to_user_id = + users_ids.shuffle.find { |user_id| RandomAssignUtils.in_working_hours?(user_id) } end assign_to_user_id ||= users_ids.sample @@ -87,35 +88,34 @@ def self.automation_script!(context, fields, automation) assign_to = User.find(assign_to_user_id) result = nil - if raw = fields.dig('post_template', 'value').presence - post = PostCreator.new( - Discourse.system_user, - raw: raw, - skip_validations: true, - topic_id: topic.id - ).create! + if raw = fields.dig("post_template", "value").presence + post = + PostCreator.new( + Discourse.system_user, + raw: raw, + skip_validations: true, + topic_id: topic.id, + ).create! result = Assigner.new(post, Discourse.system_user).assign(assign_to) - if !result[:success] - PostDestroyer.new(Discourse.system_user, post).destroy - end + PostDestroyer.new(Discourse.system_user, post).destroy if !result[:success] else result = Assigner.new(topic, Discourse.system_user).assign(assign_to) end - if !result[:success] - RandomAssignUtils.no_one!(topic_id, group.name) - end + RandomAssignUtils.no_one!(topic_id, group.name) if !result[:success] end def self.recently_assigned_users_ids(topic_id, from) - posts = Post - .joins(:user) - .where(topic_id: topic_id, action_code: ['assigned', 'reassigned', 'assigned_to_post']) - .where('posts.created_at > ?', from) - .order(created_at: :desc) - usernames = Post.custom_fields_for_ids(posts, [:action_code_who]).map { |_, v| v['action_code_who'] }.uniq + posts = + Post + .joins(:user) + .where(topic_id: topic_id, action_code: %w[assigned reassigned assigned_to_post]) + .where("posts.created_at > ?", from) + .order(created_at: :desc) + usernames = + Post.custom_fields_for_ids(posts, [:action_code_who]).map { |_, v| v["action_code_who"] }.uniq User.where(username: usernames).limit(100).pluck(:id) end @@ -126,7 +126,9 @@ def self.user_tzinfo(user_id) begin tzinfo = ActiveSupport::TimeZone.find_tzinfo(timezone) rescue TZInfo::InvalidTimezoneIdentifier - Rails.logger.warn("#{User.find_by(id: user_id)&.username} has the timezone #{timezone} set, we do not know how to parse it in Rails (assuming UTC)") + Rails.logger.warn( + "#{User.find_by(id: user_id)&.username} has the timezone #{timezone} set, we do not know how to parse it in Rails (assuming UTC)", + ) timezone = "UTC" tzinfo = ActiveSupport::TimeZone.find_tzinfo(timezone) end @@ -139,7 +141,7 @@ def self.no_one!(topic_id, group) Discourse.system_user, topic_id: topic_id, raw: I18n.t("discourse_automation.scriptables.random_assign.no_one", group: group), - validate: false + validate: false, ) end @@ -147,9 +149,6 @@ def self.in_working_hours?(user_id) tzinfo = RandomAssignUtils.user_tzinfo(user_id) tztime = tzinfo.now - !tztime.saturday? && - !tztime.sunday? && - tztime.hour > 7 && - tztime.hour < 11 + !tztime.saturday? && !tztime.sunday? && tztime.hour > 7 && tztime.hour < 11 end end diff --git a/lib/topic_assigner.rb b/lib/topic_assigner.rb index 7cf283c0..1bdc903f 100644 --- a/lib/topic_assigner.rb +++ b/lib/topic_assigner.rb @@ -37,6 +37,10 @@ def initialize(target, user) end def self.deprecation_note - Discourse.deprecate("TopicAssigner class is deprecated, use Assigner", since: "2.8", drop_from: "2.9") + Discourse.deprecate( + "TopicAssigner class is deprecated, use Assigner", + since: "2.8", + drop_from: "2.9", + ) end end diff --git a/plugin.rb b/plugin.rb index 83a57ded..72bcca4e 100644 --- a/plugin.rb +++ b/plugin.rb @@ -9,34 +9,46 @@ enabled_site_setting :assign_enabled -register_asset 'stylesheets/assigns.scss' -register_asset 'stylesheets/mobile/assigns.scss', :mobile +register_asset "stylesheets/assigns.scss" +register_asset "stylesheets/mobile/assigns.scss", :mobile register_svg_icon "user-plus" register_svg_icon "user-times" %w[user-plus user-times group-plus group-times].each { |i| register_svg_icon(i) } -load File.expand_path('../lib/discourse_assign/engine.rb', __FILE__) -load File.expand_path('../lib/discourse_assign/helpers.rb', __FILE__) +load File.expand_path("../lib/discourse_assign/engine.rb", __FILE__) +load File.expand_path("../lib/discourse_assign/helpers.rb", __FILE__) Discourse::Application.routes.append do mount ::DiscourseAssign::Engine, at: "/assign" - get "topics/private-messages-assigned/:username" => "list#private_messages_assigned", as: "topics_private_messages_assigned", constraints: { username: ::RouteFormat.username } - get "/topics/messages-assigned/:username" => "list#messages_assigned", constraints: { username: ::RouteFormat.username }, as: "messages_assigned" - get "/topics/group-topics-assigned/:groupname" => "list#group_topics_assigned", constraints: { username: ::RouteFormat.username }, as: "group_topics_assigned" + get "topics/private-messages-assigned/:username" => "list#private_messages_assigned", + :as => "topics_private_messages_assigned", + :constraints => { + username: ::RouteFormat.username, + } + get "/topics/messages-assigned/:username" => "list#messages_assigned", + :constraints => { + username: ::RouteFormat.username, + }, + :as => "messages_assigned" + get "/topics/group-topics-assigned/:groupname" => "list#group_topics_assigned", + :constraints => { + username: ::RouteFormat.username, + }, + :as => "group_topics_assigned" get "/g/:id/assigned" => "groups#index" get "/g/:id/assigned/:route_type" => "groups#index" end after_initialize do - require File.expand_path('../jobs/scheduled/enqueue_reminders.rb', __FILE__) - require File.expand_path('../jobs/regular/remind_user.rb', __FILE__) - require File.expand_path('../jobs/regular/assign_notification.rb', __FILE__) - require File.expand_path('../jobs/regular/unassign_notification.rb', __FILE__) - require 'topic_assigner' - require 'assigner' - require 'pending_assigns_reminder' + require File.expand_path("../jobs/scheduled/enqueue_reminders.rb", __FILE__) + require File.expand_path("../jobs/regular/remind_user.rb", __FILE__) + require File.expand_path("../jobs/regular/assign_notification.rb", __FILE__) + require File.expand_path("../jobs/regular/unassign_notification.rb", __FILE__) + require "topic_assigner" + require "assigner" + require "pending_assigns_reminder" register_group_param(:assignable_level) register_groups_callback_for_users_search_controller_action(:assignable_groups) do |groups, user| @@ -53,16 +65,21 @@ class ::Post end class ::Group - scope :assignable, ->(user) { - where("assignable_level in (:levels) OR + scope :assignable, + ->(user) { + where( + "assignable_level in (:levels) OR ( assignable_level = #{ALIAS_LEVELS[:members_mods_and_admins]} AND id in ( SELECT group_id FROM group_users WHERE user_id = :user_id) ) OR ( assignable_level = #{ALIAS_LEVELS[:owners_mods_and_admins]} AND id in ( SELECT group_id FROM group_users WHERE user_id = :user_id AND owner IS TRUE) - )", levels: alias_levels(user), user_id: user && user.id) - } + )", + levels: alias_levels(user), + user_id: user && user.id, + ) + } end end @@ -70,17 +87,13 @@ class ::Group register_editable_user_custom_field frequency_field User.register_custom_field_type frequency_field, :integer DiscoursePluginRegistry.serialized_current_user_fields << frequency_field - add_to_serializer(:user, :reminders_frequency) do - RemindAssignsFrequencySiteSettings.values - end + add_to_serializer(:user, :reminders_frequency) { RemindAssignsFrequencySiteSettings.values } add_to_serializer(:group_show, :assignment_count) do - Topic - .joins(<<~SQL) + Topic.joins(<<~SQL).where(<<~SQL, group_id: object.id).where("topics.deleted_at IS NULL").count JOIN assignments a ON topics.id = a.topic_id AND a.assigned_to_id IS NOT NULL SQL - .where(<<~SQL, group_id: object.id) a.active AND (( a.assigned_to_type = 'User' AND a.assigned_to_id IN ( @@ -92,28 +105,20 @@ class ::Group a.assigned_to_type = 'Group' AND a.assigned_to_id = :group_id )) SQL - .where("topics.deleted_at IS NULL") - .count end - add_to_serializer(:group_show, 'include_assignment_count?') do - scope.can_assign? - end + add_to_serializer(:group_show, "include_assignment_count?") { scope.can_assign? } - add_to_serializer(:group_show, :assignable_level) do - object.assignable_level - end + add_to_serializer(:group_show, :assignable_level) { object.assignable_level } - add_to_serializer(:group_show, :can_show_assigned_tab?) do - object.can_show_assigned_tab? - end + add_to_serializer(:group_show, :can_show_assigned_tab?) { object.can_show_assigned_tab? } add_model_callback(UserCustomField, :before_save) do self.value = self.value.to_i if self.name == frequency_field end add_class_method(:group, :assign_allowed_groups) do - allowed_groups = SiteSetting.assign_allowed_on_groups.split('|') + allowed_groups = SiteSetting.assign_allowed_on_groups.split("|") where(id: allowed_groups) end @@ -121,21 +126,24 @@ class ::Group @can_assign ||= begin return true if admin? - allowed_groups = SiteSetting.assign_allowed_on_groups.split('|').compact - allowed_groups.present? && groups.where(id: allowed_groups).exists? ? - :true : :false + allowed_groups = SiteSetting.assign_allowed_on_groups.split("|").compact + allowed_groups.present? && groups.where(id: allowed_groups).exists? ? :true : :false end @can_assign == :true end add_to_serializer(:current_user, :never_auto_track_topics) do - (user.user_option.auto_track_topics_after_msecs || SiteSetting.default_other_auto_track_topics_after_msecs) < 0 + ( + user.user_option.auto_track_topics_after_msecs || + SiteSetting.default_other_auto_track_topics_after_msecs + ) < 0 end add_to_class(:group, :can_show_assigned_tab?) do allowed_group_ids = SiteSetting.assign_allowed_on_groups.split("|") - group_has_disallowed_users = DB.query_single(<<~SQL, allowed_group_ids: allowed_group_ids, current_group_id: self.id)[0] + group_has_disallowed_users = + DB.query_single(<<~SQL, allowed_group_ids: allowed_group_ids, current_group_id: self.id)[0] SELECT EXISTS( SELECT 1 FROM users JOIN group_users current_group_users @@ -154,11 +162,12 @@ class ::Group add_to_class(:guardian, :can_assign?) { user && user.can_assign? } add_class_method(:user, :assign_allowed) do - allowed_groups = SiteSetting.assign_allowed_on_groups.split('|') + allowed_groups = SiteSetting.assign_allowed_on_groups.split("|") # The UNION against admin users is necessary because bot users like the system user are given the admin status but # are not added into the admin group. - where("users.id IN ( + where( + "users.id IN ( SELECT user_id FROM group_users @@ -169,39 +178,46 @@ class ::Group SELECT id FROM users WHERE users.admin - )", allowed_groups) + )", + allowed_groups, + ) end add_model_callback(Group, :before_update) do if name_changed? - SiteSetting.assign_allowed_on_groups = SiteSetting.assign_allowed_on_groups.gsub(name_was, name) + SiteSetting.assign_allowed_on_groups = + SiteSetting.assign_allowed_on_groups.gsub(name_was, name) end end add_model_callback(Group, :before_destroy) do - new_setting = SiteSetting.assign_allowed_on_groups.gsub(/#{id}[|]?/, '') - new_setting = new_setting.chomp('|') if new_setting.ends_with?('|') + new_setting = SiteSetting.assign_allowed_on_groups.gsub(/#{id}[|]?/, "") + new_setting = new_setting.chomp("|") if new_setting.ends_with?("|") SiteSetting.assign_allowed_on_groups = new_setting end on(:assign_topic) do |topic, user, assigning_user, force| - if force || !Assignment.exists?(target: topic) - Assigner.new(topic, assigning_user).assign(user) - end + Assigner.new(topic, assigning_user).assign(user) if force || !Assignment.exists?(target: topic) end - on(:unassign_topic) do |topic, unassigning_user| - Assigner.new(topic, unassigning_user).unassign - end + on(:unassign_topic) { |topic, unassigning_user| Assigner.new(topic, unassigning_user).unassign } Site.preloaded_category_custom_fields << "enable_unassigned_filter" BookmarkQuery.on_preload do |bookmarks, bookmark_query| if SiteSetting.assign_enabled? - topics = Bookmark.select_type(bookmarks, "Topic").map(&:bookmarkable).concat( - Bookmark.select_type(bookmarks, "Post").map { |bm| bm.bookmarkable.topic } - ).uniq - assignments = Assignment.strict_loading.where(topic_id: topics).includes(:assigned_to).index_by(&:topic_id) + topics = + Bookmark + .select_type(bookmarks, "Topic") + .map(&:bookmarkable) + .concat(Bookmark.select_type(bookmarks, "Post").map { |bm| bm.bookmarkable.topic }) + .uniq + assignments = + Assignment + .strict_loading + .where(topic_id: topics) + .includes(:assigned_to) + .index_by(&:topic_id) topics.each do |topic| assigned_to = assignments[topic.id]&.assigned_to @@ -223,22 +239,40 @@ class ::Group assignments = Assignment.strict_loading.where(topic: topics, active: true).includes(:target) assignments_map = assignments.group_by(&:topic_id) - user_ids = assignments.filter { |assignment| assignment.assigned_to_user? }.map(&:assigned_to_id) + user_ids = + assignments.filter { |assignment| assignment.assigned_to_user? }.map(&:assigned_to_id) users_map = User.where(id: user_ids).select(UserLookup.lookup_columns).index_by(&:id) - group_ids = assignments.filter { |assignment| assignment.assigned_to_group? }.map(&:assigned_to_id) + group_ids = + assignments.filter { |assignment| assignment.assigned_to_group? }.map(&:assigned_to_id) groups_map = Group.where(id: group_ids).index_by(&:id) topics.each do |topic| assignments = assignments_map[topic.id] - direct_assignment = assignments&.find { |assignment| assignment.target_type == "Topic" && assignment.target_id == topic.id } + direct_assignment = + assignments&.find do |assignment| + assignment.target_type == "Topic" && assignment.target_id == topic.id + end indirectly_assigned_to = {} - assignments&.each do |assignment| - next if assignment.target_type == "Topic" - next if !assignment.target - next indirectly_assigned_to[assignment.target_id] = { assigned_to: users_map[assignment.assigned_to_id], post_number: assignment.target.post_number } if assignment&.assigned_to_user? - next indirectly_assigned_to[assignment.target_id] = { assigned_to: groups_map[assignment.assigned_to_id], post_number: assignment.target.post_number } if assignment&.assigned_to_group? - end&.compact&.uniq + assignments + &.each do |assignment| + next if assignment.target_type == "Topic" + next if !assignment.target + next( + indirectly_assigned_to[assignment.target_id] = { + assigned_to: users_map[assignment.assigned_to_id], + post_number: assignment.target.post_number, + } + ) if assignment&.assigned_to_user? + next( + indirectly_assigned_to[assignment.target_id] = { + assigned_to: groups_map[assignment.assigned_to_id], + post_number: assignment.target.post_number, + } + ) if assignment&.assigned_to_group? + end + &.compact + &.uniq assigned_to = if direct_assignment&.assigned_to_user? @@ -260,23 +294,34 @@ class ::Group if allowed_access && results.posts.length > 0 topics = results.posts.map(&:topic) - assignments = Assignment.strict_loading.where(topic: topics, active: true).includes(:assigned_to, :target).group_by(&:topic_id) + assignments = + Assignment + .strict_loading + .where(topic: topics, active: true) + .includes(:assigned_to, :target) + .group_by(&:topic_id) results.posts.each do |post| topic_assignments = assignments[post.topic.id] - direct_assignment = topic_assignments&.find { |assignment| assignment.target_type == "Topic" } - indirect_assignments = topic_assignments&.select { |assignment| assignment.target_type == "Post" } + direct_assignment = + topic_assignments&.find { |assignment| assignment.target_type == "Topic" } + indirect_assignments = + topic_assignments&.select { |assignment| assignment.target_type == "Post" } if direct_assignment assigned_to = direct_assignment.assigned_to post.topic.preload_assigned_to(assigned_to) end if indirect_assignments.present? - indirect_assignment_map = indirect_assignments.reduce({}) do |acc, assignment| - if assignment.target - acc[assignment.target_id] = { assigned_to: assignment.assigned_to, post_number: assignment.target.post_number } + indirect_assignment_map = + indirect_assignments.reduce({}) do |acc, assignment| + if assignment.target + acc[assignment.target_id] = { + assigned_to: assignment.assigned_to, + post_number: assignment.target.post_number, + } + end + acc end - acc - end post.topic.preload_indirectly_assigned_to(indirect_assignment_map) end end @@ -285,7 +330,7 @@ class ::Group end # TopicQuery - require_dependency 'topic_query' + require_dependency "topic_query" TopicQuery.add_custom_filter(:assigned) do |results, topic_query| name = topic_query.options[:assigned] next results if name.blank? @@ -293,32 +338,42 @@ class ::Group next results if !topic_query.guardian.can_assign? && !SiteSetting.assigns_public if name == "nobody" - next results - .joins("LEFT JOIN assignments a ON a.topic_id = topics.id AND active") - .where("a.assigned_to_id IS NULL") + next( + results.joins("LEFT JOIN assignments a ON a.topic_id = topics.id AND active").where( + "a.assigned_to_id IS NULL", + ) + ) end if name == "*" - next results - .joins("JOIN assignments a ON a.topic_id = topics.id AND active") - .where("a.assigned_to_id IS NOT NULL") + next( + results.joins("JOIN assignments a ON a.topic_id = topics.id AND active").where( + "a.assigned_to_id IS NOT NULL", + ) + ) end user_id = topic_query.guardian.user.id if name == "me" user_id ||= User.where(username_lower: name.downcase).pluck_first(:id) if user_id - next results - .joins("JOIN assignments a ON a.topic_id = topics.id AND active") - .where("a.assigned_to_id = ? AND a.assigned_to_type = 'User'", user_id) + next( + results.joins("JOIN assignments a ON a.topic_id = topics.id AND active").where( + "a.assigned_to_id = ? AND a.assigned_to_type = 'User'", + user_id, + ) + ) end group_id = Group.where(name: name.downcase).pluck_first(:id) if group_id - next results - .joins("JOIN assignments a ON a.topic_id = topics.id AND active") - .where("a.assigned_to_id = ? AND a.assigned_to_type = 'Group'", group_id) + next( + results.joins("JOIN assignments a ON a.topic_id = topics.id AND active").where( + "a.assigned_to_id = ? AND a.assigned_to_type = 'Group'", + group_id, + ) + ) end next results @@ -334,11 +389,9 @@ class ::Group (assigned_to_id = :user_id AND assigned_to_type = 'User' AND active) SQL - if @options[:filter] != :direct - topic_ids_sql << <<~SQL + topic_ids_sql << <<~SQL if @options[:filter] != :direct OR (assigned_to_id IN (group_users.group_id) AND assigned_to_type = 'Group' AND active) SQL - end sql = "topics.id IN (#{topic_ids_sql})" @@ -357,13 +410,11 @@ class ::Group ) SQL - if @options[:filter] != :direct - topic_ids_sql << <<~SQL + topic_ids_sql << <<~SQL if @options[:filter] != :direct OR ( assigned_to_id IN (SELECT user_id from group_users where group_id = :group_id) AND assigned_to_type = 'User' AND active ) SQL - end sql = "topics.id IN (#{topic_ids_sql})" @@ -395,7 +446,7 @@ class ::Group end # ListController - require_dependency 'list_controller' + require_dependency "list_controller" class ::ListController generate_message_route(:private_messages_assigned) end @@ -441,15 +492,21 @@ class ::ListController add_to_class(:topic, :indirectly_assigned_to) do return @indirectly_assigned_to if defined?(@indirectly_assigned_to) - @indirectly_assigned_to = Assignment.where(topic_id: id, target_type: "Post", active: true).includes(:target).inject({}) do |acc, assignment| - acc[assignment.target_id] = { assigned_to: assignment.assigned_to, post_number: assignment.target.post_number, assignment_note: assignment.note } if assignment.target - acc - end + @indirectly_assigned_to = + Assignment + .where(topic_id: id, target_type: "Post", active: true) + .includes(:target) + .inject({}) do |acc, assignment| + acc[assignment.target_id] = { + assigned_to: assignment.assigned_to, + post_number: assignment.target.post_number, + assignment_note: assignment.note, + } if assignment.target + acc + end end - add_to_class(:topic, :preload_assigned_to) do |assigned_to| - @assigned_to = assigned_to - end + add_to_class(:topic, :preload_assigned_to) { |assigned_to| @assigned_to = assigned_to } add_to_class(:topic, :preload_indirectly_assigned_to) do |indirectly_assigned_to| @indirectly_assigned_to = indirectly_assigned_to @@ -457,17 +514,17 @@ class ::ListController # TopicList serializer add_to_serializer(:topic_list, :assigned_messages_count) do - TopicQuery.new(object.current_user, guardian: scope, limit: false) + TopicQuery + .new(object.current_user, guardian: scope, limit: false) .private_messages_assigned_query(object.current_user) .count end - add_to_serializer(:topic_list, 'include_assigned_messages_count?') do + add_to_serializer(:topic_list, "include_assigned_messages_count?") do options = object.instance_variable_get(:@opts) if assigned_user = options.dig(:assigned) - scope.can_assign? || - assigned_user.downcase == scope.current_user&.username_lower + scope.can_assign? || assigned_user.downcase == scope.current_user&.username_lower end end @@ -489,16 +546,18 @@ class ::ListController end add_to_serializer(:topic_view, :indirectly_assigned_to) do - DiscourseAssign::Helpers.build_indirectly_assigned_to(object.topic.indirectly_assigned_to, object.topic) + DiscourseAssign::Helpers.build_indirectly_assigned_to( + object.topic.indirectly_assigned_to, + object.topic, + ) end add_to_serializer(:topic_view, :include_indirectly_assigned_to?) do - (SiteSetting.assigns_public || scope.can_assign?) && object.topic.indirectly_assigned_to.present? + (SiteSetting.assigns_public || scope.can_assign?) && + object.topic.indirectly_assigned_to.present? end - add_to_serializer(:topic_view, :assignment_note, false) do - object.topic.assignment.note - end + add_to_serializer(:topic_view, :assignment_note, false) { object.topic.assignment.note } add_to_serializer(:topic_view, :include_assignment_note?, false) do (SiteSetting.assigns_public || scope.can_assign?) && object.topic.assignment.present? @@ -559,7 +618,7 @@ class ::ListController DiscourseAssign::Helpers.build_assigned_to_user(object.assigned_to, object) end - add_to_serializer(:search_topic_list_item, 'include_assigned_to_user?') do + add_to_serializer(:search_topic_list_item, "include_assigned_to_user?") do (SiteSetting.assigns_public || scope.can_assign?) && object.assigned_to&.is_a?(User) end @@ -567,7 +626,7 @@ class ::ListController BasicGroupSerializer.new(object.assigned_to, scope: scope, root: false).as_json end - add_to_serializer(:search_topic_list_item, 'include_assigned_to_group?') do + add_to_serializer(:search_topic_list_item, "include_assigned_to_group?") do (SiteSetting.assigns_public || scope.can_assign?) && object.assigned_to&.is_a?(Group) end @@ -583,30 +642,25 @@ class ::ListController TopicsBulkAction.register_operation("assign") do if @user.can_assign? assign_user = User.find_by_username(@operation[:username]) - topics.each do |topic| - Assigner.new(topic, @user).assign(assign_user) - end + topics.each { |topic| Assigner.new(topic, @user).assign(assign_user) } end end TopicsBulkAction.register_operation("unassign") do if @user.can_assign? - topics.each do |topic| - if guardian.can_assign? - Assigner.new(topic, @user).unassign - end - end + topics.each { |topic| Assigner.new(topic, @user).unassign if guardian.can_assign? } end end register_permitted_bulk_action_parameter :username add_to_class(:user_bookmark_base_serializer, :assigned_to) do - @assigned_to ||= bookmarkable_type == "Topic" ? bookmarkable.assigned_to : bookmarkable.topic.assigned_to + @assigned_to ||= + bookmarkable_type == "Topic" ? bookmarkable.assigned_to : bookmarkable.topic.assigned_to end add_to_class(:user_bookmark_base_serializer, :can_have_assignment?) do - ["Post", "Topic"].include?(bookmarkable_type) + %w[Post Topic].include?(bookmarkable_type) end add_to_serializer(:user_bookmark_base, :assigned_to_user, false) do @@ -614,7 +668,7 @@ class ::ListController BasicUserSerializer.new(assigned_to, scope: scope, root: false).as_json end - add_to_serializer(:user_bookmark_base, 'include_assigned_to_user?') do + add_to_serializer(:user_bookmark_base, "include_assigned_to_user?") do return false if !can_have_assignment? (SiteSetting.assigns_public || scope.can_assign?) && assigned_to&.is_a?(User) end @@ -624,56 +678,48 @@ class ::ListController BasicGroupSerializer.new(assigned_to, scope: scope, root: false).as_json end - add_to_serializer(:user_bookmark_base, 'include_assigned_to_group?') do + add_to_serializer(:user_bookmark_base, "include_assigned_to_group?") do return false if !can_have_assignment? (SiteSetting.assigns_public || scope.can_assign?) && assigned_to&.is_a?(Group) end - add_to_serializer(:basic_user, :assign_icon) do - 'user-plus' - end + add_to_serializer(:basic_user, :assign_icon) { "user-plus" } add_to_serializer(:basic_user, :assign_path) do return if !object.is_a?(User) SiteSetting.assigns_user_url_path.gsub("{username}", object.username) end - add_to_serializer(:basic_group, :assign_icon) do - 'group-plus' - end + add_to_serializer(:basic_group, :assign_icon) { "group-plus" } - add_to_serializer(:basic_group, :assign_path) do - "/g/#{object.name}/assigned/everyone" - end + add_to_serializer(:basic_group, :assign_path) { "/g/#{object.name}/assigned/everyone" } # PostSerializer add_to_serializer(:post, :assigned_to_user) do BasicUserSerializer.new(object.assignment.assigned_to, scope: scope, root: false).as_json end - add_to_serializer(:post, 'include_assigned_to_user?') do - (SiteSetting.assigns_public || scope.can_assign?) && object.assignment&.assigned_to&.is_a?(User) && object.assignment.active + add_to_serializer(:post, "include_assigned_to_user?") do + (SiteSetting.assigns_public || scope.can_assign?) && + object.assignment&.assigned_to&.is_a?(User) && object.assignment.active end add_to_serializer(:post, :assigned_to_group, false) do BasicGroupSerializer.new(object.assignment.assigned_to, scope: scope, root: false).as_json end - add_to_serializer(:post, 'include_assigned_to_group?') do - (SiteSetting.assigns_public || scope.can_assign?) && object.assignment&.assigned_to&.is_a?(Group) && object.assignment.active + add_to_serializer(:post, "include_assigned_to_group?") do + (SiteSetting.assigns_public || scope.can_assign?) && + object.assignment&.assigned_to&.is_a?(Group) && object.assignment.active end - add_to_serializer(:post, :assignment_note, false) do - object.assignment.note - end + add_to_serializer(:post, :assignment_note, false) { object.assignment.note } add_to_serializer(:post, :include_assignment_note?, false) do (SiteSetting.assigns_public || scope.can_assign?) && object.assignment.present? end # CurrentUser serializer - add_to_serializer(:current_user, :can_assign) do - object.can_assign? - end + add_to_serializer(:current_user, :can_assign) { object.can_assign? } # FlaggedTopic serializer add_to_serializer(:flagged_topic, :assigned_to_user) do @@ -697,59 +743,47 @@ class ::ListController [ :assigned_to, Proc.new do |results, value| - results.joins(<<~SQL + results.joins(<<~SQL).where(target_type: Post.name).where("u.username = ?", value) INNER JOIN posts p ON p.id = target_id INNER JOIN topics t ON t.id = p.topic_id INNER JOIN assignments a ON a.topic_id = t.id AND a.assigned_to_type = 'User' INNER JOIN users u ON u.id = a.assigned_to_id SQL - ) - .where(target_type: Post.name) - .where('u.username = ?', value) - end - ] + end, + ], ) # TopicTrackingState add_class_method(:topic_tracking_state, :publish_assigned_private_message) do |topic, assignee| return unless topic.private_message? - opts = - if assignee.is_a?(User) - { user_ids: [assignee.id] } - else - { group_ids: [assignee.id] } - end + opts = (assignee.is_a?(User) ? { user_ids: [assignee.id] } : { group_ids: [assignee.id] }) - MessageBus.publish( - "/private-messages/assigned", - { topic_id: topic.id }, - opts - ) + MessageBus.publish("/private-messages/assigned", { topic_id: topic.id }, opts) end # Event listeners - on(:post_created) do |post| - ::Assigner.auto_assign(post, force: true) - end + on(:post_created) { |post| ::Assigner.auto_assign(post, force: true) } - on(:post_edited) do |post, topic_changed| - ::Assigner.auto_assign(post, force: true) - end + on(:post_edited) { |post, topic_changed| ::Assigner.auto_assign(post, force: true) } on(:topic_status_updated) do |topic, status, enabled| - if SiteSetting.unassign_on_close && (status == 'closed' || status == 'autoclosed') && enabled && Assignment.exists?(topic_id: topic.id, active: true) - + if SiteSetting.unassign_on_close && (status == "closed" || status == "autoclosed") && enabled && + Assignment.exists?(topic_id: topic.id, active: true) assigner = ::Assigner.new(topic, Discourse.system_user) assigner.unassign(silent: true, deactivate: true) - topic.posts.joins(:assignment).find_each do |post| - assigner = ::Assigner.new(post, Discourse.system_user) - assigner.unassign(silent: true, deactivate: true) - end + topic + .posts + .joins(:assignment) + .find_each do |post| + assigner = ::Assigner.new(post, Discourse.system_user) + assigner.unassign(silent: true, deactivate: true) + end MessageBus.publish("/topic/#{topic.id}", reload_topic: true, refresh_stream: true) end - if SiteSetting.reassign_on_open && (status == 'closed' || status == 'autoclosed') && !enabled && Assignment.exists?(topic_id: topic.id, active: false) + if SiteSetting.reassign_on_open && (status == "closed" || status == "autoclosed") && !enabled && + Assignment.exists?(topic_id: topic.id, active: false) Assignment.where(topic_id: topic.id, target_type: "Topic").update_all(active: true) Assignment .where(topic_id: topic.id, target_type: "Post") @@ -766,14 +800,21 @@ class ::ListController end # small actions have to be destroyed as link is incorrect - PostCustomField.where(name: "action_code_post_id", value: post.id).find_each do |post_custom_field| - next if ![Post.types[:small_action], Post.types[:whisper]].include?(post_custom_field.post.post_type) - post_custom_field.post.destroy - end + PostCustomField + .where(name: "action_code_post_id", value: post.id) + .find_each do |post_custom_field| + if ![Post.types[:small_action], Post.types[:whisper]].include?( + post_custom_field.post.post_type, + ) + next + end + post_custom_field.post.destroy + end end on(:post_recovered) do |post| - if SiteSetting.reassign_on_open && Assignment.where(target_type: "Post", target_id: post.id, active: false) + if SiteSetting.reassign_on_open && + Assignment.where(target_type: "Post", target_id: post.id, active: false) Assignment.where(target_type: "Post", target_id: post.id).update_all(active: true) MessageBus.publish("/topic/#{post.topic_id}", reload_topic: true, refresh_stream: true) end @@ -782,22 +823,28 @@ class ::ListController on(:move_to_inbox) do |info| topic = info[:topic] - TopicTrackingState.publish_assigned_private_message(topic, topic.assignment.assigned_to) if topic.assignment + if topic.assignment + TopicTrackingState.publish_assigned_private_message(topic, topic.assignment.assigned_to) + end next if !SiteSetting.unassign_on_group_archive next if !info[:group] - Assignment.where(topic_id: topic.id, active: false).find_each do |assignment| - next unless assignment.target - assignment.update!(active: true) - Jobs.enqueue(:assign_notification, - topic_id: topic.id, - post_id: assignment.target_type.is_a?(Topic) ? topic.first_post.id : assignment.target.id, - assigned_to_id: assignment.assigned_to_id, - assigned_to_type: assignment.assigned_to_type, - assigned_by_id: assignment.assigned_by_user_id, - skip_small_action_post: true) - end + Assignment + .where(topic_id: topic.id, active: false) + .find_each do |assignment| + next unless assignment.target + assignment.update!(active: true) + Jobs.enqueue( + :assign_notification, + topic_id: topic.id, + post_id: assignment.target_type.is_a?(Topic) ? topic.first_post.id : assignment.target.id, + assigned_to_id: assignment.assigned_to_id, + assigned_to_type: assignment.assigned_to_type, + assigned_by_id: assignment.assigned_by_user_id, + skip_small_action_post: true, + ) + end end on(:archive_message) do |info| @@ -809,33 +856,36 @@ class ::ListController next if !SiteSetting.unassign_on_group_archive next if !info[:group] - Assignment.where(topic_id: topic.id, active: true).find_each do |assignment| - assignment.update!(active: false) - Jobs.enqueue(:unassign_notification, - topic_id: topic.id, - assigned_to_id: assignment.assigned_to.id, - assigned_to_type: assignment.assigned_to_type) - end + Assignment + .where(topic_id: topic.id, active: true) + .find_each do |assignment| + assignment.update!(active: false) + Jobs.enqueue( + :unassign_notification, + topic_id: topic.id, + assigned_to_id: assignment.assigned_to.id, + assigned_to_type: assignment.assigned_to_type, + ) + end end on(:user_removed_from_group) do |user, group| - assign_allowed_groups = SiteSetting.assign_allowed_on_groups.split('|').map(&:to_i) + assign_allowed_groups = SiteSetting.assign_allowed_on_groups.split("|").map(&:to_i) if assign_allowed_groups.include?(group.id) groups = GroupUser.where(user: user).pluck(:group_id) if (groups & assign_allowed_groups).empty? - topics = Topic.joins(:assignment).where('assignments.assigned_to_id = ?', user.id) + topics = Topic.joins(:assignment).where("assignments.assigned_to_id = ?", user.id) - topics.each do |topic| - Assigner.new(topic, Discourse.system_user).unassign - end + topics.each { |topic| Assigner.new(topic, Discourse.system_user).unassign } end end end on(:post_moved) do |post, original_topic_id| - assignment = Assignment.where(topic_id: original_topic_id, target_type: "Post", target_id: post.id).first + assignment = + Assignment.where(topic_id: original_topic_id, target_type: "Post", target_id: post.id).first next if !assignment if post.is_first_post? assignment.update!(topic_id: post.topic_id, target_type: "Topic", target_id: post.topic_id) @@ -846,32 +896,24 @@ class ::ListController class ::WebHook def self.enqueue_assign_hooks(event, payload) - if active_web_hooks('assign').exists? - WebHook.enqueue_hooks(:assign, event, - payload: payload - ) - end + WebHook.enqueue_hooks(:assign, event, payload: payload) if active_web_hooks("assign").exists? end end register_search_advanced_filter(/in:assigned/) do |posts| - if @guardian.can_assign? - posts.where(<<~SQL) + posts.where(<<~SQL) if @guardian.can_assign? topics.id IN ( SELECT a.topic_id FROM assignments a WHERE a.active ) SQL - end end register_search_advanced_filter(/in:unassigned/) do |posts| - if @guardian.can_assign? - posts.where(<<~SQL) + posts.where(<<~SQL) if @guardian.can_assign? topics.id NOT IN ( SELECT a.topic_id FROM assignments a WHERE a.active ) SQL - end end register_search_advanced_filter(/assigned:(.+)$/) do |posts, match| @@ -893,9 +935,9 @@ def self.enqueue_assign_hooks(event, payload) end if defined?(DiscourseAutomation) - require 'random_assign_utils' + require "random_assign_utils" - add_automation_scriptable('random_assign') do + add_automation_scriptable("random_assign") do field :assignees_group, component: :group, required: true field :assigned_topic, component: :text, required: true field :minimum_time_between_assignments, component: :text diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index da3367dc..37b5edb1 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" describe Search do fab!(:user) { Fabricate(:active_user) } @@ -12,8 +12,8 @@ SiteSetting.assign_enabled = true end - context 'Advanced search' do - include_context 'A group that is allowed to assign' + context "Advanced search" do + include_context "A group that is allowed to assign" let(:post1) { Fabricate(:post) } let(:post2) { Fabricate(:post) } @@ -30,34 +30,47 @@ Assigner.new(post2.topic, user).assign(user2) Assigner.new(post3.topic, user).assign(user) Assigner.new(post5, user).assign(user) - Assignment.create!(assigned_to: user, assigned_by_user: user, target: post6, topic_id: post6.topic.id, active: false) + Assignment.create!( + assigned_to: user, + assigned_by_user: user, + target: post6, + topic_id: post6.topic.id, + active: false, + ) end - it 'can find by status' do - expect(Search.execute('in:assigned', guardian: Guardian.new(user)).posts.length).to eq(4) + it "can find by status" do + expect(Search.execute("in:assigned", guardian: Guardian.new(user)).posts.length).to eq(4) Assigner.new(post3.topic, user).unassign - expect(Search.execute('in:unassigned', guardian: Guardian.new(user)).posts.length).to eq(2) - expect(Search.execute("assigned:#{user.username}", guardian: Guardian.new(user)).posts.length).to eq(2) + expect(Search.execute("in:unassigned", guardian: Guardian.new(user)).posts.length).to eq(2) + expect( + Search.execute("assigned:#{user.username}", guardian: Guardian.new(user)).posts.length, + ).to eq(2) end - it 'serializes results' do + it "serializes results" do guardian = Guardian.new(user) - result = Search.execute('in:assigned', guardian: guardian) + result = Search.execute("in:assigned", guardian: guardian) serializer = GroupedSearchResultSerializer.new(result, scope: guardian) - indirectly_assigned_to = serializer.as_json[:topics].find { |topic| topic[:id] == post5.topic.id }[:indirectly_assigned_to] - expect(indirectly_assigned_to).to eq(post5.id => { - assigned_to: { - assign_icon: "user-plus", - assign_path: "/u/#{user.username}/activity/assigned", - avatar_template: user.avatar_template, - name: user.name, - username: user.username, + indirectly_assigned_to = + serializer.as_json[:topics].find { |topic| topic[:id] == post5.topic.id }[ + :indirectly_assigned_to + ] + expect(indirectly_assigned_to).to eq( + post5.id => { + assigned_to: { + assign_icon: "user-plus", + assign_path: "/u/#{user.username}/activity/assigned", + avatar_template: user.avatar_template, + name: user.name, + username: user.username, + }, + post_number: post5.post_number, + assignment_note: nil, }, - post_number: post5.post_number, - assignment_note: nil, - }) + ) end end end diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb index dfeaee75..6a5b0297 100644 --- a/spec/components/topic_query_spec.rb +++ b/spec/components/topic_query_spec.rb @@ -1,27 +1,23 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" describe TopicQuery do - before do - SiteSetting.assign_enabled = true - end + before { SiteSetting.assign_enabled = true } fab!(:user) { Fabricate(:user) } fab!(:user2) { Fabricate(:user) } - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" before do add_to_assign_allowed_group(user) add_to_assign_allowed_group(user2) end - describe '#list_messages_assigned' do - fab!(:private_message) do - Fabricate(:private_message_post, user: user).topic - end + describe "#list_messages_assigned" do + fab!(:private_message) { Fabricate(:private_message_post, user: user).topic } fab!(:topic) { Fabricate(:post, user: user).topic } fab!(:group_topic) { Fabricate(:post, user: user).topic } @@ -32,13 +28,13 @@ assign_to(group_topic, user, assign_allowed_group) end - it 'Includes topics and PMs assigned to user' do + it "Includes topics and PMs assigned to user" do assigned_messages = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics expect(assigned_messages).to contain_exactly(private_message, topic, group_topic) end - it 'Excludes inactive assignments' do + it "Excludes inactive assignments" do Assignment.update_all(active: false) assigned_messages = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics @@ -46,19 +42,20 @@ expect(assigned_messages).to eq([]) end - it 'Excludes topics and PMs not assigned to user' do + it "Excludes topics and PMs not assigned to user" do assigned_messages = TopicQuery.new(user2, { page: 0 }).list_messages_assigned(user2).topics expect(assigned_messages).to contain_exactly(group_topic) end - it 'direct filter excludes group assignment' do - assigned_messages = TopicQuery.new(user, { page: 0, filter: :direct }).list_messages_assigned(user).topics + it "direct filter excludes group assignment" do + assigned_messages = + TopicQuery.new(user, { page: 0, filter: :direct }).list_messages_assigned(user).topics expect(assigned_messages).to contain_exactly(private_message, topic) end - it 'Returns the results ordered by the bumped_at field' do + it "Returns the results ordered by the bumped_at field" do topic.update(bumped_at: 2.weeks.ago) assigned_messages = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics @@ -67,11 +64,8 @@ end end - describe '#list_group_topics_assigned' do - - fab!(:private_message) do - Fabricate(:private_message_post, user: user).topic - end + describe "#list_group_topics_assigned" do + fab!(:private_message) { Fabricate(:private_message_post, user: user).topic } fab!(:topic) { Fabricate(:post, user: user).topic } @@ -83,34 +77,41 @@ assign_to(group_topic, user, assign_allowed_group) end - it 'Includes topics and PMs assigned to user' do - assigned_messages = TopicQuery.new(user, { page: 0 }).list_group_topics_assigned(assign_allowed_group).topics + it "Includes topics and PMs assigned to user" do + assigned_messages = + TopicQuery.new(user, { page: 0 }).list_group_topics_assigned(assign_allowed_group).topics expect(assigned_messages).to contain_exactly(private_message, topic, group_topic) end - it 'Returns the results ordered by the bumped_at field' do + it "Returns the results ordered by the bumped_at field" do topic.update(bumped_at: 2.weeks.ago) - assigned_messages = TopicQuery.new(user, { page: 0 }).list_group_topics_assigned(assign_allowed_group).topics + assigned_messages = + TopicQuery.new(user, { page: 0 }).list_group_topics_assigned(assign_allowed_group).topics expect(assigned_messages).to eq([group_topic, private_message, topic]) end - it 'direct filter shows only group assignments' do - assigned_messages = TopicQuery.new(user, { page: 0, filter: :direct }).list_group_topics_assigned(assign_allowed_group).topics + it "direct filter shows only group assignments" do + assigned_messages = + TopicQuery + .new(user, { page: 0, filter: :direct }) + .list_group_topics_assigned(assign_allowed_group) + .topics expect(assigned_messages).to contain_exactly(group_topic) end end - describe '#list_private_messages_assigned' do + describe "#list_private_messages_assigned" do let(:user_topic) do - topic = create_post( - user: Fabricate(:user), - target_usernames: [user.username, user2.username], - archetype: Archetype.private_message - ).topic + topic = + create_post( + user: Fabricate(:user), + target_usernames: [user.username, user2.username], + archetype: Archetype.private_message, + ).topic create_post(topic_id: topic.id, user: user) @@ -118,61 +119,63 @@ end let(:assigned_topic) do - topic = create_post( - user: Fabricate(:user), - target_usernames: [user.username, user2.username], - archetype: Archetype.private_message - ).topic + topic = + create_post( + user: Fabricate(:user), + target_usernames: [user.username, user2.username], + archetype: Archetype.private_message, + ).topic assign_to(topic, user, user) end - let(:group2) do - Fabricate(:group, messageable_level: Group::ALIAS_LEVELS[:everyone]) - end + let(:group2) { Fabricate(:group, messageable_level: Group::ALIAS_LEVELS[:everyone]) } let(:group_assigned_topic) do - topic = create_post( - user: user, - target_group_names: [assign_allowed_group.name, group2.name], - archetype: Archetype.private_message - ).topic + topic = + create_post( + user: user, + target_group_names: [assign_allowed_group.name, group2.name], + archetype: Archetype.private_message, + ).topic assign_to(topic, user, user) end before do - assign_allowed_group.update!( - messageable_level: Group::ALIAS_LEVELS[:everyone] - ) + assign_allowed_group.update!(messageable_level: Group::ALIAS_LEVELS[:everyone]) user_topic assigned_topic group_assigned_topic end - it 'should return the right topics' do - expect( - TopicQuery.new(user).list_private_messages_assigned(user).topics - ).to contain_exactly(assigned_topic, group_assigned_topic) + it "should return the right topics" do + expect(TopicQuery.new(user).list_private_messages_assigned(user).topics).to contain_exactly( + assigned_topic, + group_assigned_topic, + ) UserArchivedMessage.archive!(user.id, assigned_topic) - expect( - TopicQuery.new(user).list_private_messages_assigned(user).topics - ).to contain_exactly(assigned_topic, group_assigned_topic) + expect(TopicQuery.new(user).list_private_messages_assigned(user).topics).to contain_exactly( + assigned_topic, + group_assigned_topic, + ) GroupArchivedMessage.archive!(group2.id, group_assigned_topic) - expect( - TopicQuery.new(user).list_private_messages_assigned(user).topics - ).to contain_exactly(assigned_topic, group_assigned_topic) + expect(TopicQuery.new(user).list_private_messages_assigned(user).topics).to contain_exactly( + assigned_topic, + group_assigned_topic, + ) GroupArchivedMessage.archive!(assign_allowed_group.id, group_assigned_topic) - expect( - TopicQuery.new(user).list_private_messages_assigned(user).topics - ).to contain_exactly(assigned_topic, group_assigned_topic) + expect(TopicQuery.new(user).list_private_messages_assigned(user).topics).to contain_exactly( + assigned_topic, + group_assigned_topic, + ) end end @@ -225,8 +228,6 @@ end def assign_to(topic, user, assignee) - topic.tap do |t| - Assigner.new(t, user).assign(assignee) - end + topic.tap { |t| Assigner.new(t, user).assign(assignee) } end end diff --git a/spec/components/topics_bulk_action_spec.rb b/spec/components/topics_bulk_action_spec.rb index a0f485f2..c0e4b3be 100644 --- a/spec/components/topics_bulk_action_spec.rb +++ b/spec/components/topics_bulk_action_spec.rb @@ -1,29 +1,29 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" describe TopicsBulkAction do fab!(:post) { Fabricate(:post) } fab!(:post1) { Fabricate(:post) } fab!(:post2) { Fabricate(:post) } - before do - SiteSetting.assign_enabled = true - end + before { SiteSetting.assign_enabled = true } let(:user) { Fabricate(:user) } let(:user2) { Fabricate(:user) } - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" - before do - add_to_assign_allowed_group(user) - end + before { add_to_assign_allowed_group(user) } describe "assign_topics" do it "assigns multiple topics to user" do - TopicsBulkAction.new(user, [post.topic.id, post1.topic.id], { type: 'assign', username: user.username }).perform! + TopicsBulkAction.new( + user, + [post.topic.id, post1.topic.id], + { type: "assign", username: user.username }, + ).perform! assigned_topics = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics @@ -33,7 +33,11 @@ end it "doesn't allows to assign to user not in assign_allowed_group" do - TopicsBulkAction.new(user, [post.topic.id, post1.topic.id], { type: 'assign', username: user2.username }).perform! + TopicsBulkAction.new( + user, + [post.topic.id, post1.topic.id], + { type: "assign", username: user2.username }, + ).perform! assigned_topics = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user2).topics @@ -41,7 +45,11 @@ end it "user who is not in assign_allowed_group can't assign topics" do - TopicsBulkAction.new(user2, [post.topic.id, post1.topic.id, post2.topic.id], { type: 'assign', username: user.username }).perform! + TopicsBulkAction.new( + user2, + [post.topic.id, post1.topic.id, post2.topic.id], + { type: "assign", username: user.username }, + ).perform! assigned_topics = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics @@ -51,9 +59,13 @@ describe "unassign_topics" do it "unassigns multiple topics assigned to user" do - TopicsBulkAction.new(user, [post.topic.id, post1.topic.id, post2.topic.id], { type: 'assign', username: user.username }).perform! + TopicsBulkAction.new( + user, + [post.topic.id, post1.topic.id, post2.topic.id], + { type: "assign", username: user.username }, + ).perform! - TopicsBulkAction.new(user, [post.topic.id, post1.topic.id], type: 'unassign').perform! + TopicsBulkAction.new(user, [post.topic.id, post1.topic.id], type: "unassign").perform! assigned_topics = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics @@ -63,9 +75,13 @@ end it "user who is not in assign_allowed_group can't unassign topics" do - TopicsBulkAction.new(user, [post.topic.id, post1.topic.id, post2.topic.id], { type: 'assign', username: user.username }).perform! + TopicsBulkAction.new( + user, + [post.topic.id, post1.topic.id, post2.topic.id], + { type: "assign", username: user.username }, + ).perform! - TopicsBulkAction.new(user2, [post.topic.id, post1.topic.id], type: 'unassign').perform! + TopicsBulkAction.new(user2, [post.topic.id, post1.topic.id], type: "unassign").perform! assigned_topics = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics @@ -73,6 +89,5 @@ expect(assigned_topics).to contain_exactly(post.topic, post1.topic, post2.topic) end - end end diff --git a/spec/fabricators/assign_hook_fabricator.rb b/spec/fabricators/assign_hook_fabricator.rb index 6c145d23..e331154e 100644 --- a/spec/fabricators/assign_hook_fabricator.rb +++ b/spec/fabricators/assign_hook_fabricator.rb @@ -1,9 +1,7 @@ # frozen_string_literal: true Fabricator(:assign_web_hook, from: :web_hook) do - transient assign_hook: WebHookEventType.find_by(name: 'assign') + transient assign_hook: WebHookEventType.find_by(name: "assign") - after_build do |web_hook, transients| - web_hook.web_hook_event_types = [transients[:assign_hook]] - end + after_build { |web_hook, transients| web_hook.web_hook_event_types = [transients[:assign_hook]] } end diff --git a/spec/integration/assign_spec.rb b/spec/integration/assign_spec.rb index 2d5785a3..7183e40c 100644 --- a/spec/integration/assign_spec.rb +++ b/spec/integration/assign_spec.rb @@ -1,15 +1,13 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' -require_relative '../fabricators/assign_hook_fabricator.rb' +require "rails_helper" +require_relative "../support/assign_allowed_group" +require_relative "../fabricators/assign_hook_fabricator.rb" -describe 'integration tests' do - before do - SiteSetting.assign_enabled = true - end +describe "integration tests" do + before { SiteSetting.assign_enabled = true } - it 'preloads data in topic list' do + it "preloads data in topic list" do admin = Fabricate(:admin) post = create_post list = TopicList.new("latest", admin, [post.topic]) @@ -17,7 +15,7 @@ # should not explode for now end - describe 'for a private message' do + describe "for a private message" do let(:post) { Fabricate(:private_message_post) } let(:pm) { post.topic } let(:user) { pm.allowed_users.first } @@ -25,7 +23,7 @@ let(:channel) { "/private-messages/assigned" } fab!(:group) { Fabricate(:group, assignable_level: Group::ALIAS_LEVELS[:everyone]) } - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" before do add_to_assign_allowed_group(user) @@ -35,9 +33,7 @@ end def assert_publish_topic_state(topic, user: nil, group: nil) - messages = MessageBus.track_publish do - yield - end + messages = MessageBus.track_publish { yield } message = messages.find { |m| m.channel == channel } @@ -46,7 +42,7 @@ def assert_publish_topic_state(topic, user: nil, group: nil) expect(message.group_ids).to eq([group.id]) if group end - it 'publishes the right message on archive and move to inbox' do + it "publishes the right message on archive and move to inbox" do assigner = Assigner.new(pm, user) assigner.assign(user) @@ -59,7 +55,7 @@ def assert_publish_topic_state(topic, user: nil, group: nil) end end - it 'publishes the right message on archive and move to inbox for groups' do + it "publishes the right message on archive and move to inbox for groups" do assigner = Assigner.new(pm, user) assigner.assign(group) @@ -106,7 +102,7 @@ def assert_publish_topic_state(topic, user: nil, group: nil) let(:user1) { Fabricate(:user) } let(:user2) { Fabricate(:user) } - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" before do add_to_assign_allowed_group(user1) @@ -142,15 +138,15 @@ def assert_publish_topic_state(topic, user: nil, group: nil) end end - context 'already assigned' do + context "already assigned" do fab!(:post) { Fabricate(:post) } fab!(:post_2) { Fabricate(:post, topic: post.topic) } let(:topic) { post.topic } fab!(:user) { Fabricate(:user) } - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" - it 'does not allow to assign topic if post is already assigned' do + it "does not allow to assign topic if post is already assigned" do add_to_assign_allowed_group(user) assigner = Assigner.new(post, user) @@ -168,14 +164,22 @@ def assert_publish_topic_state(topic, user: nil, group: nil) end end - context 'move post' do + context "move post" do fab!(:old_topic) { Fabricate(:topic) } fab!(:post) { Fabricate(:post, topic: old_topic) } fab!(:user) { Fabricate(:user) } - fab!(:assignment) { Assignment.create!(target_id: post.id, target_type: "Post", topic_id: old_topic.id, assigned_by_user: user, assigned_to: user) } + fab!(:assignment) do + Assignment.create!( + target_id: post.id, + target_type: "Post", + topic_id: old_topic.id, + assigned_by_user: user, + assigned_to: user, + ) + end let(:new_topic) { Fabricate(:topic) } - it 'assignment becomes topic assignment when new topic' do + it "assignment becomes topic assignment when new topic" do post.update!(topic: new_topic) DiscourseEvent.trigger(:post_moved, post, old_topic.id) assignment.reload @@ -184,7 +188,7 @@ def assert_publish_topic_state(topic, user: nil, group: nil) expect(assignment.target_id).to eq(new_topic.id) end - it 'assigment is still post assignment when not first post' do + it "assigment is still post assignment when not first post" do post.update!(topic: new_topic, post_number: "3") DiscourseEvent.trigger(:post_moved, post, old_topic.id) assignment.reload diff --git a/spec/jobs/regular/assign_notification_spec.rb b/spec/jobs/regular/assign_notification_spec.rb index 6f639ac5..e996477e 100644 --- a/spec/jobs/regular/assign_notification_spec.rb +++ b/spec/jobs/regular/assign_notification_spec.rb @@ -1,51 +1,65 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" RSpec.describe Jobs::AssignNotification do - describe '#execute' do + describe "#execute" do fab!(:user1) { Fabricate(:user, last_seen_at: 1.day.ago) } fab!(:user2) { Fabricate(:user, last_seen_at: 1.day.ago) } - fab!(:topic) { Fabricate(:topic, title: 'Basic topic title') } + fab!(:topic) { Fabricate(:topic, title: "Basic topic title") } fab!(:post) { Fabricate(:post, topic: topic) } fab!(:pm_post) { Fabricate(:private_message_post) } fab!(:pm) { pm_post.topic } - fab!(:assign_allowed_group) { Group.find_by(name: 'staff') } + fab!(:assign_allowed_group) { Group.find_by(name: "staff") } def assert_publish_topic_state(topic, user) - message = MessageBus.track_publish('/private-messages/assigned') do - yield - end.first + message = MessageBus.track_publish("/private-messages/assigned") { yield }.first expect(message.data[:topic_id]).to eq(topic.id) expect(message.user_ids).to eq([user.id]) end - before do - assign_allowed_group.add(user1) - end - - context 'User' do - - it 'sends notification alert' do - messages = MessageBus.track_publish("/notification-alert/#{user2.id}") do - described_class.new.execute({ topic_id: topic.id, post_id: post.id, assigned_to_id: user2.id, assigned_to_type: 'User', assigned_by_id: user1.id, skip_small_action_post: false }) - end + before { assign_allowed_group.add(user1) } + + context "User" do + it "sends notification alert" do + messages = + MessageBus.track_publish("/notification-alert/#{user2.id}") do + described_class.new.execute( + { + topic_id: topic.id, + post_id: post.id, + assigned_to_id: user2.id, + assigned_to_type: "User", + assigned_by_id: user1.id, + skip_small_action_post: false, + }, + ) + end expect(messages.length).to eq(1) expect(messages.first.data[:excerpt]).to eq("assigned you the topic 'Basic topic title'") end - it 'should publish the right message when private message' do + it "should publish the right message when private message" do user = pm.allowed_users.first assign_allowed_group.add(user) assert_publish_topic_state(pm, user) do - described_class.new.execute({ topic_id: pm.id, post_id: pm_post.id, assigned_to_id: pm.allowed_users.first.id, assigned_to_type: 'User', assigned_by_id: user1.id, skip_small_action_post: false }) + described_class.new.execute( + { + topic_id: pm.id, + post_id: pm_post.id, + assigned_to_id: pm.allowed_users.first.id, + assigned_to_type: "User", + assigned_by_id: user1.id, + skip_small_action_post: false, + }, + ) end end - it 'sends a high priority notification to the assignee' do + it "sends a high priority notification to the assignee" do Notification.expects(:create!).with( notification_type: Notification.types[:assigned] || Notification.types[:custom], user_id: user2.id, @@ -53,20 +67,31 @@ def assert_publish_topic_state(topic, user) post_number: 1, high_priority: true, data: { - message: 'discourse_assign.assign_notification', + message: "discourse_assign.assign_notification", display_username: user1.username, - topic_title: topic.title - }.to_json + topic_title: topic.title, + }.to_json, + ) + described_class.new.execute( + { + topic_id: topic.id, + post_id: post.id, + assigned_to_id: user2.id, + assigned_to_type: "User", + assigned_by_id: user1.id, + skip_small_action_post: false, + }, ) - described_class.new.execute({ topic_id: topic.id, post_id: post.id, assigned_to_id: user2.id, assigned_to_type: 'User', assigned_by_id: user1.id, skip_small_action_post: false }) end end - context 'Group' do + context "Group" do fab!(:user3) { Fabricate(:user, last_seen_at: 1.day.ago) } fab!(:user4) { Fabricate(:user, suspended_till: 1.year.from_now) } - fab!(:group) { Fabricate(:group, name: 'Developers') } - let(:assignment) { Assignment.create!(topic: topic, assigned_by_user: user1, assigned_to: group) } + fab!(:group) { Fabricate(:group, name: "Developers") } + let(:assignment) do + Assignment.create!(topic: topic, assigned_by_user: user1, assigned_to: group) + end before do group.add(user2) @@ -74,26 +99,60 @@ def assert_publish_topic_state(topic, user) group.add(user4) end - it 'sends notification alert to all group members' do - messages = MessageBus.track_publish("/notification-alert/#{user2.id}") do - described_class.new.execute({ topic_id: topic.id, post_id: post.id, assigned_to_id: group.id, assigned_to_type: 'Group', assigned_by_id: user1.id, skip_small_action_post: false }) - end + it "sends notification alert to all group members" do + messages = + MessageBus.track_publish("/notification-alert/#{user2.id}") do + described_class.new.execute( + { + topic_id: topic.id, + post_id: post.id, + assigned_to_id: group.id, + assigned_to_type: "Group", + assigned_by_id: user1.id, + skip_small_action_post: false, + }, + ) + end expect(messages.length).to eq(1) - expect(messages.first.data[:excerpt]).to eq("assigned to Developers the topic 'Basic topic title'") + expect(messages.first.data[:excerpt]).to eq( + "assigned to Developers the topic 'Basic topic title'", + ) - messages = MessageBus.track_publish("/notification-alert/#{user3.id}") do - described_class.new.execute({ topic_id: topic.id, post_id: post.id, assigned_to_id: group.id, assigned_to_type: 'Group', assigned_by_id: user1.id, skip_small_action_post: false }) - end + messages = + MessageBus.track_publish("/notification-alert/#{user3.id}") do + described_class.new.execute( + { + topic_id: topic.id, + post_id: post.id, + assigned_to_id: group.id, + assigned_to_type: "Group", + assigned_by_id: user1.id, + skip_small_action_post: false, + }, + ) + end expect(messages.length).to eq(1) - expect(messages.first.data[:excerpt]).to eq("assigned to Developers the topic 'Basic topic title'") + expect(messages.first.data[:excerpt]).to eq( + "assigned to Developers the topic 'Basic topic title'", + ) - messages = MessageBus.track_publish("/notification-alert/#{user4.id}") do - described_class.new.execute({ topic_id: topic.id, post_id: post.id, assigned_to_id: group.id, assigned_to_type: 'Group', assigned_by_id: user1.id, skip_small_action_post: false }) - end + messages = + MessageBus.track_publish("/notification-alert/#{user4.id}") do + described_class.new.execute( + { + topic_id: topic.id, + post_id: post.id, + assigned_to_id: group.id, + assigned_to_type: "Group", + assigned_by_id: user1.id, + skip_small_action_post: false, + }, + ) + end expect(messages.length).to eq(0) end - it 'sends a high priority notification to all group members' do + it "sends a high priority notification to all group members" do [user2, user3, user4].each do |user| Notification.expects(:create!).with( notification_type: Notification.types[:assigned] || Notification.types[:custom], @@ -102,14 +161,23 @@ def assert_publish_topic_state(topic, user) post_number: 1, high_priority: true, data: { - message: 'discourse_assign.assign_group_notification', + message: "discourse_assign.assign_group_notification", display_username: group.name, - topic_title: topic.title - }.to_json + topic_title: topic.title, + }.to_json, ) end - described_class.new.execute({ topic_id: topic.id, post_id: post.id, assigned_to_id: group.id, assigned_to_type: 'Group', assigned_by_id: user1.id, skip_small_action_post: false }) + described_class.new.execute( + { + topic_id: topic.id, + post_id: post.id, + assigned_to_id: group.id, + assigned_to_type: "Group", + assigned_by_id: user1.id, + skip_small_action_post: false, + }, + ) end end end diff --git a/spec/jobs/regular/remind_user_spec.rb b/spec/jobs/regular/remind_user_spec.rb index 2c108084..34e3596a 100644 --- a/spec/jobs/regular/remind_user_spec.rb +++ b/spec/jobs/regular/remind_user_spec.rb @@ -1,13 +1,11 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" RSpec.describe Jobs::RemindUser do - describe '#execute' do + describe "#execute" do it "should raise the right error when user_id is invalid" do - expect do - described_class.new.execute({}) - end.to raise_error(Discourse::InvalidParameters) + expect do described_class.new.execute({}) end.to raise_error(Discourse::InvalidParameters) end end end diff --git a/spec/jobs/regular/unassign_notification_spec.rb b/spec/jobs/regular/unassign_notification_spec.rb index 6814d4ae..903c5934 100644 --- a/spec/jobs/regular/unassign_notification_spec.rb +++ b/spec/jobs/regular/unassign_notification_spec.rb @@ -1,51 +1,70 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" RSpec.describe Jobs::UnassignNotification do - describe '#execute' do + describe "#execute" do fab!(:user1) { Fabricate(:user) } fab!(:user2) { Fabricate(:user) } fab!(:topic) { Fabricate(:topic) } fab!(:post) { Fabricate(:post, topic: topic) } fab!(:pm_post) { Fabricate(:private_message_post) } fab!(:pm) { pm_post.topic } - fab!(:assign_allowed_group) { Group.find_by(name: 'staff') } + fab!(:assign_allowed_group) { Group.find_by(name: "staff") } - before do - assign_allowed_group.add(user1) - end + before { assign_allowed_group.add(user1) } def assert_publish_topic_state(topic, user) - message = MessageBus.track_publish('/private-messages/assigned') do - yield - end.first + message = MessageBus.track_publish("/private-messages/assigned") { yield }.first expect(message.data[:topic_id]).to eq(topic.id) expect(message.user_ids).to eq([user.id]) end - context 'User' do - it 'deletes notifications' do - Jobs::AssignNotification.new.execute({ topic_id: topic.id, post_id: post.id, assigned_to_id: user2.id, assigned_to_type: 'User', assigned_by_id: user1.id, skip_small_action_post: false }) + context "User" do + it "deletes notifications" do + Jobs::AssignNotification.new.execute( + { + topic_id: topic.id, + post_id: post.id, + assigned_to_id: user2.id, + assigned_to_type: "User", + assigned_by_id: user1.id, + skip_small_action_post: false, + }, + ) expect { - described_class.new.execute({ topic_id: topic.id, post_id: post.id, assigned_to_id: user2.id, assigned_to_type: 'User' }) + described_class.new.execute( + { + topic_id: topic.id, + post_id: post.id, + assigned_to_id: user2.id, + assigned_to_type: "User", + }, + ) }.to change { user2.notifications.count }.by(-1) end - it 'should publish the right message when private message' do + it "should publish the right message when private message" do user = pm.allowed_users.first assign_allowed_group.add(user) assert_publish_topic_state(pm, user) do - described_class.new.execute({ topic_id: pm.id, post_id: pm_post.id, assigned_to_id: pm.allowed_users.first.id, assigned_to_type: 'User' }) + described_class.new.execute( + { + topic_id: pm.id, + post_id: pm_post.id, + assigned_to_id: pm.allowed_users.first.id, + assigned_to_type: "User", + }, + ) end end end - context 'Group' do - fab!(:assign_allowed_group) { Group.find_by(name: 'staff') } + context "Group" do + fab!(:assign_allowed_group) { Group.find_by(name: "staff") } fab!(:user3) { Fabricate(:user) } fab!(:group) { Fabricate(:group) } @@ -54,11 +73,27 @@ def assert_publish_topic_state(topic, user) group.add(user3) end - it 'deletes notifications' do - Jobs::AssignNotification.new.execute({ topic_id: topic.id, post_id: post.id, assigned_to_id: group.id, assigned_to_type: 'Group', assigned_by_id: user1.id, skip_small_action_post: false }) + it "deletes notifications" do + Jobs::AssignNotification.new.execute( + { + topic_id: topic.id, + post_id: post.id, + assigned_to_id: group.id, + assigned_to_type: "Group", + assigned_by_id: user1.id, + skip_small_action_post: false, + }, + ) expect { - described_class.new.execute({ topic_id: topic.id, post_id: post.id, assigned_to_id: group.id, assigned_to_type: 'Group' }) + described_class.new.execute( + { + topic_id: topic.id, + post_id: post.id, + assigned_to_id: group.id, + assigned_to_type: "Group", + }, + ) }.to change { Notification.count }.by(-2) end end diff --git a/spec/jobs/scheduled/enqueue_reminders_spec.rb b/spec/jobs/scheduled/enqueue_reminders_spec.rb index 1c5e5b57..4733101d 100644 --- a/spec/jobs/scheduled/enqueue_reminders_spec.rb +++ b/spec/jobs/scheduled/enqueue_reminders_spec.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" RSpec.describe Jobs::EnqueueReminders do - let(:assign_allowed_group) { Group.find_by(name: 'staff') } + let(:assign_allowed_group) { Group.find_by(name: "staff") } let(:user) { Fabricate(:user, groups: [assign_allowed_group]) } before do @@ -11,26 +11,26 @@ SiteSetting.assign_enabled = true end - describe '#execute' do - it 'does not enqueue reminders when there are no assigned tasks' do + describe "#execute" do + it "does not enqueue reminders when there are no assigned tasks" do assert_reminders_enqueued(0) end - it 'does not enqueue reminders when no groups are allowed to assign' do - SiteSetting.assign_allowed_on_groups = '' + it "does not enqueue reminders when no groups are allowed to assign" do + SiteSetting.assign_allowed_on_groups = "" assign_multiple_tasks_to(user) assert_reminders_enqueued(0) end - it 'enqueues a reminder when the user has more than one task' do + it "enqueues a reminder when the user has more than one task" do assign_multiple_tasks_to(user) assert_reminders_enqueued(1) end - it 'does not enqueue a reminder when the user only has one task' do + it "does not enqueue a reminder when the user only has one task" do assign_one_task_to(user) assert_reminders_enqueued(0) @@ -43,31 +43,32 @@ assert_reminders_enqueued(0) end - it 'enqueues a reminder if the user was reminded more than a month ago' do + it "enqueues a reminder if the user was reminded more than a month ago" do user.upsert_custom_fields(PendingAssignsReminder::REMINDED_AT => 31.days.ago) assign_multiple_tasks_to(user) assert_reminders_enqueued(1) end - it 'does not enqueue reminders if the remind frequency is set to never' do + it "does not enqueue reminders if the remind frequency is set to never" do SiteSetting.remind_assigns_frequency = 0 assign_multiple_tasks_to(user) assert_reminders_enqueued(0) end - it 'does not enqueue reminders if the topic was just assigned to the user' do + it "does not enqueue reminders if the topic was just assigned to the user" do just_assigned = DateTime.now assign_multiple_tasks_to(user, assigned_on: just_assigned) assert_reminders_enqueued(0) end - it 'enqueues a reminder when the user overrides the global frequency' do + it "enqueues a reminder when the user overrides the global frequency" do SiteSetting.remind_assigns_frequency = 0 user.custom_fields.merge!( - PendingAssignsReminder::REMINDERS_FREQUENCY => RemindAssignsFrequencySiteSettings::DAILY_MINUTES + PendingAssignsReminder::REMINDERS_FREQUENCY => + RemindAssignsFrequencySiteSettings::DAILY_MINUTES, ) user.save_custom_fields @@ -91,9 +92,7 @@ def assert_reminders_enqueued(expected_amount) end def assign_one_task_to(user, assigned_on: 3.months.ago, post: Fabricate(:post)) - freeze_time(assigned_on) do - Assigner.new(post.topic, user).assign(user) - end + freeze_time(assigned_on) { Assigner.new(post.topic, user).assign(user) } end def assign_multiple_tasks_to(user, assigned_on: 3.months.ago) diff --git a/spec/lib/assigner_spec.rb b/spec/lib/assigner_spec.rb index c7489dc9..a0882842 100644 --- a/spec/lib/assigner_spec.rb +++ b/spec/lib/assigner_spec.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" RSpec.describe Assigner do before { SiteSetting.assign_enabled = true } - let(:assign_allowed_group) { Group.find_by(name: 'staff') } + let(:assign_allowed_group) { Group.find_by(name: "staff") } let(:pm_post) { Fabricate(:private_message_post) } let(:pm) { pm_post.topic } @@ -21,27 +21,23 @@ let(:assigner_self) { described_class.new(topic, moderator) } it "can assign and unassign correctly" do - expect_enqueued_with(job: :assign_notification) do - assigner.assign(moderator) - end + expect_enqueued_with(job: :assign_notification) { assigner.assign(moderator) } - expect(TopicQuery.new( - moderator, assigned: moderator.username - ).list_latest.topics).to eq([topic]) + expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to eq( + [topic], + ) - expect(TopicUser.find_by(user: moderator).notification_level) - .to eq(TopicUser.notification_levels[:watching]) + expect(TopicUser.find_by(user: moderator).notification_level).to eq( + TopicUser.notification_levels[:watching], + ) - expect_enqueued_with(job: :unassign_notification) do - assigner.unassign - end + expect_enqueued_with(job: :unassign_notification) { assigner.unassign } - expect(TopicQuery.new( - moderator, assigned: moderator.username - ).list_latest.topics).to eq([]) + expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to eq([]) - expect(TopicUser.find_by(user: moderator).notification_level) - .to eq(TopicUser.notification_levels[:tracking]) + expect(TopicUser.find_by(user: moderator).notification_level).to eq( + TopicUser.notification_levels[:tracking], + ) end it "can assign with note" do @@ -51,63 +47,76 @@ end it "assign with note adds moderator post with note" do - expect { assigner.assign(moderator, note: "tomtom best mom") }.to change { topic.posts.count }.by(1) + expect { assigner.assign(moderator, note: "tomtom best mom") }.to change { + topic.posts.count + }.by(1) expect(topic.posts.last.raw).to eq "tomtom best mom" end it "publishes topic assignment after assign and unassign" do - messages = MessageBus.track_publish('/staff/topic-assignment') do - assigner = described_class.new(topic, moderator_2) - assigner.assign(moderator, note: "tomtom best mom") - assigner.unassign - end + messages = + MessageBus.track_publish("/staff/topic-assignment") do + assigner = described_class.new(topic, moderator_2) + assigner.assign(moderator, note: "tomtom best mom") + assigner.unassign + end expect(messages[0].channel).to eq "/staff/topic-assignment" - expect(messages[0].data).to include({ - type: "assigned", - topic_id: topic.id, - post_id: false, - post_number: false, - assigned_type: "User", - assigned_to: BasicUserSerializer.new(moderator, scope: Guardian.new, root: false).as_json, - assignment_note: "tomtom best mom" - }) + expect(messages[0].data).to include( + { + type: "assigned", + topic_id: topic.id, + post_id: false, + post_number: false, + assigned_type: "User", + assigned_to: BasicUserSerializer.new(moderator, scope: Guardian.new, root: false).as_json, + assignment_note: "tomtom best mom", + }, + ) expect(messages[1].channel).to eq "/staff/topic-assignment" - expect(messages[1].data).to include({ - type: "unassigned", - topic_id: topic.id, - post_id: false, - post_number: false, - assigned_type: "User", - assignment_note: nil - }) + expect(messages[1].data).to include( + { + type: "unassigned", + topic_id: topic.id, + post_id: false, + post_number: false, + assigned_type: "User", + assignment_note: nil, + }, + ) end - it 'does not update notification level if already watching' do - TopicUser.change(moderator.id, topic.id, - notification_level: TopicUser.notification_levels[:watching] + it "does not update notification level if already watching" do + TopicUser.change( + moderator.id, + topic.id, + notification_level: TopicUser.notification_levels[:watching], ) - expect do - assigner_self.assign(moderator) - end.to_not change { TopicUser.last.notifications_reason_id } + expect do assigner_self.assign(moderator) end.to_not change { + TopicUser.last.notifications_reason_id + } end - it 'does not update notification level if it is not set by the plugin' do + it "does not update notification level if it is not set by the plugin" do assigner.assign(moderator) - expect(TopicUser.find_by(user: moderator).notification_level) - .to eq(TopicUser.notification_levels[:watching]) + expect(TopicUser.find_by(user: moderator).notification_level).to eq( + TopicUser.notification_levels[:watching], + ) - TopicUser.change(moderator.id, topic.id, - notification_level: TopicUser.notification_levels[:muted] + TopicUser.change( + moderator.id, + topic.id, + notification_level: TopicUser.notification_levels[:muted], ) assigner.unassign - expect(TopicUser.find_by(user: moderator, topic: topic).notification_level) - .to eq(TopicUser.notification_levels[:muted]) + expect(TopicUser.find_by(user: moderator, topic: topic).notification_level).to eq( + TopicUser.notification_levels[:muted], + ) end context "when assigns_by_staff_mention is set to true" do @@ -206,7 +215,7 @@ def assigned_to?(assignee) expect(second_assign[:success]).to eq(true) end - it 'fails to assign when the assigned user and note is the same' do + it "fails to assign when the assigned user and note is the same" do assigner = described_class.new(topic, moderator_2) assigner.assign(moderator, note: "note me down") @@ -216,7 +225,7 @@ def assigned_to?(assignee) expect(assign[:reason]).to eq(:already_assigned) end - it 'allows assign when the assigned user is same but note is different' do + it "allows assign when the assigned user is same but note is different" do assigner = described_class.new(topic, moderator_2) assigner.assign(moderator, note: "note me down") @@ -225,21 +234,21 @@ def assigned_to?(assignee) expect(assign[:success]).to eq(true) end - it 'fails to assign when the assigned user cannot view the pm' do + it "fails to assign when the assigned user cannot view the pm" do assign = described_class.new(pm, moderator_2).assign(moderator) expect(assign[:success]).to eq(false) expect(assign[:reason]).to eq(:forbidden_assignee_not_pm_participant) end - it 'fails to assign when the assigned admin cannot view the pm' do + it "fails to assign when the assigned admin cannot view the pm" do assign = described_class.new(pm, moderator_2).assign(admin) expect(assign[:success]).to eq(false) expect(assign[:reason]).to eq(:forbidden_assignee_not_pm_participant) end - it 'fails to assign when not all group members has access to pm' do + it "fails to assign when not all group members has access to pm" do assign = described_class.new(pm, moderator_2).assign(moderator.groups.first) expect(assign[:success]).to eq(false) @@ -252,14 +261,14 @@ def assigned_to?(assignee) expect(assign[:reason]).to eq(:forbidden_group_assignee_not_pm_participant) end - it 'fails to assign when the assigned user cannot view the topic' do + it "fails to assign when the assigned user cannot view the topic" do assign = described_class.new(secure_topic, moderator_2).assign(moderator) expect(assign[:success]).to eq(false) expect(assign[:reason]).to eq(:forbidden_assignee_cant_see_topic) end - it 'fails to assign when the not all group members can view the topic' do + it "fails to assign when the not all group members can view the topic" do assign = described_class.new(secure_topic, moderator_2).assign(moderator.groups.first) expect(assign[:success]).to eq(false) @@ -283,7 +292,7 @@ def assigned_to?(assignee) expect(assign[:success]).to eq(true) end - it 'triggers error for incorrect type' do + it "triggers error for incorrect type" do expect do described_class.new(secure_category, moderator).assign(moderator) end.to raise_error(Discourse::InvalidAccess) @@ -293,9 +302,9 @@ def assigned_to?(assignee) it "does not recreate assignment if no assignee change" do assigner.assign(moderator) - expect do - assigner.assign(moderator, note: "new notes!") - end.to_not change { Assignment.last.id } + expect do assigner.assign(moderator, note: "new notes!") end.to_not change { + Assignment.last.id + } end it "updates notes" do @@ -317,21 +326,25 @@ def assigned_to?(assignee) it "publishes topic assignment with note" do assigner.assign(moderator) - messages = MessageBus.track_publish('/staff/topic-assignment') do - assigner = described_class.new(topic, moderator_2) - assigner.assign(moderator, note: "new notes!") - end + messages = + MessageBus.track_publish("/staff/topic-assignment") do + assigner = described_class.new(topic, moderator_2) + assigner.assign(moderator, note: "new notes!") + end expect(messages[0].channel).to eq "/staff/topic-assignment" - expect(messages[0].data).to include({ - type: "assigned", - topic_id: topic.id, - post_id: false, - post_number: false, - assigned_type: "User", - assigned_to: BasicUserSerializer.new(moderator, scope: Guardian.new, root: false).as_json, - assignment_note: "new notes!" - }) + expect(messages[0].data).to include( + { + type: "assigned", + topic_id: topic.id, + post_id: false, + post_number: false, + assigned_type: "User", + assigned_to: + BasicUserSerializer.new(moderator, scope: Guardian.new, root: false).as_json, + assignment_note: "new notes!", + }, + ) end it "adds a note_change small action post" do @@ -348,7 +361,9 @@ def assigned_to?(assignee) context "assign_self_regex" do fab!(:me) { Fabricate(:admin) } fab!(:op) { Fabricate(:post) } - fab!(:reply) { Fabricate(:post, topic: op.topic, user: me, raw: "Will fix. Added to my list ;)") } + fab!(:reply) do + Fabricate(:post, topic: op.topic, user: me, raw: "Will fix. Added to my list ;)") + end before do SiteSetting.assigns_by_staff_mention = true @@ -388,7 +403,14 @@ def assigned_to?(assignee) fab!(:me) { Fabricate(:admin) } fab!(:other) { Fabricate(:admin) } fab!(:op) { Fabricate(:post) } - fab!(:reply) { Fabricate(:post, topic: op.topic, user: me, raw: "can you add this to your list, @#{other.username}") } + fab!(:reply) do + Fabricate( + :post, + topic: op.topic, + user: me, + raw: "can you add this to your list, @#{other.username}", + ) + end before do SiteSetting.assigns_by_staff_mention = true @@ -407,7 +429,7 @@ def assigned_to?(assignee) let(:topic) { post.topic } let(:moderator) { Fabricate(:moderator, groups: [assign_allowed_group]) } - context 'topic' do + context "topic" do let(:assigner) { described_class.new(topic, moderator) } before do @@ -417,26 +439,34 @@ def assigned_to?(assignee) it "unassigns on topic closed" do topic.update_status("closed", true, moderator) - expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to be_blank + expect( + TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics, + ).to be_blank end it "unassigns on topic autoclosed" do topic.update_status("autoclosed", true, moderator) - expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to be_blank + expect( + TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics, + ).to be_blank end it "does not unassign on topic open" do topic.update_status("closed", false, moderator) - expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to eq([topic]) + expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to eq( + [topic], + ) end it "does not unassign on automatic topic open" do topic.update_status("autoclosed", false, moderator) - expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to eq([topic]) + expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to eq( + [topic], + ) end end - context 'post' do + context "post" do let(:post_2) { Fabricate(:post, topic: topic) } let(:assigner) { described_class.new(post_2, moderator) } @@ -447,7 +477,7 @@ def assigned_to?(assignee) assigner.assign(moderator) end - it 'deactivates post assignments when topic is closed' do + it "deactivates post assignments when topic is closed" do assigner.assign(moderator) expect(post_2.assignment.active).to be true @@ -456,7 +486,7 @@ def assigned_to?(assignee) expect(post_2.assignment.reload.active).to be false end - it 'deactivates post assignments when post is deleted and activate when recovered' do + it "deactivates post assignments when post is deleted and activate when recovered" do assigner.assign(moderator) expect(post_2.assignment.active).to be true @@ -468,7 +498,7 @@ def assigned_to?(assignee) expect(post_2.assignment.reload.active).to be true end - it 'deletes post small action for deleted post' do + it "deletes post small action for deleted post" do assigner.assign(moderator) small_action_post = PostCustomField.where(name: "action_code_post_id").first.post @@ -483,7 +513,7 @@ def assigned_to?(assignee) let(:topic) { post.topic } let(:moderator) { Fabricate(:moderator, groups: [assign_allowed_group]) } - context 'topic' do + context "topic" do let(:assigner) { described_class.new(topic, moderator) } before do @@ -494,14 +524,18 @@ def assigned_to?(assignee) it "reassigns on topic open" do topic.update_status("closed", true, moderator) - expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to be_blank + expect( + TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics, + ).to be_blank topic.update_status("closed", false, moderator) - expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to eq([topic]) + expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to eq( + [topic], + ) end end - context 'post' do + context "post" do let(:post_2) { Fabricate(:post, topic: topic) } let(:assigner) { described_class.new(post_2, moderator) } @@ -512,7 +546,7 @@ def assigned_to?(assignee) assigner.assign(moderator) end - it 'reassigns post on topic open' do + it "reassigns post on topic open" do assigner.assign(moderator) expect(post_2.assignment.active).to be true @@ -535,36 +569,41 @@ def assigned_to?(assignee) it "send an email if set to 'always'" do SiteSetting.assign_mailer = AssignMailer.levels[:always] - expect { described_class.new(topic, moderator).assign(moderator) } - .to change { ActionMailer::Base.deliveries.size }.by(1) + expect { described_class.new(topic, moderator).assign(moderator) }.to change { + ActionMailer::Base.deliveries.size + }.by(1) end it "doesn't send an email if assignee is a group" do SiteSetting.assign_mailer = AssignMailer.levels[:always] - expect { described_class.new(topic, moderator).assign(assign_allowed_group) } - .to change { ActionMailer::Base.deliveries.size }.by(0) + expect { described_class.new(topic, moderator).assign(assign_allowed_group) }.to change { + ActionMailer::Base.deliveries.size + }.by(0) end it "doesn't send an email if the assigner and assignee are not different" do SiteSetting.assign_mailer = AssignMailer.levels[:different_users] - expect { described_class.new(topic, moderator).assign(moderator_2) } - .to change { ActionMailer::Base.deliveries.size }.by(1) + expect { described_class.new(topic, moderator).assign(moderator_2) }.to change { + ActionMailer::Base.deliveries.size + }.by(1) end it "doesn't send an email if the assigner and assignee are not different" do SiteSetting.assign_mailer = AssignMailer.levels[:different_users] - expect { described_class.new(topic, moderator).assign(moderator) } - .to change { ActionMailer::Base.deliveries.size }.by(0) + expect { described_class.new(topic, moderator).assign(moderator) }.to change { + ActionMailer::Base.deliveries.size + }.by(0) end it "doesn't send an email" do SiteSetting.assign_mailer = AssignMailer.levels[:never] - expect { described_class.new(topic, moderator).assign(moderator_2) } - .to change { ActionMailer::Base.deliveries.size }.by(0) + expect { described_class.new(topic, moderator).assign(moderator_2) }.to change { + ActionMailer::Base.deliveries.size + }.by(0) end end end diff --git a/spec/lib/pending_assigns_reminder_spec.rb b/spec/lib/pending_assigns_reminder_spec.rb index 01056cc2..f1476767 100644 --- a/spec/lib/pending_assigns_reminder_spec.rb +++ b/spec/lib/pending_assigns_reminder_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" def assert_reminder_not_created expect { subject.remind(user) }.to change { Post.count }.by(0) @@ -12,21 +12,21 @@ def assert_reminder_not_created let(:user) { Fabricate(:user) } - it 'does not create a reminder if the user has 0 assigned topics' do + it "does not create a reminder if the user has 0 assigned topics" do assert_reminder_not_created end - it 'does not create a reminder if the user only has one task' do + it "does not create a reminder if the user only has one task" do post = Fabricate(:post) Assigner.new(post.topic, user).assign(user) assert_reminder_not_created end - describe 'when the user has multiple tasks' do + describe "when the user has multiple tasks" do let(:system) { Discourse.system_user } - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" before do add_to_assign_allowed_group(user) @@ -46,7 +46,7 @@ def assert_reminder_not_created @post4.topic.update(category: secure_category) end - it 'creates a reminder for a particular user and sets the timestamp of the last reminder' do + it "creates a reminder for a particular user and sets the timestamp of the last reminder" do freeze_time subject.remind(user) @@ -56,31 +56,29 @@ def assert_reminder_not_created expect(topic.user).to eq(system) expect(topic.archetype).to eq(Archetype.private_message) - expect(topic.topic_allowed_users.pluck(:user_id)).to contain_exactly( - system.id, user.id - ) + expect(topic.topic_allowed_users.pluck(:user_id)).to contain_exactly(system.id, user.id) - expect(topic.title).to eq(I18n.t( - 'pending_assigns_reminder.title', - pending_assignments: 3 - )) + expect(topic.title).to eq(I18n.t("pending_assigns_reminder.title", pending_assignments: 3)) expect(post.raw).to include(@post1.topic.fancy_title) expect(post.raw).to include(@post2.topic.fancy_title) expect(post.raw).to_not include(@post3.topic.fancy_title) expect(post.raw).to_not include(@post4.topic.fancy_title) - expect( - user.reload.custom_fields[described_class::REMINDED_AT].to_datetime - ).to eq_time(DateTime.now) + expect(user.reload.custom_fields[described_class::REMINDED_AT].to_datetime).to eq_time( + DateTime.now, + ) end - it 'deletes previous reminders when creating a new one' do + it "deletes previous reminders when creating a new one" do subject.remind(user) subject.remind(user) - reminders_count = Topic.joins(:_custom_fields) - .where(topic_custom_fields: { name: described_class::CUSTOM_FIELD_NAME }).count + reminders_count = + Topic + .joins(:_custom_fields) + .where(topic_custom_fields: { name: described_class::CUSTOM_FIELD_NAME }) + .count expect(reminders_count).to eq(1) end @@ -96,8 +94,11 @@ def assert_reminder_not_created subject.remind(another_user) - reminders_count = Topic.joins(:_custom_fields) - .where(topic_custom_fields: { name: described_class::CUSTOM_FIELD_NAME }).count + reminders_count = + Topic + .joins(:_custom_fields) + .where(topic_custom_fields: { name: described_class::CUSTOM_FIELD_NAME }) + .count expect(reminders_count).to eq(2) end @@ -107,8 +108,11 @@ def assert_reminder_not_created Fabricate(:post, topic: Topic.last) subject.remind(user) - reminders_count = Topic.joins(:_custom_fields) - .where(topic_custom_fields: { name: described_class::CUSTOM_FIELD_NAME }).count + reminders_count = + Topic + .joins(:_custom_fields) + .where(topic_custom_fields: { name: described_class::CUSTOM_FIELD_NAME }) + .count expect(reminders_count).to eq(2) end @@ -124,10 +128,7 @@ def assert_reminder_not_created post = Post.last topic = post.topic - expect(topic.title).to eq(I18n.t( - 'pending_assigns_reminder.title', - pending_assignments: 4 - )) + expect(topic.title).to eq(I18n.t("pending_assigns_reminder.title", pending_assignments: 4)) @post5.topic.update_status("closed", true, Discourse.system_user) expect(@post5.topic.closed).to eq(true) @@ -137,11 +138,7 @@ def assert_reminder_not_created post = Post.last topic = post.topic - expect(topic.title).to eq(I18n.t( - 'pending_assigns_reminder.title', - pending_assignments: 3 - )) + expect(topic.title).to eq(I18n.t("pending_assigns_reminder.title", pending_assignments: 3)) end - end end diff --git a/spec/lib/random_assign_utils_spec.rb b/spec/lib/random_assign_utils_spec.rb index 524b97ff..17a51d01 100644 --- a/spec/lib/random_assign_utils_spec.rb +++ b/spec/lib/random_assign_utils_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' -require 'random_assign_utils' +require "rails_helper" +require_relative "../support/assign_allowed_group" +require "random_assign_utils" describe RandomAssignUtils do before do @@ -12,33 +12,44 @@ Rails.logger = @fake_logger = FakeLogger.new end - after do - Rails.logger = @orig_logger - end + after { Rails.logger = @orig_logger } FakeAutomation = Struct.new(:id) let(:post) { Fabricate(:post) } let!(:automation) { FakeAutomation.new(1) } - describe '.automation_script!' do - context 'all users of group are on holidays' do + describe ".automation_script!" do + context "all users of group are on holidays" do fab!(:topic_1) { Fabricate(:topic) } fab!(:group_1) { Fabricate(:group) } fab!(:user_1) { Fabricate(:user) } before do group_1.add(user_1) - UserCustomField.create!(name: 'on_holiday', value: 't', user_id: user_1.id) + UserCustomField.create!(name: "on_holiday", value: "t", user_id: user_1.id) end - it 'creates post on the topic' do - described_class.automation_script!({}, { 'assignees_group' => { 'value' => group_1.id }, 'assigned_topic' => { 'value' => topic_1.id } }, automation) - expect(topic_1.posts.first.raw).to match("Attempted randomly assign a member of `@#{group_1.name}`, but no one was available.") + it "creates post on the topic" do + described_class.automation_script!( + {}, + { + "assignees_group" => { + "value" => group_1.id, + }, + "assigned_topic" => { + "value" => topic_1.id, + }, + }, + automation, + ) + expect(topic_1.posts.first.raw).to match( + "Attempted randomly assign a member of `@#{group_1.name}`, but no one was available.", + ) end end - context 'all users of group have been assigned recently' do + context "all users of group have been assigned recently" do fab!(:topic_1) { Fabricate(:topic) } fab!(:group_1) { Fabricate(:group) } fab!(:user_1) { Fabricate(:user) } @@ -48,127 +59,217 @@ group_1.add(user_1) end - it 'creates post on the topic' do - described_class.automation_script!({}, { 'assignees_group' => { 'value' => group_1.id }, 'assigned_topic' => { 'value' => topic_1.id } }, automation) - expect(topic_1.posts.first.raw).to match("Attempted randomly assign a member of `@#{group_1.name}`, but no one was available.") + it "creates post on the topic" do + described_class.automation_script!( + {}, + { + "assignees_group" => { + "value" => group_1.id, + }, + "assigned_topic" => { + "value" => topic_1.id, + }, + }, + automation, + ) + expect(topic_1.posts.first.raw).to match( + "Attempted randomly assign a member of `@#{group_1.name}`, but no one was available.", + ) end end - context 'user can be assigned' do + context "user can be assigned" do fab!(:group_1) { Fabricate(:group) } fab!(:user_1) { Fabricate(:user) } fab!(:topic_1) { Fabricate(:topic) } before do - SiteSetting.assign_allowed_on_groups = [group_1.id.to_s].join('|') + SiteSetting.assign_allowed_on_groups = [group_1.id.to_s].join("|") group_1.add(user_1) end - context 'post_template is set' do - it 'creates a post with the template and assign the user' do - described_class.automation_script!({}, { 'post_template' => { 'value' => 'this is a post template' }, 'assignees_group' => { 'value' => group_1.id }, 'assigned_topic' => { 'value' => topic_1.id } }, automation) - expect(topic_1.posts.first.raw).to match('this is a post template') + context "post_template is set" do + it "creates a post with the template and assign the user" do + described_class.automation_script!( + {}, + { + "post_template" => { + "value" => "this is a post template", + }, + "assignees_group" => { + "value" => group_1.id, + }, + "assigned_topic" => { + "value" => topic_1.id, + }, + }, + automation, + ) + expect(topic_1.posts.first.raw).to match("this is a post template") end end - context 'post_template is not set' do + context "post_template is not set" do fab!(:post_1) { Fabricate(:post, topic: topic_1) } - it 'assigns the user to the topic' do - described_class.automation_script!({}, { 'assignees_group' => { 'value' => group_1.id }, 'assigned_topic' => { 'value' => topic_1.id } }, automation) + it "assigns the user to the topic" do + described_class.automation_script!( + {}, + { + "assignees_group" => { + "value" => group_1.id, + }, + "assigned_topic" => { + "value" => topic_1.id, + }, + }, + automation, + ) expect(topic_1.assignment.assigned_to_id).to eq(user_1.id) end end end - context 'all users in working hours' do + context "all users in working hours" do fab!(:topic_1) { Fabricate(:topic) } fab!(:group_1) { Fabricate(:group) } fab!(:user_1) { Fabricate(:user) } before do - freeze_time('2022-10-01 02:00') - UserOption.find_by(user_id: user_1.id).update(timezone: 'Europe/Paris') + freeze_time("2022-10-01 02:00") + UserOption.find_by(user_id: user_1.id).update(timezone: "Europe/Paris") group_1.add(user_1) end - it 'creates post on the topic' do - described_class.automation_script!({}, { 'in_working_hours' => { 'value' => true }, 'assignees_group' => { 'value' => group_1.id }, 'assigned_topic' => { 'value' => topic_1.id } }, automation) - expect(topic_1.posts.first.raw).to match("Attempted randomly assign a member of `@#{group_1.name}`, but no one was available.") + it "creates post on the topic" do + described_class.automation_script!( + {}, + { + "in_working_hours" => { + "value" => true, + }, + "assignees_group" => { + "value" => group_1.id, + }, + "assigned_topic" => { + "value" => topic_1.id, + }, + }, + automation, + ) + expect(topic_1.posts.first.raw).to match( + "Attempted randomly assign a member of `@#{group_1.name}`, but no one was available.", + ) end end - context 'assignees_group not provided' do + context "assignees_group not provided" do fab!(:topic_1) { Fabricate(:topic) } - it 'raises an error' do + it "raises an error" do expect { - described_class.automation_script!({}, { 'assigned_topic' => { 'value' => topic_1.id } }, automation) + described_class.automation_script!( + {}, + { "assigned_topic" => { "value" => topic_1.id } }, + automation, + ) }.to raise_error(/`assignees_group` not provided/) end end - context 'assignees_group not found' do + context "assignees_group not found" do fab!(:topic_1) { Fabricate(:topic) } - it 'raises an error' do + it "raises an error" do expect { - described_class.automation_script!({}, { 'assigned_topic' => { 'value' => topic_1.id }, 'assignees_group' => { 'value' => -1 } }, automation) + described_class.automation_script!( + {}, + { + "assigned_topic" => { + "value" => topic_1.id, + }, + "assignees_group" => { + "value" => -1, + }, + }, + automation, + ) }.to raise_error(/Group\(-1\) not found/) end end - context 'assigned_topic not provided' do - it 'raises an error' do - expect { - described_class.automation_script!({}, {}, automation) - }.to raise_error(/`assigned_topic` not provided/) + context "assigned_topic not provided" do + it "raises an error" do + expect { described_class.automation_script!({}, {}, automation) }.to raise_error( + /`assigned_topic` not provided/, + ) end end - context 'assigned_topic is not found' do - it 'raises an error' do + context "assigned_topic is not found" do + it "raises an error" do expect { - described_class.automation_script!({}, { 'assigned_topic' => { 'value' => 1 } }, automation) + described_class.automation_script!( + {}, + { "assigned_topic" => { "value" => 1 } }, + automation, + ) }.to raise_error(/Topic\(1\) not found/) end end - context 'minimum_time_between_assignments is set' do - context 'the topic has been assigned recently' do + context "minimum_time_between_assignments is set" do + context "the topic has been assigned recently" do fab!(:topic_1) { Fabricate(:topic) } before do freeze_time - TopicCustomField.create!(name: 'assigned_to_id', topic_id: topic_1.id, created_at: 20.hours.ago) + TopicCustomField.create!( + name: "assigned_to_id", + topic_id: topic_1.id, + created_at: 20.hours.ago, + ) end - it 'logs a warning' do - described_class.automation_script!({}, { 'assigned_topic' => { 'value' => topic_1.id }, 'minimum_time_between_assignments' => { 'value' => 10 } }, automation) - expect(Rails.logger.infos.first).to match(/Topic\(#{topic_1.id}\) has already been assigned recently/) + it "logs a warning" do + described_class.automation_script!( + {}, + { + "assigned_topic" => { + "value" => topic_1.id, + }, + "minimum_time_between_assignments" => { + "value" => 10, + }, + }, + automation, + ) + expect(Rails.logger.infos.first).to match( + /Topic\(#{topic_1.id}\) has already been assigned recently/, + ) end end end end - describe '.recently_assigned_users_ids' do - context 'no one has been assigned' do - it 'returns an empty array' do + describe ".recently_assigned_users_ids" do + context "no one has been assigned" do + it "returns an empty array" do assignees_ids = described_class.recently_assigned_users_ids(post.topic_id, 2.months.ago) expect(assignees_ids).to eq([]) end end - context 'users have been assigned' do + context "users have been assigned" do let(:admin) { Fabricate(:admin) } - let(:assign_allowed_group) { Group.find_by(name: 'staff') } + let(:assign_allowed_group) { Group.find_by(name: "staff") } let(:user_1) { Fabricate(:user, groups: [assign_allowed_group]) } let(:user_2) { Fabricate(:user, groups: [assign_allowed_group]) } let(:user_3) { Fabricate(:user, groups: [assign_allowed_group]) } let(:user_4) { Fabricate(:user, groups: [assign_allowed_group]) } let(:post_2) { Fabricate(:post, topic: post.topic) } - it 'returns the recently assigned user ids' do + it "returns the recently assigned user ids" do freeze_time 1.months.ago do Assigner.new(post.topic, admin).assign(user_1) Assigner.new(post.topic, admin).assign(user_2) diff --git a/spec/lib/topic_query_spec.rb b/spec/lib/topic_query_spec.rb index 377c4015..0ff0a42e 100644 --- a/spec/lib/topic_query_spec.rb +++ b/spec/lib/topic_query_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'topic_view' +require "topic_view" describe TopicQuery do fab!(:user) { Fabricate(:user) } @@ -13,17 +13,13 @@ fab!(:group) { Fabricate(:group) } - describe '#list_group_topics_assigned' do + describe "#list_group_topics_assigned" do before do SiteSetting.assign_enabled = true - [user, admin, other_admin].each do |user| - group.add(user) - end + [user, admin, other_admin].each { |user| group.add(user) } - [user_pm, admin_pm, other_admin_pm].each do |topic| - Fabricate(:post, topic: topic) - end + [user_pm, admin_pm, other_admin_pm].each { |topic| Fabricate(:post, topic: topic) } Fabricate(:topic_allowed_user, user: admin, topic: user_pm) Assigner.new(user_pm, Discourse.system_user).assign(admin) @@ -32,9 +28,17 @@ end it "includes PMs from all users" do - expect(TopicQuery.new(user).list_group_topics_assigned(group).topics).to contain_exactly(user_pm) - expect(TopicQuery.new(admin).list_group_topics_assigned(group).topics).to contain_exactly(user_pm, admin_pm, other_admin_pm) - expect(TopicQuery.new(other_admin).list_group_topics_assigned(group).topics).to contain_exactly(user_pm, admin_pm, other_admin_pm) + expect(TopicQuery.new(user).list_group_topics_assigned(group).topics).to contain_exactly( + user_pm, + ) + expect(TopicQuery.new(admin).list_group_topics_assigned(group).topics).to contain_exactly( + user_pm, + admin_pm, + other_admin_pm, + ) + expect( + TopicQuery.new(other_admin).list_group_topics_assigned(group).topics, + ).to contain_exactly(user_pm, admin_pm, other_admin_pm) end end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 059b35ef..2a515bc8 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -1,21 +1,18 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" RSpec.describe Group do let(:group) { Fabricate(:group) } - before do - SiteSetting.assign_enabled = true - end - - context 'Tracking changes that could affect the allow assign on groups site setting' do + before { SiteSetting.assign_enabled = true } - let(:removed_group_setting) { '3|4' } + context "Tracking changes that could affect the allow assign on groups site setting" do + let(:removed_group_setting) { "3|4" } let(:group_attribute) { group.id } - it 'removes the group from the setting when the group gets destroyed' do + it "removes the group from the setting when the group gets destroyed" do SiteSetting.assign_allowed_on_groups = "#{group_attribute}|#{removed_group_setting}" group.destroy! @@ -23,7 +20,7 @@ expect(SiteSetting.assign_allowed_on_groups).to eq removed_group_setting end - it 'removes the group from the setting when this is the last one on the list' do + it "removes the group from the setting when this is the last one on the list" do SiteSetting.assign_allowed_on_groups = "#{removed_group_setting}|#{group_attribute}" group.destroy! @@ -31,7 +28,7 @@ expect(SiteSetting.assign_allowed_on_groups).to eq removed_group_setting end - it 'removes the group from the list when it is on the middle of the list' do + it "removes the group from the list when it is on the middle of the list" do allowed_groups = "3|#{group_attribute}|4" SiteSetting.assign_allowed_on_groups = allowed_groups @@ -41,13 +38,13 @@ end end - context 'includes can_show_assigned_tab? method' do + context "includes can_show_assigned_tab? method" do let(:admin) { Fabricate(:admin) } let(:user) { Fabricate(:user) } let(:user1) { Fabricate(:user) } let(:user2) { Fabricate(:user) } - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" before do add_to_assign_allowed_group(user) @@ -55,7 +52,7 @@ add_to_assign_allowed_group(admin) end - it 'gives false in can_show_assigned_tab? when all users are not in assigned_allowed_group' do + it "gives false in can_show_assigned_tab? when all users are not in assigned_allowed_group" do group.add(user) group.add(user1) group.add(user2) @@ -63,7 +60,7 @@ expect(group.can_show_assigned_tab?).to eq(false) end - it 'gives true in can_show_assigned_tab? when all users are in assigned_allowed_group' do + it "gives true in can_show_assigned_tab? when all users are in assigned_allowed_group" do group.add(user) group.add(user1) diff --git a/spec/models/reviewable_spec.rb b/spec/models/reviewable_spec.rb index 7452c97d..3c944a52 100644 --- a/spec/models/reviewable_spec.rb +++ b/spec/models/reviewable_spec.rb @@ -8,14 +8,24 @@ fab!(:reviewable1) { Fabricate(:reviewable_flagged_post, target: post1) } fab!(:reviewable2) { Fabricate(:reviewable_flagged_post, target: post2) } - before do - SiteSetting.assign_enabled = true - end + before { SiteSetting.assign_enabled = true } it "can filter by assigned_to" do - Assignment.create!(target: post1, topic_id: post1.topic.id, assigned_by_user: user, assigned_to: user) - Assignment.create!(target: post2, topic_id: post2.topic.id, assigned_by_user: user, assigned_to: admin) + Assignment.create!( + target: post1, + topic_id: post1.topic.id, + assigned_by_user: user, + assigned_to: user, + ) + Assignment.create!( + target: post2, + topic_id: post2.topic.id, + assigned_by_user: user, + assigned_to: admin, + ) - expect(Reviewable.list_for(admin, additional_filters: { assigned_to: user.username })).to eq([reviewable1]) + expect(Reviewable.list_for(admin, additional_filters: { assigned_to: user.username })).to eq( + [reviewable1], + ) end end diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index 647ec1f5..9f00deff 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -8,19 +8,29 @@ let(:group) { Fabricate(:group) } let(:topic) { Fabricate(:topic) } - before do - SiteSetting.assign_enabled = true - end + before { SiteSetting.assign_enabled = true } describe "#assigned_to" do it "correctly points to a user" do - Assignment.create!(target_id: topic.id, target_type: "Topic", topic_id: topic.id, assigned_by_user: user1, assigned_to: user2) + Assignment.create!( + target_id: topic.id, + target_type: "Topic", + topic_id: topic.id, + assigned_by_user: user1, + assigned_to: user2, + ) expect(topic.reload.assigned_to).to eq(user2) end it "correctly points to a group" do - Assignment.create!(target_id: topic.id, target_type: "Topic", topic_id: topic.id, assigned_by_user: user1, assigned_to: group) + Assignment.create!( + target_id: topic.id, + target_type: "Topic", + topic_id: topic.id, + assigned_by_user: user1, + assigned_to: group, + ) expect(topic.reload.assigned_to).to eq(group) end diff --git a/spec/models/user_custom_field_spec.rb b/spec/models/user_custom_field_spec.rb index c43ed347..61a6834b 100644 --- a/spec/models/user_custom_field_spec.rb +++ b/spec/models/user_custom_field_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" RSpec.describe UserCustomField do before { SiteSetting.assign_enabled = true } @@ -8,12 +8,12 @@ let(:field_name) { PendingAssignsReminder::REMINDERS_FREQUENCY } let(:new_field) { UserCustomField.new(name: field_name, user_id: 1) } - it 'coerces the value to be an integer' do - new_field.value = 'DROP TABLE USERS;' + it "coerces the value to be an integer" do + new_field.value = "DROP TABLE USERS;" new_field.save! saved_field = new_field.reload - expect(saved_field.value).to eq('0') + expect(saved_field.value).to eq("0") end end diff --git a/spec/plugin_spec.rb b/spec/plugin_spec.rb index d2fc6dcd..8aa481b5 100644 --- a/spec/plugin_spec.rb +++ b/spec/plugin_spec.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" -describe 'plugin' do +describe "plugin" do before { SiteSetting.assign_enabled = true } - describe 'events' do - describe 'on user_removed_from_group' do + describe "events" do + describe "on user_removed_from_group" do before do @topic = Fabricate(:post).topic @user = Fabricate(:user) @@ -14,7 +14,7 @@ @group_a.add(@user) end - it 'unassigns the user' do + it "unassigns the user" do SiteSetting.assign_allowed_on_groups = @group_a.id.to_s Assigner.new(@topic, Discourse.system_user).assign(@user) @@ -26,7 +26,7 @@ it "doesn't unassign the user if it still has access through another group" do @group_b = Fabricate(:group) @group_b.add(@user) - SiteSetting.assign_allowed_on_groups = [@group_a.id.to_s, @group_b.id.to_s].join('|') + SiteSetting.assign_allowed_on_groups = [@group_a.id.to_s, @group_b.id.to_s].join("|") Assigner.new(@topic, Discourse.system_user).assign(@user) @group_a.remove(@user) diff --git a/spec/requests/assign_controller_spec.rb b/spec/requests/assign_controller_spec.rb index 432b88b2..15b3c274 100644 --- a/spec/requests/assign_controller_spec.rb +++ b/spec/requests/assign_controller_spec.rb @@ -1,45 +1,55 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" RSpec.describe DiscourseAssign::AssignController do before { SiteSetting.assign_enabled = true } - fab!(:default_allowed_group) { Group.find_by(name: 'staff') } - let(:user) { Fabricate(:admin, groups: [default_allowed_group], name: 'Robin Ward', username: 'eviltrout') } + fab!(:default_allowed_group) { Group.find_by(name: "staff") } + let(:user) do + Fabricate(:admin, groups: [default_allowed_group], name: "Robin Ward", username: "eviltrout") + end fab!(:post) { Fabricate(:post) } - fab!(:user2) { Fabricate(:active_user, name: 'David Tylor', username: 'david', groups: [default_allowed_group]) } + fab!(:user2) do + Fabricate(:active_user, name: "David Tylor", username: "david", groups: [default_allowed_group]) + end let(:nonadmin) { Fabricate(:user, groups: [default_allowed_group]) } fab!(:normal_user) { Fabricate(:user) } fab!(:normal_admin) { Fabricate(:admin) } - context 'only allow users from allowed groups' do + context "only allow users from allowed groups" do before { sign_in(user2) } - it 'filters requests where current_user is not member of an allowed group' do - SiteSetting.assign_allowed_on_groups = '' + it "filters requests where current_user is not member of an allowed group" do + SiteSetting.assign_allowed_on_groups = "" - put '/assign/assign.json', params: { - target_id: post.topic_id, target_type: 'Topic', username: user2.username - } + put "/assign/assign.json", + params: { + target_id: post.topic_id, + target_type: "Topic", + username: user2.username, + } expect(response.status).to eq(403) end - it 'filters requests where assigne group is not allowed' do - put '/assign/assign.json', params: { - target_id: post.topic_id, target_type: 'Topic', group_name: default_allowed_group.name - } + it "filters requests where assigne group is not allowed" do + put "/assign/assign.json", + params: { + target_id: post.topic_id, + target_type: "Topic", + group_name: default_allowed_group.name, + } expect(response.status).to eq(400) end - describe '#suggestions' do + describe "#suggestions" do before { sign_in(user) } - it 'includes users in allowed groups' do - allowed_group = Group.find_by(name: 'everyone') + it "includes users in allowed groups" do + allowed_group = Group.find_by(name: "everyone") allowed_group.add(user2) defaults = "#{default_allowed_group.id}|#{allowed_group.id}" @@ -47,25 +57,25 @@ SiteSetting.assign_allowed_on_groups = defaults Assigner.new(post.topic, user).assign(user2) - get '/assign/suggestions.json' - suggestions = JSON.parse(response.body)['suggestions'].map { |u| u['username'] } + get "/assign/suggestions.json" + suggestions = JSON.parse(response.body)["suggestions"].map { |u| u["username"] } expect(suggestions).to contain_exactly(user2.username, user.username) end - it 'does not include users from disallowed groups' do - allowed_group = Group.find_by(name: 'everyone') + it "does not include users from disallowed groups" do + allowed_group = Group.find_by(name: "everyone") allowed_group.add(user2) SiteSetting.assign_allowed_on_groups = default_allowed_group.id.to_s Assigner.new(post.topic, user).assign(user2) - get '/assign/suggestions.json' - suggestions = JSON.parse(response.body)['suggestions'].map { |u| u['username'] }.sort + get "/assign/suggestions.json" + suggestions = JSON.parse(response.body)["suggestions"].map { |u| u["username"] }.sort - expect(suggestions).to eq(['david', 'eviltrout']) + expect(suggestions).to eq(%w[david eviltrout]) end - it 'does include only visible assign_allowed_on_groups' do + it "does include only visible assign_allowed_on_groups" do sign_in(nonadmin) # Need to use nonadmin to test. Admins can see all groups visible_group = Fabricate(:group, visibility_level: Group.visibility_levels[:members]) @@ -74,8 +84,8 @@ SiteSetting.assign_allowed_on_groups = "#{visible_group.id}|#{invisible_group.id}" - get '/assign/suggestions.json' - assign_allowed_on_groups = JSON.parse(response.body)['assign_allowed_on_groups'] + get "/assign/suggestions.json" + assign_allowed_on_groups = JSON.parse(response.body)["assign_allowed_on_groups"] expect(assign_allowed_on_groups).to contain_exactly(visible_group.name) end @@ -88,68 +98,86 @@ sign_in(user) end - it 'excludes other users from the suggestions when they already reached the max assigns limit' do + it "excludes other users from the suggestions when they already reached the max assigns limit" do another_admin = Fabricate(:admin, groups: [default_allowed_group]) Assigner.new(post.topic, user).assign(another_admin) - get '/assign/suggestions.json' - suggestions = JSON.parse(response.body)['suggestions'].map { |u| u['username'] } + get "/assign/suggestions.json" + suggestions = JSON.parse(response.body)["suggestions"].map { |u| u["username"] } expect(suggestions).to contain_exactly(user.username) end end - describe '#assign' do - include_context 'A group that is allowed to assign' + describe "#assign" do + include_context "A group that is allowed to assign" before do sign_in(user) add_to_assign_allowed_group(user2) end - it 'assigns topic to a user' do - put '/assign/assign.json', params: { - target_id: post.topic_id, target_type: 'Topic', username: user2.username - } + it "assigns topic to a user" do + put "/assign/assign.json", + params: { + target_id: post.topic_id, + target_type: "Topic", + username: user2.username, + } expect(response.status).to eq(200) expect(post.topic.reload.assignment.assigned_to_id).to eq(user2.id) end - it 'assigns topic with note to a user' do - put '/assign/assign.json', params: { - target_id: post.topic_id, target_type: 'Topic', username: user2.username, note: "do dis pls" - } + it "assigns topic with note to a user" do + put "/assign/assign.json", + params: { + target_id: post.topic_id, + target_type: "Topic", + username: user2.username, + note: "do dis pls", + } expect(post.topic.reload.assignment.note).to eq("do dis pls") end - it 'assigns topic to a group' do - put '/assign/assign.json', params: { - target_id: post.topic_id, target_type: 'Topic', group_name: assign_allowed_group.name - } + it "assigns topic to a group" do + put "/assign/assign.json", + params: { + target_id: post.topic_id, + target_type: "Topic", + group_name: assign_allowed_group.name, + } expect(response.status).to eq(200) expect(post.topic.reload.assignment.assigned_to).to eq(assign_allowed_group) end - it 'fails to assign topic to the user if its already assigned to the same user' do - put '/assign/assign.json', params: { - target_id: post.topic_id, target_type: 'Topic', username: user2.username - } + it "fails to assign topic to the user if its already assigned to the same user" do + put "/assign/assign.json", + params: { + target_id: post.topic_id, + target_type: "Topic", + username: user2.username, + } expect(response.status).to eq(200) expect(post.topic.reload.assignment.assigned_to_id).to eq(user2.id) - put '/assign/assign.json', params: { - target_id: post.topic_id, target_type: 'Topic', username: user2.username - } + put "/assign/assign.json", + params: { + target_id: post.topic_id, + target_type: "Topic", + username: user2.username, + } expect(response.status).to eq(400) - expect(JSON.parse(response.body)['error']).to eq(I18n.t('discourse_assign.already_assigned', username: user2.username)) + expect(JSON.parse(response.body)["error"]).to eq( + I18n.t("discourse_assign.already_assigned", username: user2.username), + ) end - it 'fails to assign topic to the user if they already reached the max assigns limit' do + it "fails to assign topic to the user if they already reached the max assigns limit" do another_user = Fabricate(:user) add_to_assign_allowed_group(another_user) another_post = Fabricate(:post) @@ -157,45 +185,64 @@ SiteSetting.max_assigned_topics = max_assigns Assigner.new(post.topic, user).assign(another_user) - put '/assign/assign.json', params: { - target_id: another_post.topic_id, target_type: 'Topic', username: another_user.username - } + put "/assign/assign.json", + params: { + target_id: another_post.topic_id, + target_type: "Topic", + username: another_user.username, + } expect(response.status).to eq(400) - expect(JSON.parse(response.body)['error']).to eq( - I18n.t('discourse_assign.too_many_assigns', username: another_user.username, max: max_assigns) + expect(JSON.parse(response.body)["error"]).to eq( + I18n.t( + "discourse_assign.too_many_assigns", + username: another_user.username, + max: max_assigns, + ), ) end - it 'fails with a specific error message if the topic is a PM and the assignee can not see it' do + it "fails with a specific error message if the topic is a PM and the assignee can not see it" do pm = Fabricate(:private_message_post, user: user).topic another_user = Fabricate(:user) add_to_assign_allowed_group(another_user) - put '/assign/assign.json', params: { - target_id: pm.id, target_type: 'Topic', username: another_user.username - } - - expect(response.parsed_body['error']).to eq( - I18n.t('discourse_assign.forbidden_assignee_not_pm_participant', username: another_user.username) + put "/assign/assign.json", + params: { + target_id: pm.id, + target_type: "Topic", + username: another_user.username, + } + + expect(response.parsed_body["error"]).to eq( + I18n.t( + "discourse_assign.forbidden_assignee_not_pm_participant", + username: another_user.username, + ), ) end - it 'fails with a specific error message if the topic is not a PM and the assignee can not see it' do + it "fails with a specific error message if the topic is not a PM and the assignee can not see it" do topic = Fabricate(:topic, category: Fabricate(:private_category, group: Fabricate(:group))) another_user = Fabricate(:user) add_to_assign_allowed_group(another_user) - put '/assign/assign.json', params: { - target_id: topic.id, target_type: "Topic", username: another_user.username - } - - expect(response.parsed_body['error']).to eq( - I18n.t('discourse_assign.forbidden_assignee_cant_see_topic', username: another_user.username) + put "/assign/assign.json", + params: { + target_id: topic.id, + target_type: "Topic", + username: another_user.username, + } + + expect(response.parsed_body["error"]).to eq( + I18n.t( + "discourse_assign.forbidden_assignee_cant_see_topic", + username: another_user.username, + ), ) end end - describe '#assigned' do - include_context 'A group that is allowed to assign' + describe "#assigned" do + include_context "A group that is allowed to assign" fab!(:post1) { Fabricate(:post) } fab!(:post2) { Fabricate(:post) } @@ -216,40 +263,44 @@ sign_in(user) end - it 'lists topics ordered by user' do - get '/assign/assigned.json' - expect(JSON.parse(response.body)['topics'].map { |t| t['id'] }).to match_array([post2.topic_id, post1.topic_id, post3.topic_id]) + it "lists topics ordered by user" do + get "/assign/assigned.json" + expect(JSON.parse(response.body)["topics"].map { |t| t["id"] }).to match_array( + [post2.topic_id, post1.topic_id, post3.topic_id], + ) - get '/assign/assigned.json', params: { limit: 2 } - expect(JSON.parse(response.body)['topics'].map { |t| t['id'] }).to match_array([post3.topic_id, post2.topic_id]) + get "/assign/assigned.json", params: { limit: 2 } + expect(JSON.parse(response.body)["topics"].map { |t| t["id"] }).to match_array( + [post3.topic_id, post2.topic_id], + ) - get '/assign/assigned.json', params: { offset: 2 } - expect(JSON.parse(response.body)['topics'].map { |t| t['id'] }).to match_array([post1.topic_id]) + get "/assign/assigned.json", params: { offset: 2 } + expect(JSON.parse(response.body)["topics"].map { |t| t["id"] }).to match_array( + [post1.topic_id], + ) end context "with custom allowed groups" do - let(:custom_allowed_group) { Fabricate(:group, name: 'mygroup') } + let(:custom_allowed_group) { Fabricate(:group, name: "mygroup") } let(:other_user) { Fabricate(:user, groups: [custom_allowed_group]) } - before do - SiteSetting.assign_allowed_on_groups += "|#{custom_allowed_group.id}" - end + before { SiteSetting.assign_allowed_on_groups += "|#{custom_allowed_group.id}" } - it 'works for admins' do - get '/assign/assigned.json' + it "works for admins" do + get "/assign/assigned.json" expect(response.status).to eq(200) end - it 'does not work for other groups' do + it "does not work for other groups" do sign_in(other_user) - get '/assign/assigned.json' + get "/assign/assigned.json" expect(response.status).to eq(403) end end end - describe '#group_members' do - include_context 'A group that is allowed to assign' + describe "#group_members" do + include_context "A group that is allowed to assign" fab!(:post1) { Fabricate(:post) } fab!(:post2) { Fabricate(:post) } @@ -264,12 +315,14 @@ Assigner.new(post3.topic, user).assign(user) end - it 'list members order by assignments_count' do + it "list members order by assignments_count" do sign_in(user) get "/assign/members/#{get_assigned_allowed_group_name}.json" expect(response.status).to eq(200) - expect(JSON.parse(response.body)['members'].map { |m| m['id'] }).to match_array([user.id, user2.id]) + expect(JSON.parse(response.body)["members"].map { |m| m["id"] }).to match_array( + [user.id, user2.id], + ) end it "doesn't include members with no assignments" do @@ -278,23 +331,27 @@ get "/assign/members/#{get_assigned_allowed_group_name}.json" expect(response.status).to eq(200) - expect(JSON.parse(response.body)['members'].map { |m| m['id'] }).to match_array([user.id, user2.id]) + expect(JSON.parse(response.body)["members"].map { |m| m["id"] }).to match_array( + [user.id, user2.id], + ) end it "returns members as according to filter" do sign_in(user) - get "/assign/members/#{get_assigned_allowed_group_name}.json", params: { filter: 'a' } + get "/assign/members/#{get_assigned_allowed_group_name}.json", params: { filter: "a" } expect(response.status).to eq(200) - expect(JSON.parse(response.body)['members'].map { |m| m['id'] }).to match_array([user.id, user2.id]) + expect(JSON.parse(response.body)["members"].map { |m| m["id"] }).to match_array( + [user.id, user2.id], + ) - get "/assign/members/#{get_assigned_allowed_group_name}.json", params: { filter: 'david' } + get "/assign/members/#{get_assigned_allowed_group_name}.json", params: { filter: "david" } expect(response.status).to eq(200) - expect(JSON.parse(response.body)['members'].map { |m| m['id'] }).to match_array([user2.id]) + expect(JSON.parse(response.body)["members"].map { |m| m["id"] }).to match_array([user2.id]) - get "/assign/members/#{get_assigned_allowed_group_name}.json", params: { filter: 'Tylor' } + get "/assign/members/#{get_assigned_allowed_group_name}.json", params: { filter: "Tylor" } expect(response.status).to eq(200) - expect(JSON.parse(response.body)['members'].map { |m| m['id'] }).to match_array([user2.id]) + expect(JSON.parse(response.body)["members"].map { |m| m["id"] }).to match_array([user2.id]) end it "404 error to non-group-members" do diff --git a/spec/requests/list_controller_spec.rb b/spec/requests/list_controller_spec.rb index d5f22a50..365bdc58 100644 --- a/spec/requests/list_controller_spec.rb +++ b/spec/requests/list_controller_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" describe ListController do before { SiteSetting.assign_enabled = true } @@ -11,12 +11,12 @@ let(:admin) { Fabricate(:admin) } let(:post) { Fabricate(:post) } - describe 'only allow users from allowed groups' do - include_context 'A group that is allowed to assign' + describe "only allow users from allowed groups" do + include_context "A group that is allowed to assign" - it 'filters requests where current_user is not member of an allowed group' do + it "filters requests where current_user is not member of an allowed group" do sign_in(user) - SiteSetting.assign_allowed_on_groups = '' + SiteSetting.assign_allowed_on_groups = "" get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json" expect(response.status).to eq(403) @@ -25,7 +25,7 @@ expect(response.status).to eq(403) end - it 'as an anon user' do + it "as an anon user" do get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json" expect(response.status).to eq(403) @@ -33,7 +33,7 @@ expect(response.status).to eq(403) end - it 'as an admin user' do + it "as an admin user" do sign_in(admin) get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json" expect(response.status).to eq(200) @@ -43,8 +43,8 @@ end end - context '#group_topics_assigned' do - include_context 'A group that is allowed to assign' + context "#group_topics_assigned" do + include_context "A group that is allowed to assign" fab!(:post1) { Fabricate(:post) } fab!(:post2) { Fabricate(:post) } @@ -62,30 +62,30 @@ sign_in(user) end - it 'returns user-assigned-topics-list of users in the assigned_allowed_group and doesnt include deleted topic' do + it "returns user-assigned-topics-list of users in the assigned_allowed_group and doesnt include deleted topic" do get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['assigned_to_user']['id'] }).to match_array([user.id]) + expect( + JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["assigned_to_user"]["id"] }, + ).to match_array([user.id]) end - it 'returns user-assigned-topics-list of users in the assigned_allowed_group and doesnt include inactive topics' do + it "returns user-assigned-topics-list of users in the assigned_allowed_group and doesnt include inactive topics" do Assignment.where(assigned_to: user, target: topic1).update_all(active: false) get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json" - expect(response.parsed_body['topic_list']['topics']).to be_empty + expect(response.parsed_body["topic_list"]["topics"]).to be_empty end - it 'returns empty user-assigned-topics-list for users not in the assigned_allowed_group' do + it "returns empty user-assigned-topics-list for users not in the assigned_allowed_group" do ids = [] get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json" - JSON.parse(response.body)['topic_list']['topics'].each do |t| - if t['assigned_to_user']['id'] == user2.id - ids.push(t['assigned_to_user']['id']) - end + JSON.parse(response.body)["topic_list"]["topics"].each do |t| + ids.push(t["assigned_to_user"]["id"]) if t["assigned_to_user"]["id"] == user2.id end expect(ids).to be_empty end - it 'doesnt returns deleted topics' do + it "doesnt returns deleted topics" do sign_in(admin) Assigner.new(topic, user).assign(user) @@ -97,18 +97,16 @@ id = 0 get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json" - JSON.parse(response.body)['topic_list']['topics'].each do |t| - if t['id'] == topic.id - id = t.id - end + JSON.parse(response.body)["topic_list"]["topics"].each do |t| + id = t.id if t["id"] == topic.id end expect(id).to eq(0) end end - context '#sorting messages_assigned and group_topics_assigned' do - include_context 'A group that is allowed to assign' + context "#sorting messages_assigned and group_topics_assigned" do + include_context "A group that is allowed to assign" fab!(:post1) { Fabricate(:post) } fab!(:post2) { Fabricate(:post) } @@ -128,7 +126,7 @@ sign_in(user) end - it 'group_topics_assigned returns sorted topicsList' do + it "group_topics_assigned returns sorted topicsList" do topic1.bumped_at = Time.now topic2.bumped_at = 1.day.ago topic3.bumped_at = 3.day.ago @@ -146,25 +144,37 @@ topic3.save! get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json?order=posts" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic2.id, topic1.id, topic3.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic2.id, topic1.id, topic3.id], + ) get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json?order=views" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic3.id, topic1.id, topic2.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic3.id, topic1.id, topic2.id], + ) get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json?order=activity" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic3.id, topic2.id, topic1.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic3.id, topic2.id, topic1.id], + ) get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json?order=posts&ascending=true" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic3.id, topic1.id, topic2.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic3.id, topic1.id, topic2.id], + ) get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json?order=views&ascending=true" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic2.id, topic1.id, topic3.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic2.id, topic1.id, topic3.id], + ) get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json?order=activity&ascending=true" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([ topic1.id, topic2.id, topic3.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic1.id, topic2.id, topic3.id], + ) end - it 'messages_assigned returns sorted topicsList' do + it "messages_assigned returns sorted topicsList" do topic1.bumped_at = Time.now topic3.bumped_at = 3.day.ago @@ -178,27 +188,39 @@ topic3.reload get "/topics/messages-assigned/#{user.username}.json?order=posts" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic1.id, topic3.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic1.id, topic3.id], + ) get "/topics/messages-assigned/#{user.username}.json?order=views" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic3.id, topic1.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic3.id, topic1.id], + ) get "/topics/messages-assigned/#{user.username}.json?order=activity" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic3.id, topic1.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic3.id, topic1.id], + ) get "/topics/messages-assigned/#{user.username}.json?order=posts&ascending=true" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic3.id, topic1.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic3.id, topic1.id], + ) get "/topics/messages-assigned/#{user.username}.json?order=views&ascending=true" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic1.id, topic3.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic1.id, topic3.id], + ) get "/topics/messages-assigned/#{user.username}.json?order=activity&ascending=true" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic1.id, topic3.id]) + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic1.id, topic3.id], + ) end end - context 'filtering of topics as per parameter' do - include_context 'A group that is allowed to assign' + context "filtering of topics as per parameter" do + include_context "A group that is allowed to assign" fab!(:post1) { Fabricate(:post) } fab!(:post2) { Fabricate(:post) } @@ -222,44 +244,66 @@ after { SearchIndexer.disable } - it 'returns topics as per filter for #group_topics_assigned' do - topic1.title = 'QUnit testing is love' - topic2.title = 'RSpec testing is too fun' - topic3.title = 'Testing is main part of programming' + it "returns topics as per filter for #group_topics_assigned" do + topic1.title = "QUnit testing is love" + topic2.title = "RSpec testing is too fun" + topic3.title = "Testing is main part of programming" topic1.save! topic2.save! topic3.save! - get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json", params: { search: 'Testing' } - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic1.id, topic2.id, topic3.id]) - - get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json", params: { search: 'RSpec' } - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic2.id]) - - get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json", params: { search: 'love' } - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic1.id]) + get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json", + params: { + search: "Testing", + } + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic1.id, topic2.id, topic3.id], + ) + + get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json", + params: { + search: "RSpec", + } + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic2.id], + ) + + get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json", + params: { + search: "love", + } + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic1.id], + ) end - it 'returns topics as per filter for #group_topics_assigned' do - topic1.title = 'QUnit testing is love' - topic2.title = 'RSpec testing is too fun' - topic3.title = 'Testing is main part of programming' + it "returns topics as per filter for #group_topics_assigned" do + topic1.title = "QUnit testing is love" + topic2.title = "RSpec testing is too fun" + topic3.title = "Testing is main part of programming" topic1.save! topic2.save! topic3.save! - get "/topics/messages-assigned/#{user.username}.json", params: { search: 'Testing' } - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic1.id, topic3.id]) - - get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json", params: { search: 'love' } - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['id'] }).to match_array([topic1.id]) + get "/topics/messages-assigned/#{user.username}.json", params: { search: "Testing" } + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic1.id, topic3.id], + ) + + get "/topics/group-topics-assigned/#{get_assigned_allowed_group_name}.json", + params: { + search: "love", + } + expect(JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["id"] }).to match_array( + [topic1.id], + ) end end - context '#messages_assigned' do - include_context 'A group that is allowed to assign' + context "#messages_assigned" do + include_context "A group that is allowed to assign" fab!(:post1) { Fabricate(:post) } fab!(:post2) { Fabricate(:post) } @@ -273,14 +317,16 @@ sign_in(user) end - it 'returns user-assigned-topics-list of given user' do + it "returns user-assigned-topics-list of given user" do get "/topics/messages-assigned/#{user.username_lower}.json" - expect(JSON.parse(response.body)['topic_list']['topics'].map { |t| t['assigned_to_user']['id'] }).to match_array([user.id]) + expect( + JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["assigned_to_user"]["id"] }, + ).to match_array([user.id]) end - it 'returns empty user-assigned-topics-list for given user not in the assigned_allowed_group' do + it "returns empty user-assigned-topics-list for given user not in the assigned_allowed_group" do get "/topics/messages-assigned/#{user2.username_lower}.json" - expect(JSON.parse(response.body)['topic_list']['topics']).to be_empty + expect(JSON.parse(response.body)["topic_list"]["topics"]).to be_empty end end end diff --git a/spec/serializers/flagged_topic_serializer_spec.rb b/spec/serializers/flagged_topic_serializer_spec.rb index 8fde18bf..ff46c4e8 100644 --- a/spec/serializers/flagged_topic_serializer_spec.rb +++ b/spec/serializers/flagged_topic_serializer_spec.rb @@ -27,11 +27,8 @@ context "when there is a user assignment" do let(:topic) do - topic = Fabricate(:topic, - topic_allowed_users: [ - Fabricate.build(:topic_allowed_user, user: user) - ] - ) + topic = + Fabricate(:topic, topic_allowed_users: [Fabricate.build(:topic_allowed_user, user: user)]) topic.posts << Fabricate(:post) @@ -42,24 +39,28 @@ it "includes the assigned_to_user attribute" do json = FlaggedTopicSerializer.new(topic, scope: guardian).as_json - expect(json[:flagged_topic][:assigned_to_user]).to match({ - username: user.username, - name: user.name, - assign_icon: "user-plus", - avatar_template: /letter_avatar_proxy.*/, - assign_path: "/u/#{user.username}/activity/assigned", - }) + expect(json[:flagged_topic][:assigned_to_user]).to match( + { + username: user.username, + name: user.name, + assign_icon: "user-plus", + avatar_template: /letter_avatar_proxy.*/, + assign_path: "/u/#{user.username}/activity/assigned", + }, + ) expect(json[:flagged_topic]).to_not have_key(:assigned_to_group) end end context "when there is a group assignment" do let(:topic) do - topic = Fabricate(:topic, - topic_allowed_groups: [ - Fabricate.build(:topic_allowed_group, group: assign_allowed_group) - ] - ) + topic = + Fabricate( + :topic, + topic_allowed_groups: [ + Fabricate.build(:topic_allowed_group, group: assign_allowed_group), + ], + ) topic.posts << Fabricate(:post) @@ -70,15 +71,17 @@ it "includes the assigned_to_group attribute" do json = FlaggedTopicSerializer.new(topic, scope: guardian).as_json - expect(json[:flagged_topic][:assigned_to_group]).to match({ - name: assign_allowed_group.name, - flair_bg_color: assign_allowed_group.flair_bg_color, - flair_color: assign_allowed_group.flair_color, - flair_icon: assign_allowed_group.flair_icon, - flair_upload_id: assign_allowed_group.flair_upload_id, - assign_icon: "group-plus", - assign_path: "/g/#{assign_allowed_group.name}/assigned/everyone", - }) + expect(json[:flagged_topic][:assigned_to_group]).to match( + { + name: assign_allowed_group.name, + flair_bg_color: assign_allowed_group.flair_bg_color, + flair_color: assign_allowed_group.flair_color, + flair_icon: assign_allowed_group.flair_icon, + flair_upload_id: assign_allowed_group.flair_upload_id, + assign_icon: "group-plus", + assign_path: "/g/#{assign_allowed_group.name}/assigned/everyone", + }, + ) expect(json[:flagged_topic]).to_not have_key(:assigned_to_user) end end diff --git a/spec/serializers/group_show_serializer_spec.rb b/spec/serializers/group_show_serializer_spec.rb index d7c0f09e..f8153232 100644 --- a/spec/serializers/group_show_serializer_spec.rb +++ b/spec/serializers/group_show_serializer_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" RSpec.describe GroupShowSerializer do fab!(:user) { Fabricate(:user) } diff --git a/spec/serializers/post_serializer_spec.rb b/spec/serializers/post_serializer_spec.rb index a68875f1..a50a67d0 100644 --- a/spec/serializers/post_serializer_spec.rb +++ b/spec/serializers/post_serializer_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" describe PostSerializer do fab!(:user) { Fabricate(:user) } @@ -9,7 +9,7 @@ fab!(:post) { Fabricate(:post, topic: topic) } let(:guardian) { Guardian.new(user) } - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" before do SiteSetting.assign_enabled = true diff --git a/spec/serializers/suggested_topic_serializer_spec.rb b/spec/serializers/suggested_topic_serializer_spec.rb index cd560acd..e43d2983 100644 --- a/spec/serializers/suggested_topic_serializer_spec.rb +++ b/spec/serializers/suggested_topic_serializer_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" RSpec.describe SuggestedTopicSerializer do fab!(:user) { Fabricate(:user) } diff --git a/spec/serializers/topic_list_serializer_spec.rb b/spec/serializers/topic_list_serializer_spec.rb index 650af81b..c2c946c3 100644 --- a/spec/serializers/topic_list_serializer_spec.rb +++ b/spec/serializers/topic_list_serializer_spec.rb @@ -1,27 +1,27 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" RSpec.describe TopicListSerializer do fab!(:user) { Fabricate(:user) } let(:private_message_topic) do - topic = Fabricate(:private_message_topic, - topic_allowed_users: [ - Fabricate.build(:topic_allowed_user, user: user) - ] - ) + topic = + Fabricate( + :private_message_topic, + topic_allowed_users: [Fabricate.build(:topic_allowed_user, user: user)], + ) topic.posts << Fabricate(:post) topic end let(:assigned_topic) do - topic = Fabricate(:private_message_topic, - topic_allowed_users: [ - Fabricate.build(:topic_allowed_user, user: user) - ] - ) + topic = + Fabricate( + :private_message_topic, + topic_allowed_users: [Fabricate.build(:topic_allowed_user, user: user)], + ) topic.posts << Fabricate(:post) @@ -32,77 +32,67 @@ let(:guardian) { Guardian.new(user) } let(:serializer) { TopicListSerializer.new(topic_list, scope: guardian) } - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" before do SiteSetting.assign_enabled = true add_to_assign_allowed_group(user) end - describe '#assigned_messages_count' do + describe "#assigned_messages_count" do let(:topic_list) do TopicQuery.new(user, assigned: user.username).list_private_messages_assigned(user) end - before do - assigned_topic - end + before { assigned_topic } - it 'should include right attribute' do - expect(serializer.as_json[:topic_list][:assigned_messages_count]) - .to eq(1) + it "should include right attribute" do + expect(serializer.as_json[:topic_list][:assigned_messages_count]).to eq(1) end - describe 'when not viewing assigned list' do - let(:topic_list) do - TopicQuery.new(user).list_private_messages_assigned(user) - end + describe "when not viewing assigned list" do + let(:topic_list) { TopicQuery.new(user).list_private_messages_assigned(user) } - describe 'as an admin user' do + describe "as an admin user" do let(:guardian) { Guardian.new(Fabricate(:admin)) } - it 'should not include the attribute' do - expect(serializer.as_json[:topic_list][:assigned_messages_count]) - .to eq(nil) + it "should not include the attribute" do + expect(serializer.as_json[:topic_list][:assigned_messages_count]).to eq(nil) end end - describe 'as an anon user' do + describe "as an anon user" do let(:guardian) { Guardian.new } - it 'should not include the attribute' do - expect(serializer.as_json[:topic_list][:assigned_messages_count]) - .to eq(nil) + it "should not include the attribute" do + expect(serializer.as_json[:topic_list][:assigned_messages_count]).to eq(nil) end end end - describe 'viewing another user' do - describe 'as an anon user' do + describe "viewing another user" do + describe "as an anon user" do let(:guardian) { Guardian.new } - it 'should not include the attribute' do - expect(serializer.as_json[:topic_list][:assigned_messages_count]) - .to eq(nil) + it "should not include the attribute" do + expect(serializer.as_json[:topic_list][:assigned_messages_count]).to eq(nil) end end - describe 'as a staff' do - let(:admin) { Fabricate(:admin, groups: [Group.find_by(name: 'staff')]) } + describe "as a staff" do + let(:admin) { Fabricate(:admin, groups: [Group.find_by(name: "staff")]) } let(:guardian) { Guardian.new(admin) } - it 'should include the right attribute' do - expect(serializer.as_json[:topic_list][:assigned_messages_count]) - .to eq(1) + it "should include the right attribute" do + expect(serializer.as_json[:topic_list][:assigned_messages_count]).to eq(1) end end - describe 'as a normal user' do + describe "as a normal user" do let(:guardian) { Guardian.new(Fabricate(:user)) } - it 'should not include the attribute' do - expect(serializer.as_json[:topic_list][:assigned_messages_count]) - .to eq(nil) + it "should not include the attribute" do + expect(serializer.as_json[:topic_list][:assigned_messages_count]).to eq(nil) end end end diff --git a/spec/serializers/topic_view_serializer_spec.rb b/spec/serializers/topic_view_serializer_spec.rb index 23a25d8c..f7f7559a 100644 --- a/spec/serializers/topic_view_serializer_spec.rb +++ b/spec/serializers/topic_view_serializer_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" RSpec.describe TopicViewSerializer do fab!(:user) { Fabricate(:user) } @@ -9,7 +9,7 @@ fab!(:post) { Fabricate(:post, topic: topic) } let(:guardian) { Guardian.new(user) } - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" before do SiteSetting.assign_enabled = true @@ -26,7 +26,9 @@ it "includes assigned group in serializer" do Assigner.new(topic, user).assign(assign_allowed_group) serializer = TopicViewSerializer.new(TopicView.new(topic), scope: guardian) - expect(serializer.as_json[:topic_view][:assigned_to_group][:name]).to eq(assign_allowed_group.name) + expect(serializer.as_json[:topic_view][:assigned_to_group][:name]).to eq( + assign_allowed_group.name, + ) expect(serializer.as_json[:topic_view][:assigned_to_user]).to be nil end @@ -39,6 +41,8 @@ it "includes indirectly_assigned_to notes in serializer" do Assigner.new(post, user).assign(user, note: "note me down") serializer = TopicViewSerializer.new(TopicView.new(topic), scope: guardian) - expect(serializer.as_json[:topic_view][:indirectly_assigned_to][post.id][:assignment_note]).to eq("note me down") + expect( + serializer.as_json[:topic_view][:indirectly_assigned_to][post.id][:assignment_note], + ).to eq("note me down") end end diff --git a/spec/serializers/user_bookmark_base_serializer_spec.rb b/spec/serializers/user_bookmark_base_serializer_spec.rb index a28a23c4..d638e59a 100644 --- a/spec/serializers/user_bookmark_base_serializer_spec.rb +++ b/spec/serializers/user_bookmark_base_serializer_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -require 'rails_helper' -require_relative '../support/assign_allowed_group' +require "rails_helper" +require_relative "../support/assign_allowed_group" describe UserBookmarkBaseSerializer do - include_context 'A group that is allowed to assign' + include_context "A group that is allowed to assign" before do SiteSetting.assign_enabled = true diff --git a/spec/support/assign_allowed_group.rb b/spec/support/assign_allowed_group.rb index 2855278a..73380888 100644 --- a/spec/support/assign_allowed_group.rb +++ b/spec/support/assign_allowed_group.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true -shared_context 'A group that is allowed to assign' do - fab!(:assign_allowed_group) { Fabricate(:group, assignable_level: Group::ALIAS_LEVELS[:everyone]) } - - before do - SiteSetting.assign_allowed_on_groups += "|#{assign_allowed_group.id}" +shared_context "A group that is allowed to assign" do + fab!(:assign_allowed_group) do + Fabricate(:group, assignable_level: Group::ALIAS_LEVELS[:everyone]) end + before { SiteSetting.assign_allowed_on_groups += "|#{assign_allowed_group.id}" } + def add_to_assign_allowed_group(user) assign_allowed_group.add(user) end