diff --git a/app/javascript/mastodon/features/notifications/components/notification.jsx b/app/javascript/mastodon/features/notifications/components/notification.jsx index cb3f92b71c..1872d9f689 100644 --- a/app/javascript/mastodon/features/notifications/components/notification.jsx +++ b/app/javascript/mastodon/features/notifications/components/notification.jsx @@ -30,6 +30,7 @@ const messages = defineMessages({ status: { id: 'notification.status', defaultMessage: '{name} just posted' }, statusReference: { id: 'notification.status_reference', defaultMessage: '{name} refered' }, update: { id: 'notification.update', defaultMessage: '{name} edited a post' }, + warning: { id: 'notification.warning', defaultMessage: 'You have been warned and "{action}" has been executed. Check your mailbox' }, adminSignUp: { id: 'notification.admin.sign_up', defaultMessage: '{name} signed up' }, adminReport: { id: 'notification.admin.report', defaultMessage: '{name} reported {target}' }, }); @@ -443,6 +444,31 @@ class Notification extends ImmutablePureComponent { ); } + renderWarning (notification) { + const { intl, unread } = this.props; + console.dir(notification); + + return ( + +
+
+
+ +
+ + + + +
+ +
+ {notification.getIn(['account_warning', 'text'])} +
+
+
+ ); + } + renderAdminSignUp (notification, account, link) { const { intl, unread } = this.props; @@ -522,6 +548,8 @@ class Notification extends ImmutablePureComponent { return this.renderUpdate(notification, link); case 'poll': return this.renderPoll(notification, account); + case 'warning': + return this.renderWarning(notification); case 'admin.sign_up': return this.renderAdminSignUp(notification, account, link); case 'admin.report': diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index cca4facea9..40e19d3a7a 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -439,6 +439,7 @@ "notification.status": "{name}さんが投稿しました", "notification.status_reference": "{name}さんがあなたの投稿を参照しました", "notification.update": "{name}さんが投稿を編集しました", + "notification.warning": "あなたは警告を出され、「{action}」が実行されました。詳細はメールをご確認ください", "notifications.clear": "通知を消去", "notifications.clear_confirmation": "本当に通知を消去しますか?", "notifications.column_settings.admin.report": "新しい通報:", diff --git a/app/javascript/mastodon/reducers/notifications.js b/app/javascript/mastodon/reducers/notifications.js index 984097ca0f..8ba9cf3c18 100644 --- a/app/javascript/mastodon/reducers/notifications.js +++ b/app/javascript/mastodon/reducers/notifications.js @@ -52,10 +52,11 @@ const notificationToMap = notification => ImmutableMap({ id: notification.id, type: notification.type, account: notification.account.id, - emoji_reaction: ImmutableMap(notification.emoji_reaction), created_at: notification.created_at, + emoji_reaction: ImmutableMap(notification.emoji_reaction), status: notification.status ? notification.status.id : null, report: notification.report ? fromJS(notification.report) : null, + account_warning: notification.account_warning ? ImmutableMap(notification.account_warning) : null, }); const normalizeNotification = (state, notification, usePendingItems) => { diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 1b6e5626ec..9cfce31355 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1848,6 +1848,11 @@ a.account__display-name { } } +.notification__warning-text { + padding: 16px 16px 16px 48px; + color: $darker-text-color; +} + .notification__display-name { color: inherit; font-weight: 500; diff --git a/app/models/admin/account_action.rb b/app/models/admin/account_action.rb index 2b5560e2eb..c85d733619 100644 --- a/app/models/admin/account_action.rb +++ b/app/models/admin/account_action.rb @@ -54,6 +54,7 @@ class Admin::AccountAction process_email! process_queue! + notify! end def report @@ -107,6 +108,10 @@ class Admin::AccountAction log_action(:create, @warning) if @warning.text.present? && type == 'none' end + def notify! + LocalNotificationWorker.perform_async(target_account.id, @warning.id, 'AccountWarning', 'warning') if @warning && %w(none sensitive silence).include?(type) + end + def process_reports! # If we're doing "mark as resolved" on a single report, # then we want to keep other reports open in case they diff --git a/app/models/admin/status_batch_action.rb b/app/models/admin/status_batch_action.rb index b5178c672e..a6c0260758 100644 --- a/app/models/admin/status_batch_action.rb +++ b/app/models/admin/status_batch_action.rb @@ -17,6 +17,7 @@ class Admin::StatusBatchAction def save! process_action! + notify! end private @@ -157,6 +158,10 @@ class Admin::StatusBatchAction report.save! end + def notify! + LocalNotificationWorker.perform_async(target_account.id, @warning.id, 'AccountWarning', 'warning') if warnable? && @warning + end + def report @report ||= Report.find(report_id) if report_id.present? end diff --git a/app/models/notification.rb b/app/models/notification.rb index 8f15435c2a..50e45f05b3 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -28,6 +28,7 @@ class Notification < ApplicationRecord 'EmojiReaction' => :emoji_reaction, 'StatusReference' => :status_reference, 'Poll' => :poll, + 'AccountWarning' => :warning, }.freeze TYPES = %i( @@ -42,6 +43,7 @@ class Notification < ApplicationRecord reaction poll update + warning admin.sign_up admin.report ).freeze @@ -73,6 +75,7 @@ class Notification < ApplicationRecord belongs_to :status_reference, inverse_of: :notification belongs_to :poll, inverse_of: false belongs_to :report, inverse_of: false + belongs_to :account_warning, inverse_of: false end validates :type, inclusion: { in: TYPES } @@ -159,6 +162,15 @@ class Notification < ApplicationRecord end end + def from_account_web + case activity_type + when 'AccountWarning' + account_warning&.target_account + else + from_account + end + end + after_initialize :set_from_account before_validation :set_from_account @@ -168,7 +180,7 @@ class Notification < ApplicationRecord return unless new_record? case activity_type - when 'Status', 'Follow', 'Favourite', 'EmojiReaction', 'EmojiReact', 'FollowRequest', 'Poll', 'Report' + when 'Status', 'Follow', 'Favourite', 'EmojiReaction', 'EmojiReact', 'FollowRequest', 'Poll', 'Report', 'AccountWarning' self.from_account_id = activity&.account_id when 'Mention', 'StatusReference' self.from_account_id = activity&.status&.account_id diff --git a/app/serializers/rest/account_warning_serializer.rb b/app/serializers/rest/account_warning_serializer.rb new file mode 100644 index 0000000000..3f5940b71c --- /dev/null +++ b/app/serializers/rest/account_warning_serializer.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class REST::AccountWarningSerializer < ActiveModel::Serializer + attributes :id, :action, :text, :status_ids +end diff --git a/app/serializers/rest/notification_serializer.rb b/app/serializers/rest/notification_serializer.rb index 5a7d6e11b5..71b5d69fc5 100644 --- a/app/serializers/rest/notification_serializer.rb +++ b/app/serializers/rest/notification_serializer.rb @@ -3,10 +3,11 @@ class REST::NotificationSerializer < ActiveModel::Serializer attributes :id, :type, :created_at - belongs_to :from_account, key: :account, serializer: REST::AccountSerializer + belongs_to :from_account_web, key: :account, serializer: REST::AccountSerializer belongs_to :target_status, key: :status, if: :status_type?, serializer: REST::StatusSerializer belongs_to :report, if: :report_type?, serializer: REST::ReportSerializer belongs_to :emoji_reaction, if: :emoji_reaction_type?, serializer: REST::NotifyEmojiReactionSerializer + belongs_to :account_warning, if: :warning_type?, serializer: REST::AccountWarningSerializer def id object.id.to_s @@ -20,6 +21,10 @@ class REST::NotificationSerializer < ActiveModel::Serializer object.type == :'admin.report' end + def warning_type? + object.type == :warning + end + def emoji_reaction_type? object.type == :emoji_reaction end