about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/api/v1/accounts_controller.rb6
-rw-r--r--app/controllers/api/v1/blocks_controller.rb2
-rw-r--r--app/controllers/api/v1/domain_blocks_controller.rb4
-rw-r--r--app/controllers/api/v1/follow_requests_controller.rb6
-rw-r--r--app/controllers/api/v1/media_controller.rb2
-rw-r--r--app/controllers/api/v1/mutes_controller.rb2
-rw-r--r--app/javascript/mastodon/features/getting_started/index.js17
-rw-r--r--app/javascript/mastodon/features/ui/components/link_footer.js3
-rw-r--r--app/javascript/mastodon/features/ui/components/navigation_panel.js3
-rw-r--r--app/lib/activitypub/activity/announce.rb2
-rw-r--r--app/lib/activitypub/activity/follow.rb4
-rw-r--r--app/lib/activitypub/activity/like.rb2
-rw-r--r--app/lib/activitypub/activity/update.rb5
-rw-r--r--app/lib/formatter.rb2
-rw-r--r--app/models/account_statuses_cleanup_policy.rb1
-rw-r--r--app/services/bootstrap_timeline_service.rb2
-rw-r--r--app/services/favourite_service.rb2
-rw-r--r--app/views/about/_logged_in.html.haml10
-rw-r--r--app/views/about/_registration.html.haml28
-rw-r--r--app/views/about/show.html.haml5
-rw-r--r--app/workers/feed_insert_worker.rb2
-rw-r--r--app/workers/poll_expiration_notify_worker.rb8
-rw-r--r--config/locales/en.yml4
-rw-r--r--spec/views/about/show.html.haml_spec.rb1
24 files changed, 66 insertions, 57 deletions
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index 5c47158e0..5134bfb94 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -2,9 +2,9 @@
 
 class Api::V1::AccountsController < Api::BaseController
   before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:create, :follow, :unfollow, :remove_from_followers, :block, :unblock, :mute, :unmute]
-  before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, only: [:follow, :unfollow, :remove_from_followers]
-  before_action -> { doorkeeper_authorize! :follow, :'write:mutes' }, only: [:mute, :unmute]
-  before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, only: [:block, :unblock]
+  before_action -> { doorkeeper_authorize! :follow, :write, :'write:follows' }, only: [:follow, :unfollow, :remove_from_followers]
+  before_action -> { doorkeeper_authorize! :follow, :write, :'write:mutes' }, only: [:mute, :unmute]
+  before_action -> { doorkeeper_authorize! :follow, :write, :'write:blocks' }, only: [:block, :unblock]
   before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create]
 
   before_action :require_user!, except: [:show, :create]
diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb
index 586cdfca9..a65e762c9 100644
--- a/app/controllers/api/v1/blocks_controller.rb
+++ b/app/controllers/api/v1/blocks_controller.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class Api::V1::BlocksController < Api::BaseController
-  before_action -> { doorkeeper_authorize! :follow, :'read:blocks' }
+  before_action -> { doorkeeper_authorize! :follow, :read, :'read:blocks' }
   before_action :require_user!
   after_action :insert_pagination_headers
 
diff --git a/app/controllers/api/v1/domain_blocks_controller.rb b/app/controllers/api/v1/domain_blocks_controller.rb
index 5bb02d834..1891261b9 100644
--- a/app/controllers/api/v1/domain_blocks_controller.rb
+++ b/app/controllers/api/v1/domain_blocks_controller.rb
@@ -3,8 +3,8 @@
 class Api::V1::DomainBlocksController < Api::BaseController
   BLOCK_LIMIT = 100
 
-  before_action -> { doorkeeper_authorize! :follow, :'read:blocks' }, only: :show
-  before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, except: :show
+  before_action -> { doorkeeper_authorize! :follow, :read, :'read:blocks' }, only: :show
+  before_action -> { doorkeeper_authorize! :follow, :write, :'write:blocks' }, except: :show
   before_action :require_user!
   after_action :insert_pagination_headers, only: :show
 
diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb
index f4b2a74d0..54ff0e11d 100644
--- a/app/controllers/api/v1/follow_requests_controller.rb
+++ b/app/controllers/api/v1/follow_requests_controller.rb
@@ -1,8 +1,8 @@
 # frozen_string_literal: true
 
 class Api::V1::FollowRequestsController < Api::BaseController
-  before_action -> { doorkeeper_authorize! :follow, :'read:follows' }, only: :index
-  before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, except: :index
+  before_action -> { doorkeeper_authorize! :follow, :read, :'read:follows' }, only: :index
+  before_action -> { doorkeeper_authorize! :follow, :write, :'write:follows' }, except: :index
   before_action :require_user!
   after_action :insert_pagination_headers, only: :index
 
@@ -13,7 +13,7 @@ class Api::V1::FollowRequestsController < Api::BaseController
 
   def authorize
     AuthorizeFollowService.new.call(account, current_account)
-    NotifyService.new.call(current_account, :follow, Follow.find_by(account: account, target_account: current_account))
+    LocalNotificationWorker.perform_async(current_account.id, Follow.find_by(account: account, target_account: current_account).id, 'Follow', 'follow')
     render json: account, serializer: REST::RelationshipSerializer, relationships: relationships
   end
 
diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb
index 72094790f..f9c935bf3 100644
--- a/app/controllers/api/v1/media_controller.rb
+++ b/app/controllers/api/v1/media_controller.rb
@@ -31,7 +31,7 @@ class Api::V1::MediaController < Api::BaseController
   end
 
   def set_media_attachment
-    @media_attachment = current_account.media_attachments.unattached.find(params[:id])
+    @media_attachment = current_account.media_attachments.where(status_id: nil).find(params[:id])
   end
 
   def check_processing
diff --git a/app/controllers/api/v1/mutes_controller.rb b/app/controllers/api/v1/mutes_controller.rb
index fd52511d7..6cde53a2a 100644
--- a/app/controllers/api/v1/mutes_controller.rb
+++ b/app/controllers/api/v1/mutes_controller.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class Api::V1::MutesController < Api::BaseController
-  before_action -> { doorkeeper_authorize! :follow, :'read:mutes' }
+  before_action -> { doorkeeper_authorize! :follow, :read, :'read:mutes' }
   before_action :require_user!
   after_action :insert_pagination_headers
 
diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js
index 5508adb80..07572c530 100644
--- a/app/javascript/mastodon/features/getting_started/index.js
+++ b/app/javascript/mastodon/features/getting_started/index.js
@@ -7,7 +7,7 @@ import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
-import { me, profile_directory, showTrends } from '../../initial_state';
+import { me, showTrends } from '../../initial_state';
 import { fetchFollowRequests } from 'mastodon/actions/accounts';
 import { List as ImmutableList } from 'immutable';
 import NavigationContainer from '../compose/containers/navigation_container';
