From ed099d8bdc5b3d9e7df7ce5358441887e6bb7e48 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 15 Sep 2020 14:37:58 +0200 Subject: Change account suspensions to be reversible by default (#14726) --- db/migrate/20200908193330_create_account_deletion_requests.rb | 8 ++++++++ db/schema.rb | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20200908193330_create_account_deletion_requests.rb (limited to 'db') diff --git a/db/migrate/20200908193330_create_account_deletion_requests.rb b/db/migrate/20200908193330_create_account_deletion_requests.rb new file mode 100644 index 000000000..e03183ae4 --- /dev/null +++ b/db/migrate/20200908193330_create_account_deletion_requests.rb @@ -0,0 +1,8 @@ +class CreateAccountDeletionRequests < ActiveRecord::Migration[5.2] + def change + create_table :account_deletion_requests do |t| + t.references :account, foreign_key: { on_delete: :cascade } + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index e37aae962..038e39130 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: 2020_06_30_190544) do +ActiveRecord::Schema.define(version: 2020_09_08_193330) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -36,6 +36,13 @@ ActiveRecord::Schema.define(version: 2020_06_30_190544) do t.index ["conversation_id"], name: "index_account_conversations_on_conversation_id" end + create_table "account_deletion_requests", force: :cascade do |t| + t.bigint "account_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["account_id"], name: "index_account_deletion_requests_on_account_id" + end + create_table "account_domain_blocks", force: :cascade do |t| t.string "domain" t.datetime "created_at", null: false @@ -926,6 +933,7 @@ ActiveRecord::Schema.define(version: 2020_06_30_190544) do add_foreign_key "account_aliases", "accounts", on_delete: :cascade add_foreign_key "account_conversations", "accounts", on_delete: :cascade add_foreign_key "account_conversations", "conversations", on_delete: :cascade + add_foreign_key "account_deletion_requests", "accounts", on_delete: :cascade add_foreign_key "account_domain_blocks", "accounts", name: "fk_206c6029bd", on_delete: :cascade add_foreign_key "account_identity_proofs", "accounts", on_delete: :cascade add_foreign_key "account_migrations", "accounts", column: "target_account_id", on_delete: :nullify -- cgit From 974b1b79ce58e6799e5e5bb576e630ca783150de Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 18 Sep 2020 17:26:45 +0200 Subject: Add option to be notified when a followed user posts (#13546) * Add bell button Fix #4890 * Remove duplicate type from post-deployment migration * Fix legacy class type mappings * Improve query performance with better index * Fix validation * Remove redundant index from notifications --- app/controllers/api/v1/accounts_controller.rb | 5 +- .../api/v1/follow_requests_controller.rb | 2 +- app/javascript/mastodon/actions/accounts.js | 4 +- app/javascript/mastodon/actions/notifications.js | 2 +- .../mastodon/features/account/components/header.js | 12 +++- .../features/account_timeline/components/header.js | 5 ++ .../containers/header_container.js | 12 +++- .../notifications/components/filter_bar.js | 8 +++ .../notifications/components/notification.js | 35 +++++++++ app/javascript/styles/mastodon/components.scss | 4 ++ app/lib/activitypub/activity.rb | 4 +- app/lib/activitypub/activity/follow.rb | 4 +- app/lib/activitypub/activity/like.rb | 2 +- app/models/concerns/account_interactions.rb | 26 ++++--- app/models/follow.rb | 3 +- app/models/follow_request.rb | 3 +- app/models/notification.rb | 44 +++++++----- app/serializers/rest/notification_serializer.rb | 2 +- app/serializers/rest/relationship_serializer.rb | 12 +++- app/services/favourite_service.rb | 2 +- app/services/follow_service.rb | 15 ++-- app/services/import_service.rb | 6 +- app/services/notify_service.rb | 8 ++- app/services/process_mentions_service.rb | 2 +- app/services/reblog_service.rb | 2 +- app/workers/feed_insert_worker.rb | 15 +++- app/workers/local_notification_worker.rb | 4 +- app/workers/poll_expiration_notify_worker.rb | 4 +- app/workers/refollow_worker.rb | 3 +- app/workers/unfollow_follow_worker.rb | 5 +- db/migrate/20200917192924_add_notify_to_follows.rb | 19 +++++ .../20200917193034_add_type_to_notifications.rb | 5 ++ ...200917222316_add_index_notifications_on_type.rb | 7 ++ .../20200917193528_migrate_notifications_type.rb | 22 ++++++ ...move_index_notifications_on_account_activity.rb | 15 ++++ db/schema.rb | 8 ++- .../controllers/api/v1/accounts_controller_spec.rb | 84 +++++++++++++++------- spec/models/concerns/account_interactions_spec.rb | 2 +- spec/models/follow_request_spec.rb | 2 +- spec/services/import_service_spec.rb | 1 + spec/services/notify_service_spec.rb | 6 +- spec/workers/refollow_worker_spec.rb | 4 +- 42 files changed, 324 insertions(+), 106 deletions(-) create mode 100644 db/migrate/20200917192924_add_notify_to_follows.rb create mode 100644 db/migrate/20200917193034_add_type_to_notifications.rb create mode 100644 db/migrate/20200917222316_add_index_notifications_on_type.rb create mode 100644 db/post_migrate/20200917193528_migrate_notifications_type.rb create mode 100644 db/post_migrate/20200917222734_remove_index_notifications_on_account_activity.rb (limited to 'db') diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index 61dcb87c2..aef51a647 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -30,9 +30,8 @@ class Api::V1::AccountsController < Api::BaseController end def follow - FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs), with_rate_limit: true) - - options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } } + follow = FollowService.new.call(current_user.account, @account, reblogs: params.key?(:reblogs) ? truthy_param?(:reblogs) : nil, notify: params.key?(:notify) ? truthy_param?(:notify) : nil, with_rate_limit: true) + options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: follow.show_reblogs?, notify: follow.notify? } }, requested_map: { @account.id => false } } render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(options) end diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb index 0420b7bef..b34c76f29 100644 --- a/app/controllers/api/v1/follow_requests_controller.rb +++ b/app/controllers/api/v1/follow_requests_controller.rb @@ -13,7 +13,7 @@ class Api::V1::FollowRequestsController < Api::BaseController def authorize AuthorizeFollowService.new.call(account, current_account) - NotifyService.new.call(current_account, Follow.find_by(account: account, target_account: current_account)) + NotifyService.new.call(current_account, :follow, Follow.find_by(account: account, target_account: current_account)) render json: account, serializer: REST::RelationshipSerializer, relationships: relationships end diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js index d28f7dad8..723c04e55 100644 --- a/app/javascript/mastodon/actions/accounts.js +++ b/app/javascript/mastodon/actions/accounts.js @@ -109,14 +109,14 @@ export function fetchAccountFail(id, error) { }; }; -export function followAccount(id, reblogs = true) { +export function followAccount(id, options = { reblogs: true }) { return (dispatch, getState) => { const alreadyFollowing = getState().getIn(['relationships', id, 'following']); const locked = getState().getIn(['accounts', id, 'locked'], false); dispatch(followAccountRequest(id, locked)); - api(getState).post(`/api/v1/accounts/${id}/follow`, { reblogs }).then(response => { + api(getState).post(`/api/v1/accounts/${id}/follow`, options).then(response => { dispatch(followAccountSuccess(response.data, alreadyFollowing)); }).catch(error => { dispatch(followAccountFail(error, locked)); diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js index a26844f84..099e42f6c 100644 --- a/app/javascript/mastodon/actions/notifications.js +++ b/app/javascript/mastodon/actions/notifications.js @@ -59,7 +59,7 @@ export function updateNotifications(notification, intlMessages, intlLocale) { let filtered = false; - if (notification.type === 'mention') { + if (['mention', 'status'].includes(notification.type)) { const dropRegex = filters[0]; const regex = filters[1]; const searchIndex = searchTextFromRawStatus(notification.status); diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js index 02217b62c..2b97af4e6 100644 --- a/app/javascript/mastodon/features/account/components/header.js +++ b/app/javascript/mastodon/features/account/components/header.js @@ -7,6 +7,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import { autoPlayGif, me, isStaff } from 'mastodon/initial_state'; import classNames from 'classnames'; import Icon from 'mastodon/components/icon'; +import IconButton from 'mastodon/components/icon_button'; import Avatar from 'mastodon/components/avatar'; import { counterRenderer } from 'mastodon/components/common_counter'; import ShortNumber from 'mastodon/components/short_number'; @@ -35,6 +36,8 @@ const messages = defineMessages({ unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' }, hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide boosts from @{name}' }, showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' }, + enableNotifications: { id: 'account.enable_notifications', defaultMessage: 'Notify me when @{name} posts' }, + disableNotifications: { id: 'account.disable_notifications', defaultMessage: 'Stop notifying me when @{name} posts' }, pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, @@ -68,8 +71,9 @@ class Header extends ImmutablePureComponent { onBlock: PropTypes.func.isRequired, onMention: PropTypes.func.isRequired, onDirect: PropTypes.func.isRequired, - onReport: PropTypes.func.isRequired, onReblogToggle: PropTypes.func.isRequired, + onNotifyToggle: PropTypes.func.isRequired, + onReport: PropTypes.func.isRequired, onMute: PropTypes.func.isRequired, onBlockDomain: PropTypes.func.isRequired, onUnblockDomain: PropTypes.func.isRequired, @@ -144,6 +148,7 @@ class Header extends ImmutablePureComponent { let info = []; let actionBtn = ''; + let bellBtn = ''; let lockedIcon = ''; let menu = []; @@ -173,6 +178,10 @@ class Header extends ImmutablePureComponent { actionBtn = +