Profile redirect notes (#5746)
* Serialize moved accounts into REST and ActivityPub APIs * Parse federated moved accounts from ActivityPub * Add note about moved accounts to public profiles * Add moved account message to web UI * Fix code style issuesgh/stable
parent
6be72a3ec6
commit
58cede4808
|
@ -7,6 +7,7 @@ import Motion from '../../ui/util/optional_motion';
|
||||||
import spring from 'react-motion/lib/spring';
|
import spring from 'react-motion/lib/spring';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { autoPlayGif, me } from '../../../initial_state';
|
import { autoPlayGif, me } from '../../../initial_state';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||||
|
@ -102,6 +103,10 @@ export default class Header extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (account.get('moved')) {
|
||||||
|
actionBtn = '';
|
||||||
|
}
|
||||||
|
|
||||||
if (account.get('locked')) {
|
if (account.get('locked')) {
|
||||||
lockedIcon = <i className='fa fa-lock' />;
|
lockedIcon = <i className='fa fa-lock' />;
|
||||||
}
|
}
|
||||||
|
@ -110,7 +115,7 @@ export default class Header extends ImmutablePureComponent {
|
||||||
const displayNameHtml = { __html: account.get('display_name_html') };
|
const displayNameHtml = { __html: account.get('display_name_html') };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='account__header' style={{ backgroundImage: `url(${account.get('header')})` }}>
|
<div className={classNames('account__header', { inactive: !!account.get('moved') })} style={{ backgroundImage: `url(${account.get('header')})` }}>
|
||||||
<div>
|
<div>
|
||||||
<Avatar account={account} />
|
<Avatar account={account} />
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import InnerHeader from '../../account/components/header';
|
||||||
import ActionBar from '../../account/components/action_bar';
|
import ActionBar from '../../account/components/action_bar';
|
||||||
import MissingIndicator from '../../../components/missing_indicator';
|
import MissingIndicator from '../../../components/missing_indicator';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import MovedNote from './moved_note';
|
||||||
|
|
||||||
export default class Header extends ImmutablePureComponent {
|
export default class Header extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
@ -68,6 +69,8 @@ export default class Header extends ImmutablePureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='account-timeline__header'>
|
<div className='account-timeline__header'>
|
||||||
|
{account.get('moved') && <MovedNote from={account} to={account.get('moved')} />}
|
||||||
|
|
||||||
<InnerHeader
|
<InnerHeader
|
||||||
account={account}
|
account={account}
|
||||||
onFollow={this.handleFollow}
|
onFollow={this.handleFollow}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import AvatarOverlay from '../../../components/avatar_overlay';
|
||||||
|
import DisplayName from '../../../components/display_name';
|
||||||
|
|
||||||
|
export default class MovedNote extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static contextTypes = {
|
||||||
|
router: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
from: ImmutablePropTypes.map.isRequired,
|
||||||
|
to: ImmutablePropTypes.map.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleAccountClick = e => {
|
||||||
|
if (e.button === 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.context.router.history.push(`/accounts/${this.props.to.get('id')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { from, to } = this.props;
|
||||||
|
const displayNameHtml = { __html: from.get('display_name_html') };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='account__moved-note'>
|
||||||
|
<div className='account__moved-note__message'>
|
||||||
|
<div className='account__moved-note__icon-wrapper'><i className='fa fa-fw fa-suitcase account__moved-note__icon' /></div>
|
||||||
|
<FormattedMessage id='account.moved_to' defaultMessage='{name} has moved to:' values={{ name: <strong dangerouslySetInnerHTML={displayNameHtml} /> }} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href={to.get('url')} onClick={this.handleAccountClick} className='detailed-status__display-name'>
|
||||||
|
<div className='detailed-status__display-avatar'><AvatarOverlay account={to} friend={from} /></div>
|
||||||
|
<DisplayName account={to} />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -59,6 +59,11 @@ const normalizeAccount = (state, account) => {
|
||||||
account.display_name_html = emojify(escapeTextContentForBrowser(displayName));
|
account.display_name_html = emojify(escapeTextContentForBrowser(displayName));
|
||||||
account.note_emojified = emojify(account.note);
|
account.note_emojified = emojify(account.note);
|
||||||
|
|
||||||
|
if (account.moved) {
|
||||||
|
state = normalizeAccount(state, account.moved);
|
||||||
|
account.moved = account.moved.id;
|
||||||
|
}
|
||||||
|
|
||||||
return state.set(account.id, fromJS(account));
|
return state.set(account.id, fromJS(account));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,18 @@ import { List as ImmutableList } from 'immutable';
|
||||||
const getAccountBase = (state, id) => state.getIn(['accounts', id], null);
|
const getAccountBase = (state, id) => state.getIn(['accounts', id], null);
|
||||||
const getAccountCounters = (state, id) => state.getIn(['accounts_counters', id], null);
|
const getAccountCounters = (state, id) => state.getIn(['accounts_counters', id], null);
|
||||||
const getAccountRelationship = (state, id) => state.getIn(['relationships', id], null);
|
const getAccountRelationship = (state, id) => state.getIn(['relationships', id], null);
|
||||||
|
const getAccountMoved = (state, id) => state.getIn(['accounts', state.getIn(['accounts', id, 'moved'])]);
|
||||||
|
|
||||||
export const makeGetAccount = () => {
|
export const makeGetAccount = () => {
|
||||||
return createSelector([getAccountBase, getAccountCounters, getAccountRelationship], (base, counters, relationship) => {
|
return createSelector([getAccountBase, getAccountCounters, getAccountRelationship, getAccountMoved], (base, counters, relationship, moved) => {
|
||||||
if (base === null) {
|
if (base === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.merge(counters).set('relationship', relationship);
|
return base.merge(counters).withMutations(map => {
|
||||||
|
map.set('relationship', relationship);
|
||||||
|
map.set('moved', moved);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -917,6 +917,18 @@
|
||||||
background-position: center;
|
background-position: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
&.inactive {
|
||||||
|
opacity: 0.5;
|
||||||
|
|
||||||
|
.account__header__avatar {
|
||||||
|
filter: grayscale(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.account__header__username {
|
||||||
|
color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
background: rgba(lighten($ui-base-color, 4%), 0.9);
|
background: rgba(lighten($ui-base-color, 4%), 0.9);
|
||||||
padding: 20px 10px;
|
padding: 20px 10px;
|
||||||
|
@ -4375,3 +4387,40 @@ noscript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.account__moved-note {
|
||||||
|
padding: 14px 10px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
background: lighten($ui-base-color, 4%);
|
||||||
|
border-top: 1px solid lighten($ui-base-color, 8%);
|
||||||
|
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
||||||
|
|
||||||
|
&__message {
|
||||||
|
position: relative;
|
||||||
|
margin-left: 58px;
|
||||||
|
color: $ui-base-lighter-color;
|
||||||
|
padding: 8px 0;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon-wrapper {
|
||||||
|
left: -26px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status__display-avatar {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status__display-name {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -34,3 +34,66 @@
|
||||||
.memoriam-strip {
|
.memoriam-strip {
|
||||||
background: rgba($base-shadow-color, 0.7);
|
background: rgba($base-shadow-color, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.moved-strip {
|
||||||
|
padding: 14px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgba(darken($ui-base-color, 7%), 0.8);
|
||||||
|
color: $ui-secondary-color;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
strong,
|
||||||
|
a {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&.mention {
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
span {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus,
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
span {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__message {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
.fa {
|
||||||
|
margin-right: 5px;
|
||||||
|
color: $ui-primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card {
|
||||||
|
.detailed-status__display-avatar {
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detailed-status__display-name {
|
||||||
|
margin-bottom: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: $ui-highlight-color;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
|
||||||
{
|
{
|
||||||
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
|
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
|
||||||
'sensitive' => 'as:sensitive',
|
'sensitive' => 'as:sensitive',
|
||||||
|
'movedTo' => 'as:movedTo',
|
||||||
'Hashtag' => 'as:Hashtag',
|
'Hashtag' => 'as:Hashtag',
|
||||||
'ostatus' => 'http://ostatus.org#',
|
'ostatus' => 'http://ostatus.org#',
|
||||||
'atomUri' => 'ostatus:atomUri',
|
'atomUri' => 'ostatus:atomUri',
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
# followers_url :string default(""), not null
|
# followers_url :string default(""), not null
|
||||||
# protocol :integer default("ostatus"), not null
|
# protocol :integer default("ostatus"), not null
|
||||||
# memorial :boolean default(FALSE), not null
|
# memorial :boolean default(FALSE), not null
|
||||||
|
# moved_to_account_id :integer
|
||||||
#
|
#
|
||||||
|
|
||||||
class Account < ApplicationRecord
|
class Account < ApplicationRecord
|
||||||
|
@ -100,6 +101,9 @@ class Account < ApplicationRecord
|
||||||
has_many :list_accounts, inverse_of: :account, dependent: :destroy
|
has_many :list_accounts, inverse_of: :account, dependent: :destroy
|
||||||
has_many :lists, through: :list_accounts
|
has_many :lists, through: :list_accounts
|
||||||
|
|
||||||
|
# Account migrations
|
||||||
|
belongs_to :moved_to_account, class_name: 'Account'
|
||||||
|
|
||||||
scope :remote, -> { where.not(domain: nil) }
|
scope :remote, -> { where.not(domain: nil) }
|
||||||
scope :local, -> { where(domain: nil) }
|
scope :local, -> { where(domain: nil) }
|
||||||
scope :without_followers, -> { where(followers_count: 0) }
|
scope :without_followers, -> { where(followers_count: 0) }
|
||||||
|
@ -133,6 +137,10 @@ class Account < ApplicationRecord
|
||||||
domain.nil?
|
domain.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def moved?
|
||||||
|
moved_to_account_id.present?
|
||||||
|
end
|
||||||
|
|
||||||
def acct
|
def acct
|
||||||
local? ? username : "#{username}@#{domain}"
|
local? ? username : "#{username}@#{domain}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,8 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer
|
||||||
|
|
||||||
has_one :public_key, serializer: ActivityPub::PublicKeySerializer
|
has_one :public_key, serializer: ActivityPub::PublicKeySerializer
|
||||||
|
|
||||||
|
attribute :moved_to, if: :moved?
|
||||||
|
|
||||||
class EndpointsSerializer < ActiveModel::Serializer
|
class EndpointsSerializer < ActiveModel::Serializer
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
|
|
||||||
|
@ -25,6 +27,8 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer
|
||||||
has_one :icon, serializer: ActivityPub::ImageSerializer, if: :avatar_exists?
|
has_one :icon, serializer: ActivityPub::ImageSerializer, if: :avatar_exists?
|
||||||
has_one :image, serializer: ActivityPub::ImageSerializer, if: :header_exists?
|
has_one :image, serializer: ActivityPub::ImageSerializer, if: :header_exists?
|
||||||
|
|
||||||
|
delegate :moved?, to: :object
|
||||||
|
|
||||||
def id
|
def id
|
||||||
account_url(object)
|
account_url(object)
|
||||||
end
|
end
|
||||||
|
@ -92,4 +96,8 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer
|
||||||
def manually_approves_followers
|
def manually_approves_followers
|
||||||
object.locked
|
object.locked
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def moved_to
|
||||||
|
ActivityPub::TagManager.instance.uri_for(object.moved_to_account)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,10 @@ class REST::AccountSerializer < ActiveModel::Serializer
|
||||||
:note, :url, :avatar, :avatar_static, :header, :header_static,
|
:note, :url, :avatar, :avatar_static, :header, :header_static,
|
||||||
:followers_count, :following_count, :statuses_count
|
:followers_count, :following_count, :statuses_count
|
||||||
|
|
||||||
|
has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved?
|
||||||
|
|
||||||
|
delegate :moved?, to: :object
|
||||||
|
|
||||||
def id
|
def id
|
||||||
object.id.to_s
|
object.id.to_s
|
||||||
end
|
end
|
||||||
|
|
|
@ -74,6 +74,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
@account.statuses_count = outbox_total_items if outbox_total_items.present?
|
@account.statuses_count = outbox_total_items if outbox_total_items.present?
|
||||||
@account.following_count = following_total_items if following_total_items.present?
|
@account.following_count = following_total_items if following_total_items.present?
|
||||||
@account.followers_count = followers_total_items if followers_total_items.present?
|
@account.followers_count = followers_total_items if followers_total_items.present?
|
||||||
|
@account.moved_to_account = moved_account if @json['movedTo'].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_protocol_change!
|
def after_protocol_change!
|
||||||
|
@ -137,6 +138,12 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
@collections[type] = nil
|
@collections[type] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def moved_account
|
||||||
|
account = ActivityPub::TagManager.instance.uri_to_resource(@json['movedTo'], Account)
|
||||||
|
account ||= ActivityPub::FetchRemoteAccountService.new.call(@json['movedTo'], id: true)
|
||||||
|
account
|
||||||
|
end
|
||||||
|
|
||||||
def skip_download?
|
def skip_download?
|
||||||
@account.suspended? || domain_block&.reject_media?
|
@account.suspended? || domain_block&.reject_media?
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
.card.h-card.p-author{ style: "background-image: url(#{account.header.url(:original)})" }
|
.card.h-card.p-author{ style: "background-image: url(#{account.header.url(:original)})" }
|
||||||
.card__illustration
|
.card__illustration
|
||||||
- unless account.memorial?
|
- unless account.memorial? || account.moved?
|
||||||
- if user_signed_in? && current_account.id != account.id && !current_account.requested?(account)
|
- if user_signed_in? && current_account.id != account.id && !current_account.requested?(account)
|
||||||
.controls
|
.controls
|
||||||
- if current_account.following?(account)
|
- if current_account.following?(account)
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
- moved_to_account = account.moved_to_account
|
||||||
|
|
||||||
|
.moved-strip
|
||||||
|
.moved-strip__message
|
||||||
|
= fa_icon 'suitcase'
|
||||||
|
= t('accounts.moved_html', name: content_tag(:strong, display_name(account), class: :emojify), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention'))
|
||||||
|
|
||||||
|
.moved-strip__card
|
||||||
|
= link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
|
||||||
|
.detailed-status__display-avatar
|
||||||
|
.account__avatar-overlay
|
||||||
|
.account__avatar-overlay-base{ style: "background-image: url('#{moved_to_account.avatar.url(:original)}')" }
|
||||||
|
.account__avatar-overlay-overlay{ style: "background-image: url('#{account.avatar.url(:original)}')" }
|
||||||
|
|
||||||
|
%span.display-name
|
||||||
|
%strong.emojify= display_name(moved_to_account)
|
||||||
|
%span @#{moved_to_account.acct}
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
- if @account.memorial?
|
- if @account.memorial?
|
||||||
.memoriam-strip= t('in_memoriam_html')
|
.memoriam-strip= t('in_memoriam_html')
|
||||||
|
- elsif @account.moved?
|
||||||
|
= render partial: 'moved_strip', locals: { account: @account }
|
||||||
- elsif show_landing_strip?
|
- elsif show_landing_strip?
|
||||||
= render partial: 'shared/landing_strip', locals: { account: @account }
|
= render partial: 'shared/landing_strip', locals: { account: @account }
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ en:
|
||||||
followers: Followers
|
followers: Followers
|
||||||
following: Following
|
following: Following
|
||||||
media: Media
|
media: Media
|
||||||
|
moved_html: "%{name} has moved to %{new_profile_link}:"
|
||||||
nothing_here: There is nothing here!
|
nothing_here: There is nothing here!
|
||||||
people_followed_by: People whom %{name} follows
|
people_followed_by: People whom %{name} follows
|
||||||
people_who_follow: People who follow %{name}
|
people_who_follow: People who follow %{name}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
class AddMovedToAccountIdToAccounts < ActiveRecord::Migration[5.1]
|
||||||
|
def change
|
||||||
|
add_column :accounts, :moved_to_account_id, :bigint, null: true, default: nil
|
||||||
|
add_foreign_key :accounts, :accounts, column: :moved_to_account_id, on_delete: :nullify
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20171116161857) do
|
ActiveRecord::Schema.define(version: 20171118012443) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -72,6 +72,7 @@ ActiveRecord::Schema.define(version: 20171116161857) do
|
||||||
t.string "followers_url", default: "", null: false
|
t.string "followers_url", default: "", null: false
|
||||||
t.integer "protocol", default: 0, null: false
|
t.integer "protocol", default: 0, null: false
|
||||||
t.boolean "memorial", default: false, null: false
|
t.boolean "memorial", default: false, null: false
|
||||||
|
t.bigint "moved_to_account_id"
|
||||||
t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin
|
t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin
|
||||||
t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower"
|
t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower"
|
||||||
t.index ["uri"], name: "index_accounts_on_uri"
|
t.index ["uri"], name: "index_accounts_on_uri"
|
||||||
|
@ -486,6 +487,7 @@ ActiveRecord::Schema.define(version: 20171116161857) do
|
||||||
add_foreign_key "account_domain_blocks", "accounts", name: "fk_206c6029bd", on_delete: :cascade
|
add_foreign_key "account_domain_blocks", "accounts", name: "fk_206c6029bd", on_delete: :cascade
|
||||||
add_foreign_key "account_moderation_notes", "accounts"
|
add_foreign_key "account_moderation_notes", "accounts"
|
||||||
add_foreign_key "account_moderation_notes", "accounts", column: "target_account_id"
|
add_foreign_key "account_moderation_notes", "accounts", column: "target_account_id"
|
||||||
|
add_foreign_key "accounts", "accounts", column: "moved_to_account_id", on_delete: :nullify
|
||||||
add_foreign_key "blocks", "accounts", column: "target_account_id", name: "fk_9571bfabc1", on_delete: :cascade
|
add_foreign_key "blocks", "accounts", column: "target_account_id", name: "fk_9571bfabc1", on_delete: :cascade
|
||||||
add_foreign_key "blocks", "accounts", name: "fk_4269e03e65", on_delete: :cascade
|
add_foreign_key "blocks", "accounts", name: "fk_4269e03e65", on_delete: :cascade
|
||||||
add_foreign_key "conversation_mutes", "accounts", name: "fk_225b4212bb", on_delete: :cascade
|
add_foreign_key "conversation_mutes", "accounts", name: "fk_225b4212bb", on_delete: :cascade
|
||||||
|
|
Reference in New Issue