@@ -35,7 +35,6 @@ const messages = defineMessages({
   personal: { id: 'navigation_bar.personal', defaultMessage: 'Personal' },
   security: { id: 'navigation_bar.security', defaultMessage: 'Security' },
   menu: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
-  profile_directory: { id: 'getting_started.directory', defaultMessage: 'Profile directory' },
 });
 
 const mapStateToProps = state => ({
@@ -104,25 +103,11 @@ class GettingStarted extends ImmutablePureComponent {
 
       height += 34 + 48*2;
 
-      if (profile_directory) {
-        navItems.push(
-          <ColumnLink key='directory' icon='address-book' text={intl.formatMessage(messages.profile_directory)} to='/directory' />,
-        );
-
-        height += 48;
-      }
-
       navItems.push(
         <ColumnSubheading key='header-personal' text={intl.formatMessage(messages.personal)} />,
       );
 
       height += 34;
-    } else if (profile_directory) {
-      navItems.push(
-        <ColumnLink key='directory' icon='address-book' text={intl.formatMessage(messages.profile_directory)} to='/directory' />,
-      );
-
-      height += 48;
     }
 
     if (multiColumn && !columns.find(item => item.get('id') === 'HOME')) {
diff --git a/app/javascript/mastodon/features/ui/components/link_footer.js b/app/javascript/mastodon/features/ui/components/link_footer.js
index 4a9243c9e..edf1104c4 100644
--- a/app/javascript/mastodon/features/ui/components/link_footer.js
+++ b/app/javascript/mastodon/features/ui/components/link_footer.js
@@ -3,7 +3,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
 import { Link } from 'react-router-dom';
-import { invitesEnabled, limitedFederationMode, version, repository, source_url } from 'mastodon/initial_state';
+import { invitesEnabled, limitedFederationMode, version, repository, source_url, profile_directory as profileDirectory } from 'mastodon/initial_state';
 import { logOut } from 'mastodon/utils/log_out';
 import { openModal } from 'mastodon/actions/modal';
 
@@ -52,6 +52,7 @@ class LinkFooter extends React.PureComponent {
           {withHotkeys && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
           <li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li>
           {!limitedFederationMode && <li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a> · </li>}
+          {profileDirectory && <li><Link to='/directory'><FormattedMessage id='getting_started.directory' defaultMessage='Profile directory' /></Link> · </li>}
           <li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li>
           <li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
           <li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li>
diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.js b/app/javascript/mastodon/features/ui/components/navigation_panel.js
index a70e5ab61..51a0757bc 100644
--- a/app/javascript/mastodon/features/ui/components/navigation_panel.js
+++ b/app/javascript/mastodon/features/ui/components/navigation_panel.js
@@ -2,7 +2,7 @@ import React from 'react';
 import { NavLink, withRouter } from 'react-router-dom';
 import { FormattedMessage } from 'react-intl';
 import Icon from 'mastodon/components/icon';
-import { profile_directory, showTrends } from 'mastodon/initial_state';
+import { showTrends } from 'mastodon/initial_state';
 import NotificationsCounterIcon from './notifications_counter_icon';
 import FollowRequestsNavLink from './follow_requests_nav_link';
 import ListPanel from './list_panel';
@@ -20,7 +20,6 @@ const NavigationPanel = () => (
     <NavLink className='column-link column-link--transparent' to='/favourites'><Icon className='column-link__icon' id='star' fixedWidth /><FormattedMessage id='navigation_bar.favourites' defaultMessage='Favourites' /></NavLink>
     <NavLink className='column-link column-link--transparent' to='/bookmarks'><Icon className='column-link__icon' id='bookmark' fixedWidth /><FormattedMessage id='navigation_bar.bookmarks' defaultMessage='Bookmarks' /></NavLink>
     <NavLink className='column-link column-link--transparent' to='/lists'><Icon className='column-link__icon' id='list-ul' fixedWidth /><FormattedMessage id='navigation_bar.lists' defaultMessage='Lists' /></NavLink>
-    {profile_directory && <NavLink className='column-link column-link--transparent' to='/directory'><Icon className='column-link__icon' id='address-book-o' fixedWidth /><FormattedMessage id='getting_started.directory' defaultMessage='Profile directory' /></NavLink>}
 
     <ListPanel />
 
diff --git a/app/lib/activitypub/activity/announce.rb b/app/lib/activitypub/activity/announce.rb
index 7cd5a41e8..0674b1083 100644
--- a/app/lib/activitypub/activity/announce.rb
+++ b/app/lib/activitypub/activity/announce.rb
@@ -35,7 +35,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
 
   def distribute
     # Notify the author of the original status if that status is local
-    NotifyService.new.call(@status.reblog.account, :reblog, @status) if reblog_of_local_account?(@status) && !reblog_by_following_group_account?(@status)
+    LocalNotificationWorker.perform_async(@status.reblog.account_id, @status.id, 'Status', 'reblog') if reblog_of_local_account?(@status) && !reblog_by_following_group_account?(@status)
 
     # Distribute into home and list feeds
     ::DistributionWorker.perform_async(@status.id) if @options[:override_timestamps] || @status.within_realtime_window?
diff --git a/app/lib/activitypub/activity/follow.rb b/app/lib/activitypub/activity/follow.rb
index 4efb84b8c..97e41ab78 100644
--- a/app/lib/activitypub/activity/follow.rb
+++ b/app/lib/activitypub/activity/follow.rb
@@ -31,10 +31,10 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity
     follow_request = FollowRequest.create!(account: @account, target_account: target_account, uri: @json['id'])
 
     if target_account.locked? || @account.silenced?
-      NotifyService.new.call(target_account, :follow_request, follow_request)
+      LocalNotificationWorker.perform_async(target_account.id, follow_request.id, 'FollowRequest', 'follow_request')
     else
       AuthorizeFollowService.new.call(@account, target_account)
-      NotifyService.new.call(target_account, :follow, ::Follow.find_by(account: @account, target_account: target_account))
+      LocalNotificationWorker.perform_async(target_account.id, ::Follow.find_by(account: @account, target_account: target_account).id, 'Follow', 'follow')
     end
   end
 
diff --git a/app/lib/activitypub/activity/like.rb b/app/lib/activitypub/activity/like.rb
index ebbda15b9..aa1dc3040 100644
--- a/app/lib/activitypub/activity/like.rb
+++ b/app/lib/activitypub/activity/like.rb
@@ -8,7 +8,7 @@ class ActivityPub::Activity::Like < ActivityPub::Activity
 
     favourite = original_status.favourites.create!(account: @account)
 
-    NotifyService.new.call(original_status.account, :favourite, favourite)
+    LocalNotificationWorker.perform_async(original_status.account_id, favourite.id, 'Favourite', 'favourite')
     Trends.statuses.register(original_status)
   end
 end
diff --git a/app/lib/activitypub/activity/update.rb b/app/lib/activitypub/activity/update.rb
index 0bfead55b..36ad5f446 100644
--- a/app/lib/activitypub/activity/update.rb
+++ b/app/lib/activitypub/activity/update.rb
@@ -26,11 +26,6 @@ class ActivityPub::Activity::Update < ActivityPub::Activity
 
     return if @status.nil?
 
-    forwarder.forward! if forwarder.forwardable?
     ActivityPub::ProcessStatusUpdateService.new.call(@status, @object)
   end
-
-  def forwarder
-    @forwarder ||= ActivityPub::Forwarder.new(@account, @json, @status)
-  end
 end
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index 94d149da3..dfa493ed5 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -90,6 +90,8 @@ class Formatter
   end
 
   def simplified_format(account, **options)
+    return '' if account.note.blank?
+
     html = account.local? ? linkify(account.note) : reformat(account.note)
     html = encode_custom_emojis(html, account.emojis, options[:autoplay]) if options[:custom_emojify]
     html.html_safe # rubocop:disable Rails/OutputSafety
diff --git a/app/models/account_statuses_cleanup_policy.rb b/app/models/account_statuses_cleanup_policy.rb
index 0f78c1a54..365123653 100644
--- a/app/models/account_statuses_cleanup_policy.rb
+++ b/app/models/account_statuses_cleanup_policy.rb
@@ -23,6 +23,7 @@ class AccountStatusesCleanupPolicy < ApplicationRecord
   include Redisable
 
   ALLOWED_MIN_STATUS_AGE = [
+    1.week.seconds,
     2.weeks.seconds,
     1.month.seconds,
     2.months.seconds,
diff --git a/app/services/bootstrap_timeline_service.rb b/app/services/bootstrap_timeline_service.rb
index 312c163e4..a02e55a6d 100644
--- a/app/services/bootstrap_timeline_service.rb
+++ b/app/services/bootstrap_timeline_service.rb
@@ -18,7 +18,7 @@ class BootstrapTimelineService < BaseService
 
   def notify_staff!
     User.staff.includes(:account).find_each do |user|
-      NotifyService.new.call(user.account, :'admin.sign_up', @source_account)
+      LocalNotificationWorker.perform_async(user.account_id, @source_account.id, 'Account', 'admin.sign_up')
     end
   end
 end
diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb
index 0ca0081b4..dc7fe8855 100644
--- a/app/services/favourite_service.rb
+++ b/app/services/favourite_service.rb
@@ -31,7 +31,7 @@ class FavouriteService < BaseService
     status = favourite.status
 
     if status.account.local?
-      NotifyService.new.call(status.account, :favourite, favourite)
+      LocalNotificationWorker.perform_async(status.account_id, favourite.id, 'Favourite', 'favourite')
     elsif status.account.activitypub?
       ActivityPub::DeliveryWorker.perform_async(build_json(favourite), favourite.account_id, status.account.inbox_url)
     end
diff --git a/app/views/about/_logged_in.html.haml b/app/views/about/_logged_in.html.haml
new file mode 100644
index 000000000..e1bcfffb3
--- /dev/null
+++ b/app/views/about/_logged_in.html.haml
@@ -0,0 +1,10 @@
+.simple_form
+  %p.lead= t('about.logged_in_as_html', username: content_tag(:strong, current_account.username))
+
+  .actions
+    = link_to t('about.continue_to_web'), root_url, class: 'button button-primary'
+
+.form-footer
+  %ul.no-list
+    %li= link_to t('about.get_apps'), 'https://joinmastodon.org/apps', target: '_blank', rel: 'noopener noreferrer'
+    %li= link_to t('auth.logout'), destroy_user_session_path, data: { method: :delete }
diff --git a/app/views/about/_registration.html.haml b/app/views/about/_registration.html.haml
index e4d614d71..b452e4936 100644
--- a/app/views/about/_registration.html.haml
+++ b/app/views/about/_registration.html.haml
@@ -1,17 +1,20 @@
-.simple_form__overlay-area{ class: (closed_registrations? && @instance_presenter.closed_registrations_message.present?) ? 'simple_form__overlay-area__blurred' : '' }
+- disabled = closed_registrations? || omniauth_only? || current_account.present?
+- show_message = disabled && (current_user.present? || @instance_presenter.closed_registrations_message.present?)
+
+.simple_form__overlay-area{ class: show_message ? 'simple_form__overlay-area__blurred' : '' }
   = simple_form_for(new_user, url: user_registration_path, namespace: 'registration', html: { novalidate: false }) do |f|
     %p.lead= t('about.federation_hint_html', instance: content_tag(:strong, site_hostname))
 
     .fields-group
       = f.simple_fields_for :account do |account_fields|
-        = account_fields.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username'), :autocomplete => 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false, disabled: closed_registrations?
+        = account_fields.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username'), :autocomplete => 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false, disabled: disabled
 
-      = f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?
-      = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'off', :minlength => User.password_length.first, :maxlength => User.password_length.last }, hint: false, disabled: closed_registrations?
-      = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?
+      = f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'off' }, hint: false, disabled: disabled
+      = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'off', :minlength => User.password_length.first, :maxlength => User.password_length.last }, hint: false, disabled: disabled
+      = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'off' }, hint: false, disabled: disabled
 
-      = f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?
-      = f.input :website, as: :url, placeholder: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: 'Website'), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?
+      = f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), :autocomplete => 'off' }, hint: false, disabled: disabled
+      = f.input :website, as: :url, placeholder: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: 'Website'), :autocomplete => 'off' }, hint: false, disabled: disabled
 
     - if approved_registrations?
       .fields-group
