# frozen_string_literal: true module Notifications class ConsolidationPlanner def consolidate_or_save!(notification) plan = plan_for(notification) return :no_plan if plan.nil? plan.consolidate_or_save!(notification) end private def plan_for(notification) consolidation_plans = [ liked_by_two_users, liked, group_message_summary, group_membership, new_features_notification, ] consolidation_plans.concat(DiscoursePluginRegistry.notification_consolidation_plans) consolidation_plans.detect { |plan| plan.can_consolidate_data?(notification) } end def liked ConsolidateNotifications .new( from: Notification.types[:liked], to: Notification.types[:liked_consolidated], threshold: -> { SiteSetting.notification_consolidation_threshold }, consolidation_window: SiteSetting.likes_notification_consolidation_window_mins.minutes, unconsolidated_query_blk: Proc.new do |notifications, data| key = "display_username" value = data[key.to_sym] filtered = notifications.where("data::json ->> 'username2' IS NULL") filtered = filtered.where("data::json ->> '#{key}' = ?", value) if value filtered end, consolidated_query_blk: filtered_by_data_attribute("display_username"), ) .set_mutations( set_data_blk: Proc.new do |notification| data = notification.data_hash data.merge(username: data[:display_username]) end, ) .set_precondition(precondition_blk: Proc.new { |data| data[:username2].blank? }) end def liked_by_two_users DeletePreviousNotifications .new( type: Notification.types[:liked], previous_query_blk: Proc.new do |notifications, data| notifications.where(id: data[:previous_notification_id]) end, ) .set_mutations( set_data_blk: Proc.new do |notification| existing_notification_of_same_type = Notification .where(user: notification.user) .order("notifications.id DESC") .where(topic_id: notification.topic_id, post_number: notification.post_number) .where(notification_type: notification.notification_type) .where("created_at > ?", 1.day.ago) .first data = notification.data_hash if existing_notification_of_same_type same_type_data = existing_notification_of_same_type.data_hash data.merge( previous_notification_id: existing_notification_of_same_type.id, username2: same_type_data[:display_username], count: (same_type_data[:count] || 1).to_i + 1, ) else data end end, ) .set_precondition( precondition_blk: Proc.new do |data, notification| always_freq = UserOption.like_notification_frequency_type[:always] notification.user&.user_option&.like_notification_frequency == always_freq && data[:previous_notification_id].present? end, ) end def group_membership ConsolidateNotifications .new( from: Notification.types[:private_message], to: Notification.types[:membership_request_consolidated], threshold: -> { SiteSetting.notification_consolidation_threshold }, consolidation_window: Notification::MEMBERSHIP_REQUEST_CONSOLIDATION_WINDOW_HOURS.hours, unconsolidated_query_blk: filtered_by_data_attribute("topic_title"), consolidated_query_blk: filtered_by_data_attribute("group_name"), ) .set_precondition(precondition_blk: Proc.new { |data| data[:group_name].present? }) .set_mutations( set_data_blk: Proc.new do |notification| data = notification.data_hash post_id = data[:original_post_id] custom_field = PostCustomField.select(:value).find_by(post_id: post_id, name: "requested_group_id") group_id = custom_field&.value group_name = group_id.present? ? Group.select(:name).find_by(id: group_id.to_i)&.name : nil data[:group_name] = group_name data end, ) end def group_message_summary DeletePreviousNotifications.new( type: Notification.types[:group_message_summary], previous_query_blk: filtered_by_data_attribute("group_id"), ).set_precondition(precondition_blk: Proc.new { |data| data[:group_id].present? }) end def filtered_by_data_attribute(attribute_name) Proc.new do |notifications, data| if (value = data[attribute_name.to_sym]) notifications.where("data::json ->> '#{attribute_name}' = ?", value.to_s) else notifications end end end def new_features_notification DeletePreviousNotifications.new(type: Notification.types[:new_features]) end end end