diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index 5c47158e02..5134bfb94a 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 586cdfca9d..a65e762c9f 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 5bb02d834c..1891261b9c 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 f4b2a74d0a..54ff0e11d0 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 72094790fd..f9c935bf3e 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 fd52511d7e..6cde53a2a7 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 5508adb80e..07572c530d 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(
- ,
- );
-
- height += 48;
- }
-
navItems.push(
,
);
height += 34;
- } else if (profile_directory) {
- navItems.push(
- ,
- );
-
- 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 4a9243c9e1..edf1104c4e 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 &&
· }
·
{!limitedFederationMode && · }
+ {profileDirectory && · }
·
·
·
diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.js b/app/javascript/mastodon/features/ui/components/navigation_panel.js
index a70e5ab61c..51a0757bcf 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 = () => (
- {profile_directory && }
diff --git a/app/lib/activitypub/activity/announce.rb b/app/lib/activitypub/activity/announce.rb
index 7cd5a41e8e..0674b10833 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 4efb84b8c9..97e41ab789 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 ebbda15b9f..aa1dc30403 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 0bfead55b2..36ad5f4465 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 94d149da37..dfa493ed5e 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 0f78c1a546..3651236531 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 312c163e47..a02e55a6df 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 0ca0081b48..dc7fe88552 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 0000000000..e1bcfffb31
--- /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 e4d614d71e..b452e49368 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 6ae9e6ae07..3214400960 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 b81b09cac6..9483510aaf 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 7613ed5f15..0e29a5f60b 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 6a55941858..2367d5ded4 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 d608bbf5d3..140f3fd41c 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