@@ -19,13 +22,16 @@
           = invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text
 
     .fields-group
-      = f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.checkbox_agreement_html', rules_path: about_more_path, terms_path: terms_path), required: true, disabled: closed_registrations?
+      = f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.checkbox_agreement_html', rules_path: about_more_path, terms_path: terms_path), required: true, disabled: disabled
 
     .actions
-      = f.button :button, sign_up_message, type: :submit, class: 'button button-primary', disabled: closed_registrations?
+      = f.button :button, sign_up_message, type: :submit, class: 'button button-primary', disabled: disabled
 
-  - if closed_registrations? && @instance_presenter.closed_registrations_message.present?
+  - if show_message
     .simple_form__overlay-area__overlay
       .simple_form__overlay-area__overlay__content.rich-formatting
         .block-icon= fa_icon 'warning'
-        = @instance_presenter.closed_registrations_message.html_safe
+        - if current_account.present?
+          = t('about.logout_before_registering')
+        - else
+          = @instance_presenter.closed_registrations_message.html_safe
diff --git a/app/views/about/show.html.haml b/app/views/about/show.html.haml
index 6ae9e6ae0..321440096 100644
--- a/app/views/about/show.html.haml
+++ b/app/views/about/show.html.haml
@@ -46,7 +46,10 @@
 
     .landing__grid__column.landing__grid__column-login
       .box-widget
