diff --git a/Gemfile.lock b/Gemfile.lock index 699e2f83e1e..e4d787eb646 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -758,7 +758,7 @@ GEM rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (3.0.3) + rubocop-rspec (3.0.4) rubocop (~> 1.61) rubocop-rspec_rails (2.30.0) rubocop (~> 1.61) diff --git a/app/controllers/api/v1/notifications/policies_controller.rb b/app/controllers/api/v1/notifications/policies_controller.rb index 1ec336f9a59..9d70c283bec 100644 --- a/app/controllers/api/v1/notifications/policies_controller.rb +++ b/app/controllers/api/v1/notifications/policies_controller.rb @@ -8,12 +8,12 @@ class Api::V1::Notifications::PoliciesController < Api::BaseController before_action :set_policy def show - render json: @policy, serializer: REST::NotificationPolicySerializer + render json: @policy, serializer: REST::V1::NotificationPolicySerializer end def update @policy.update!(resource_params) - render json: @policy, serializer: REST::NotificationPolicySerializer + render json: @policy, serializer: REST::V1::NotificationPolicySerializer end private diff --git a/app/controllers/api/v1/notifications/requests_controller.rb b/app/controllers/api/v1/notifications/requests_controller.rb index b4207147c87..0710166d05b 100644 --- a/app/controllers/api/v1/notifications/requests_controller.rb +++ b/app/controllers/api/v1/notifications/requests_controller.rb @@ -29,7 +29,7 @@ class Api::V1::Notifications::RequestsController < Api::BaseController end def dismiss - @request.destroy! + DismissNotificationRequestService.new.call(@request) render_empty end diff --git a/app/controllers/api/v2/notifications/policies_controller.rb b/app/controllers/api/v2/notifications/policies_controller.rb new file mode 100644 index 00000000000..637587967fe --- /dev/null +++ b/app/controllers/api/v2/notifications/policies_controller.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +class Api::V2::Notifications::PoliciesController < Api::BaseController + before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, only: :show + before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: :update + + before_action :require_user! + before_action :set_policy + + def show + render json: @policy, serializer: REST::NotificationPolicySerializer + end + + def update + @policy.update!(resource_params) + render json: @policy, serializer: REST::NotificationPolicySerializer + end + + private + + def set_policy + @policy = NotificationPolicy.find_or_initialize_by(account: current_account) + + with_read_replica do + @policy.summarize! + end + end + + def resource_params + params.permit( + :for_not_following, + :for_not_followers, + :for_new_accounts, + :for_private_mentions, + :for_limited_accounts + ) + end +end diff --git a/app/controllers/api/v2_alpha/notifications_controller.rb b/app/controllers/api/v2_alpha/notifications_controller.rb index 837499e8984..d0205ad6af8 100644 --- a/app/controllers/api/v2_alpha/notifications_controller.rb +++ b/app/controllers/api/v2_alpha/notifications_controller.rb @@ -16,10 +16,10 @@ class Api::V2Alpha::NotificationsController < Api::BaseController @group_metadata = load_group_metadata @grouped_notifications = load_grouped_notifications @relationships = StatusRelationshipsPresenter.new(target_statuses_from_notifications, current_user&.account_id) - @sample_accounts = @grouped_notifications.flat_map(&:sample_accounts) + @presenter = GroupedNotificationsPresenter.new(@grouped_notifications, expand_accounts: expand_accounts_param) # Preload associations to avoid N+1s - ActiveRecord::Associations::Preloader.new(records: @sample_accounts, associations: [:account_stat, { user: :role }]).call + ActiveRecord::Associations::Preloader.new(records: @presenter.accounts, associations: [:account_stat, { user: :role }]).call end MastodonOTELTracer.in_span('Api::V2Alpha::NotificationsController#index rendering') do |span| @@ -27,14 +27,14 @@ class Api::V2Alpha::NotificationsController < Api::BaseController span.add_attributes( 'app.notification_grouping.count' => @grouped_notifications.size, - 'app.notification_grouping.sample_account.count' => @sample_accounts.size, - 'app.notification_grouping.sample_account.unique_count' => @sample_accounts.pluck(:id).uniq.size, + 'app.notification_grouping.account.count' => @presenter.accounts.size, + 'app.notification_grouping.partial_account.count' => @presenter.partial_accounts.size, 'app.notification_grouping.status.count' => statuses.size, - 'app.notification_grouping.status.unique_count' => statuses.uniq.size + 'app.notification_grouping.status.unique_count' => statuses.uniq.size, + 'app.notification_grouping.expand_accounts_param' => expand_accounts_param ) - presenter = GroupedNotificationsPresenter.new(@grouped_notifications) - render json: presenter, serializer: REST::DedupNotificationGroupSerializer, relationships: @relationships, group_metadata: @group_metadata + render json: @presenter, serializer: REST::DedupNotificationGroupSerializer, relationships: @relationships, group_metadata: @group_metadata, expand_accounts: expand_accounts_param end end @@ -131,4 +131,15 @@ class Api::V2Alpha::NotificationsController < Api::BaseController def pagination_params(core_params) params.slice(:limit, :types, :exclude_types, :include_filtered).permit(:limit, :include_filtered, types: [], exclude_types: []).merge(core_params) end + + def expand_accounts_param + case params[:expand_accounts] + when nil, 'full' + 'full' + when 'partial_avatars' + 'partial_avatars' + else + raise Mastodon::InvalidParameterError, "Invalid value for 'expand_accounts': '#{params[:expand_accounts]}', allowed values are 'full' and 'partial_avatars'" + end + end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 7e9cfee3f68..a6ab4044bcb 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -116,7 +116,7 @@ module ApplicationHelper def material_symbol(icon, attributes = {}) inline_svg_tag( "400-24px/#{icon}.svg", - class: %w(icon).concat(attributes[:class].to_s.split), + class: ['icon', "material-#{icon}"].concat(attributes[:class].to_s.split), role: :img ) end @@ -127,23 +127,23 @@ module ApplicationHelper def visibility_icon(status) if status.public_visibility? - fa_icon('globe', title: I18n.t('statuses.visibilities.public')) + material_symbol('globe', title: I18n.t('statuses.visibilities.public')) elsif status.unlisted_visibility? - fa_icon('unlock', title: I18n.t('statuses.visibilities.unlisted')) + material_symbol('lock_open', title: I18n.t('statuses.visibilities.unlisted')) elsif status.private_visibility? || status.limited_visibility? - fa_icon('lock', title: I18n.t('statuses.visibilities.private')) + material_symbol('lock', title: I18n.t('statuses.visibilities.private')) elsif status.direct_visibility? - fa_icon('at', title: I18n.t('statuses.visibilities.direct')) + material_symbol('alternate_email', title: I18n.t('statuses.visibilities.direct')) end end def interrelationships_icon(relationships, account_id) if relationships.following[account_id] && relationships.followed_by[account_id] - fa_icon('exchange', title: I18n.t('relationships.mutual'), class: 'fa-fw active passive') + material_symbol('sync_alt', title: I18n.t('relationships.mutual'), class: 'active passive') elsif relationships.following[account_id] - fa_icon(locale_direction == 'ltr' ? 'arrow-right' : 'arrow-left', title: I18n.t('relationships.following'), class: 'fa-fw active') + material_symbol(locale_direction == 'ltr' ? 'arrow_right_alt' : 'arrow_left_alt', title: I18n.t('relationships.following'), class: 'active') elsif relationships.followed_by[account_id] - fa_icon(locale_direction == 'ltr' ? 'arrow-left' : 'arrow-right', title: I18n.t('relationships.followers'), class: 'fa-fw passive') + material_symbol(locale_direction == 'ltr' ? 'arrow_left_alt' : 'arrow_right_alt', title: I18n.t('relationships.followers'), class: 'passive') end end diff --git a/app/helpers/statuses_helper.rb b/app/helpers/statuses_helper.rb index ca693a8a78a..d956e4fcd8f 100644 --- a/app/helpers/statuses_helper.rb +++ b/app/helpers/statuses_helper.rb @@ -60,13 +60,13 @@ module StatusesHelper def fa_visibility_icon(status) case status.visibility when 'public' - fa_icon 'globe fw' + material_symbol 'globe' when 'unlisted' - fa_icon 'unlock fw' + material_symbol 'lock_open' when 'private' - fa_icon 'lock fw' + material_symbol 'lock' when 'direct' - fa_icon 'at fw' + material_symbol 'alternate_email' end end diff --git a/app/javascript/mastodon/api/notification_policies.ts b/app/javascript/mastodon/api/notification_policies.ts index 4032134fb58..77473975568 100644 --- a/app/javascript/mastodon/api/notification_policies.ts +++ b/app/javascript/mastodon/api/notification_policies.ts @@ -2,8 +2,8 @@ import { apiRequestGet, apiRequestPut } from 'mastodon/api'; import type { NotificationPolicyJSON } from 'mastodon/api_types/notification_policies'; export const apiGetNotificationPolicy = () => - apiRequestGet('/v1/notifications/policy'); + apiRequestGet('/v2/notifications/policy'); export const apiUpdateNotificationsPolicy = ( policy: Partial, -) => apiRequestPut('/v1/notifications/policy', policy); +) => apiRequestPut('/v2/notifications/policy', policy); diff --git a/app/javascript/mastodon/api_types/notification_policies.ts b/app/javascript/mastodon/api_types/notification_policies.ts index 0f4a2d132e0..1c3970782cb 100644 --- a/app/javascript/mastodon/api_types/notification_policies.ts +++ b/app/javascript/mastodon/api_types/notification_policies.ts @@ -1,10 +1,13 @@ // See app/serializers/rest/notification_policy_serializer.rb +export type NotificationPolicyValue = 'accept' | 'filter' | 'drop'; + export interface NotificationPolicyJSON { - filter_not_following: boolean; - filter_not_followers: boolean; - filter_new_accounts: boolean; - filter_private_mentions: boolean; + for_not_following: NotificationPolicyValue; + for_not_followers: NotificationPolicyValue; + for_new_accounts: NotificationPolicyValue; + for_private_mentions: NotificationPolicyValue; + for_limited_accounts: NotificationPolicyValue; summary: { pending_requests_count: number; pending_notifications_count: number; diff --git a/app/javascript/mastodon/components/account.jsx b/app/javascript/mastodon/components/account.jsx index 2a748e67ff1..265c68697ba 100644 --- a/app/javascript/mastodon/components/account.jsx +++ b/app/javascript/mastodon/components/account.jsx @@ -106,7 +106,7 @@ const Account = ({ size = 46, account, onFollow, onBlock, onMute, onMuteNotifica ); } else if (defaultAction === 'mute') { - buttons =