diff --git a/app/controllers/api/notifications_controller.rb b/app/controllers/api/notifications_controller.rb index 76202452d..c99d78579 100644 --- a/app/controllers/api/notifications_controller.rb +++ b/app/controllers/api/notifications_controller.rb @@ -15,14 +15,16 @@ class API::NotificationsController < API::ApiController def index loop do @notifications = current_user.notifications + .delivered_in_system(current_user) .includes(:attached_object) .page(params[:page]) - .per(NOTIFICATIONS_PER_PAGE).order('created_at DESC') + .per(NOTIFICATIONS_PER_PAGE) + .order('created_at DESC') # we delete obsolete notifications on first access break unless delete_obsoletes(@notifications) end @totals = { - total: current_user.notifications.count, + total: current_user.notifications.delivered_in_system(current_user).count, unread: current_user.notifications.where(is_read: false).count } render :index @@ -39,7 +41,7 @@ class API::NotificationsController < API::ApiController break unless delete_obsoletes(@notifications) end @totals = { - total: current_user.notifications.count, + total: current_user.notifications.delivered_in_system(current_user).count, unread: current_user.notifications.where(is_read: false).count } render :index @@ -50,7 +52,7 @@ class API::NotificationsController < API::ApiController .where('is_read = false AND created_at >= :date', date: params[:last_poll]) .order('created_at DESC') @totals = { - total: current_user.notifications.count, + total: current_user.notifications.delivered_in_system(current_user).count, unread: current_user.notifications.where(is_read: false).count } render :index diff --git a/app/models/notification.rb b/app/models/notification.rb index 4d10409e1..f635ed868 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -6,6 +6,17 @@ class Notification < ApplicationRecord belongs_to :receiver, polymorphic: true belongs_to :attached_object, polymorphic: true + # This scope filter a user's in system (push) notifications : + # It fetch his notifications where no notification preference is made, + # or if this preference specify that the user accepts in system notification + scope :delivered_in_system, lambda { |user| + left_outer_joins(notification_type: :notification_preferences) + .where(<<-SQL.squish, user.id) + (notification_preferences.user_id = ? AND notification_preferences.in_system IS TRUE) + OR notification_preferences.id IS NULL + SQL + } + validates :receiver_id, :receiver_type, :attached_object_id, @@ -33,6 +44,16 @@ class Notification < ApplicationRecord NotificationsMailer.send_mail_by(self).deliver_later if save end + def deliver_with_preferences(user, notification_type) + preference = NotificationPreference.find_by(notification_type: notification_type, user: user) + + # Set as read if user do not want push notifications + self.is_read = true if preference && preference.in_system == false + + # Save notification if user do not want email notifications ; else, deliver. + preference && preference.email == false ? save : deliver_later + end + def get_meta_data(key) meta_data.try(:[], key.to_s) end diff --git a/app/models/notification_preference.rb b/app/models/notification_preference.rb new file mode 100644 index 000000000..530b1639f --- /dev/null +++ b/app/models/notification_preference.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# Allow user to set their preferences for notifications (push and email) +class NotificationPreference < ApplicationRecord + belongs_to :user + belongs_to :notification_type +end diff --git a/app/models/notification_type.rb b/app/models/notification_type.rb index 0a95a8978..b8fcc007b 100644 --- a/app/models/notification_type.rb +++ b/app/models/notification_type.rb @@ -3,5 +3,7 @@ # NotificationType defines the different types of Notification. class NotificationType < ApplicationRecord has_many :notifications, dependent: :destroy + has_many :notification_preferences, dependent: :destroy + validates :name, uniqueness: true, presence: true end diff --git a/app/models/user.rb b/app/models/user.rb index 976a1c7e2..335706913 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -51,6 +51,7 @@ class User < ApplicationRecord has_many :proof_of_identity_refusals, dependent: :destroy has_many :notifications, as: :receiver, dependent: :destroy + has_many :notification_preferences, dependent: :destroy # fix for create admin user before_save do diff --git a/app/services/notification_center.rb b/app/services/notification_center.rb index 8712d763e..dc9710763 100644 --- a/app/services/notification_center.rb +++ b/app/services/notification_center.rb @@ -4,14 +4,16 @@ class NotificationCenter def self.call(type: nil, receiver: nil, attached_object: nil, meta_data: {}) receiver = [receiver] unless receiver.respond_to?(:each) + notification_type = NotificationType.find_by(name: type) + receiver.each do |user| Notification.new( meta_data: meta_data, attached_object: attached_object, receiver: user, - notification_type: NotificationType.find_by(name: type) + notification_type: notification_type ) - .deliver_later + .deliver_with_preferences(user, notification_type) end end end diff --git a/db/migrate/20230127100506_create_notification_preferences.rb b/db/migrate/20230127100506_create_notification_preferences.rb new file mode 100644 index 000000000..f80d66f15 --- /dev/null +++ b/db/migrate/20230127100506_create_notification_preferences.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Create notification preferences : allow user to decide which type of notifications +# they want to receive via push ('in system') or via email. +class CreateNotificationPreferences < ActiveRecord::Migration[5.2] + def change + create_table :notification_preferences do |t| + t.references :user, index: true, foreign_key: true, null: false + t.references :notification_type, index: true, foreign_key: true, null: false + t.boolean :in_system, default: true + t.boolean :email, default: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 241653212..e43d4e49b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2023_01_26_160900) do +ActiveRecord::Schema.define(version: 2023_01_27_100506) do # These are extensions that must be enabled in order to support this database enable_extension "fuzzystrmatch"