diff --git a/app/controllers/notifications/trays_controller.rb b/app/controllers/notifications/trays_controller.rb index 0adc0e17b..46dc445cf 100644 --- a/app/controllers/notifications/trays_controller.rb +++ b/app/controllers/notifications/trays_controller.rb @@ -1,9 +1,27 @@ class Notifications::TraysController < ApplicationController + MAX_ENTRIES_LIMIT = 100 + def show - @notifications = Current.user.notifications.unread.preloaded.ordered.limit(100) + @notifications = unread_notifications + if include_read? + @notifications += read_notifications + end # Invalidate on the whole set instead of the unread set since the max updated at in the unread set # can stay the same when reading old notifications. - fresh_when Current.user.notifications + fresh_when etag: [ Current.user.notifications, include_read? ] end + + private + def unread_notifications + Current.user.notifications.unread.preloaded.ordered.limit(MAX_ENTRIES_LIMIT) + end + + def read_notifications + Current.user.notifications.read.preloaded.ordered.limit(MAX_ENTRIES_LIMIT) + end + + def include_read? + ActiveModel::Type::Boolean.new.cast(params[:include_read]) + end end diff --git a/app/models/notification.rb b/app/models/notification.rb index 3d7df5885..417a2f22d 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -10,7 +10,13 @@ class Notification < ApplicationRecord scope :unread, -> { where(read_at: nil) } scope :read, -> { where.not(read_at: nil) } scope :ordered, -> { order(read_at: :desc, updated_at: :desc) } - scope :preloaded, -> { preload(:card, :creator, :account, source: [ :board, :creator, { eventable: [ :closure, :board, :assignments ] } ]) } + scope :preloaded, -> { + preload( + :creator, :account, + card: [ :board, :column, :closure, :not_now ], + source: [ :board, :creator, { eventable: [ :closure, :board, :assignments ] } ] + ) + } before_validation :set_card after_create :bundle diff --git a/app/views/cards/_card.json.jbuilder b/app/views/cards/_card.json.jbuilder index f8e727732..bccf51d6e 100644 --- a/app/views/cards/_card.json.jbuilder +++ b/app/views/cards/_card.json.jbuilder @@ -8,6 +8,7 @@ json.cache! card do json.tags card.tags.pluck(:title).sort json.closed card.closed? + json.postponed card.postponed? json.golden card.golden? json.last_active_at card.last_active_at.utc json.created_at card.created_at.utc diff --git a/app/views/notifications/_notification.json.jbuilder b/app/views/notifications/_notification.json.jbuilder index d2fadfa1b..ae166f44a 100644 --- a/app/views/notifications/_notification.json.jbuilder +++ b/app/views/notifications/_notification.json.jbuilder @@ -3,14 +3,19 @@ json.cache! notification do json.read notification.read? json.read_at notification.read_at&.utc json.created_at notification.created_at.utc + json.source_type notification.source_type.underscore json.partial! "notifications/notification/#{notification.source_type.underscore}/body", notification: notification json.creator notification.creator, partial: "users/user", as: :user json.card do - json.(notification.card, :id, :title, :status) + json.(notification.card, :id, :number, :title, :status) + json.board_name notification.card.board.name + json.closed notification.card.closed? + json.postponed notification.card.postponed? json.url card_url(notification.card) + json.column notification.card.column, partial: "columns/column", as: :column if notification.card.column end json.url notification_url(notification) diff --git a/app/views/notifications/trays/show.json.jbuilder b/app/views/notifications/trays/show.json.jbuilder new file mode 100644 index 000000000..0c2928cef --- /dev/null +++ b/app/views/notifications/trays/show.json.jbuilder @@ -0,0 +1 @@ +json.array! @notifications, partial: "notifications/notification", as: :notification diff --git a/app/views/users/_user.json.jbuilder b/app/views/users/_user.json.jbuilder index 0884f225a..ed05bc67f 100644 --- a/app/views/users/_user.json.jbuilder +++ b/app/views/users/_user.json.jbuilder @@ -5,4 +5,5 @@ json.cache! user do json.created_at user.created_at.utc json.url user_url(user) + json.avatar_url user_avatar_url(user) end diff --git a/test/controllers/cards_controller_test.rb b/test/controllers/cards_controller_test.rb index 3a97f3166..42e24d927 100644 --- a/test/controllers/cards_controller_test.rb +++ b/test/controllers/cards_controller_test.rb @@ -176,6 +176,7 @@ class CardsControllerTest < ActionDispatch::IntegrationTest assert_equal card.title, @response.parsed_body["title"] assert_equal card.closed?, @response.parsed_body["closed"] + assert_equal card.postponed?, @response.parsed_body["postponed"] assert_equal 2, @response.parsed_body["steps"].size assert_equal card_comments_url(card), @response.parsed_body["comments_url"] assert_equal card_reactions_url(card), @response.parsed_body["reactions_url"] diff --git a/test/controllers/notifications/trays_controller_test.rb b/test/controllers/notifications/trays_controller_test.rb index 07034fff0..b6efa200b 100644 --- a/test/controllers/notifications/trays_controller_test.rb +++ b/test/controllers/notifications/trays_controller_test.rb @@ -11,4 +11,24 @@ class Notifications::TraysControllerTest < ActionDispatch::IntegrationTest assert_response :success assert_select "div", text: /Layout is broken/ end + + test "show as JSON" do + expected_ids = users(:kevin).notifications.unread.ordered.limit(100).pluck(:id) + + get tray_notifications_path(format: :json) + + assert_response :success + assert_equal expected_ids, @response.parsed_body.map { |s| s["id"] } + end + + test "show as JSON with include_read includes read notifications" do + notifications = users(:kevin).notifications + expected_ids = notifications.unread.ordered.limit(100).pluck(:id) + + notifications.read.ordered.limit(100).pluck(:id) + + get tray_notifications_path(format: :json, include_read: true) + + assert_response :success + assert_equal expected_ids, @response.parsed_body.map { |s| s["id"] } + end end diff --git a/test/controllers/notifications_controller_test.rb b/test/controllers/notifications_controller_test.rb index 0d0565f24..29b454ebd 100644 --- a/test/controllers/notifications_controller_test.rb +++ b/test/controllers/notifications_controller_test.rb @@ -22,5 +22,13 @@ class NotificationsControllerTest < ActionDispatch::IntegrationTest assert_not_nil notification["card"] assert_not_nil notification["creator"] assert_not_nil notification["unread_count"] + assert_not_nil notification.dig("creator", "avatar_url") + assert_not_nil notification.dig("card", "number") + assert_not_nil notification.dig("card", "board_name") + assert_not_nil notification.dig("card", "column") + + card = notifications(:logo_assignment_kevin).card + assert_equal card.closed?, notification.dig("card", "closed") + assert_equal card.postponed?, notification.dig("card", "postponed") end end diff --git a/test/fixtures/notifications.yml b/test/fixtures/notifications.yml index b7ae167cd..8fa4404d5 100644 --- a/test/fixtures/notifications.yml +++ b/test/fixtures/notifications.yml @@ -5,6 +5,7 @@ logo_assignment_kevin: card: logo_uuid unread_count: 2 created_at: <%= 1.week.ago %> + updated_at: <%= 1.week.ago + 1.second %> creator: david_uuid account: 37s_uuid @@ -15,6 +16,7 @@ layout_commented_kevin: card: layout_uuid unread_count: 1 created_at: <%= 1.week.ago %> + updated_at: <%= 1.week.ago + 2.seconds %> creator: david_uuid account: 37s_uuid @@ -25,5 +27,6 @@ logo_mentioned_david: card: logo_uuid unread_count: 2 created_at: <%= 1.week.ago %> + updated_at: <%= 1.week.ago + 3.seconds %> creator: david_uuid account: 37s_uuid