-        = render 'login'
+        - if current_user.present?
+          = render 'logged_in'
+        - else
+          = render 'login'
 
       .hero-widget
         .hero-widget__img
diff --git a/app/workers/feed_insert_worker.rb b/app/workers/feed_insert_worker.rb
index b81b09cac..9483510aa 100644
--- a/app/workers/feed_insert_worker.rb
+++ b/app/workers/feed_insert_worker.rb
@@ -74,7 +74,7 @@ class FeedInsertWorker
   end
 
   def perform_notify
-    NotifyService.new.call(@follower, :status, @status)
+    LocalNotificationWorker.perform_async(@follower.id, @status.id, 'Status', 'status')
   end
 
   def update?
diff --git a/app/workers/poll_expiration_notify_worker.rb b/app/workers/poll_expiration_notify_worker.rb
index 7613ed5f1..0e29a5f60 100644
--- a/app/workers/poll_expiration_notify_worker.rb
+++ b/app/workers/poll_expiration_notify_worker.rb
@@ -38,12 +38,14 @@ class PollExpirationNotifyWorker
 
   def notify_remote_voters_and_owner!
     ActivityPub::DistributePollUpdateWorker.perform_async(@poll.status.id)
-    NotifyService.new.call(@poll.account, :poll, @poll)
+    LocalNotificationWorker.perform_async(@poll.account_id, @poll.id, 'Poll', 'poll')
   end
 
   def notify_local_voters!
-    @poll.voters.merge(Account.local).find_each do |account|
-      NotifyService.new.call(account, :poll, @poll)
+    @poll.voters.merge(Account.local).select(:id).find_in_batches do |accounts|
+      LocalNotificationWorker.push_bulk(accounts) do |account|
+        [account.id, @poll.id, 'Poll', 'poll']
+      end
     end
   end
 end
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 6a5594185..2367d5ded 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -16,6 +16,7 @@ en:
     contact: Contact
     contact_missing: Not set
     contact_unavailable: N/A
+    continue_to_web: Continue to web app
     discover_users: Discover users
     documentation: Documentation
     federation_hint_html: With an account on %{instance} you'll be able to follow people on any Mastodon server and beyond.
@@ -25,6 +26,8 @@ en:
       This account is a virtual actor used to represent the server itself and not any individual user.
       It is used for federation purposes and should not be blocked unless you want to block the whole instance, in which case you should use a domain block.
     learn_more: Learn more
+    logged_in_as_html: You are currently logged in as %{username}.
+    logout_before_registering: You are already logged in.
     privacy_policy: Privacy policy
     rules: Server rules
     rules_html: 'Below is a summary of rules you need to follow if you want to have an account on this server of Mastodon:'
@@ -1484,6 +1487,7 @@ en:
       '2629746': 1 month
       '31556952': 1 year
       '5259492': 2 months
+      '604800': 1 week
       '63113904': 2 years
       '7889238': 3 months
     min_age_label: Age threshold
diff --git a/spec/views/about/show.html.haml_spec.rb b/spec/views/about/show.html.haml_spec.rb
index d608bbf5d..140f3fd41 100644
--- a/spec/views/about/show.html.haml_spec.rb
+++ b/spec/views/about/show.html.haml_spec.rb
@@ -10,6 +10,7 @@ describe 'about/show.html.haml', without_verify_partial_doubles: true do
     allow(view).to receive(:site_title).and_return('example site')
     allow(view).to receive(:new_user).and_return(User.new)
     allow(view).to receive(:use_seamless_external_login?).and_return(false)
+    allow(view).to receive(:current_account).and_return(nil)
   end
 
   it 'has valid open graph tags' do