0
0
Fork 0

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 issues
This commit is contained in:
Eugen Rochko 2017-11-18 19:39:02 +01:00 committed by GitHub
parent 6be72a3ec6
commit 58cede4808
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 238 additions and 5 deletions

View file

@ -7,6 +7,7 @@ import Motion from '../../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { autoPlayGif, me } from '../../../initial_state';
import classNames from 'classnames';
const messages = defineMessages({
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')) {
lockedIcon = <i className='fa fa-lock' />;
}
@ -110,7 +115,7 @@ export default class Header extends ImmutablePureComponent {
const displayNameHtml = { __html: account.get('display_name_html') };
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>
<Avatar account={account} />

View file

@ -5,6 +5,7 @@ import InnerHeader from '../../account/components/header';
import ActionBar from '../../account/components/action_bar';
import MissingIndicator from '../../../components/missing_indicator';
import ImmutablePureComponent from 'react-immutable-pure-component';
import MovedNote from './moved_note';
export default class Header extends ImmutablePureComponent {
@ -68,6 +69,8 @@ export default class Header extends ImmutablePureComponent {
return (
<div className='account-timeline__header'>
{account.get('moved') && <MovedNote from={account} to={account.get('moved')} />}
<InnerHeader
account={account}
onFollow={this.handleFollow}

View file

@ -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>
);
}
}

View file

@ -59,6 +59,11 @@ const normalizeAccount = (state, account) => {
account.display_name_html = emojify(escapeTextContentForBrowser(displayName));
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));
};

View file

@ -4,14 +4,18 @@ import { List as ImmutableList } from 'immutable';
const getAccountBase = (state, id) => state.getIn(['accounts', id], null);
const getAccountCounters = (state, id) => state.getIn(['accounts_counters', 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 = () => {
return createSelector([getAccountBase, getAccountCounters, getAccountRelationship], (base, counters, relationship) => {
return createSelector([getAccountBase, getAccountCounters, getAccountRelationship, getAccountMoved], (base, counters, relationship, moved) => {
if (base === null) {
return null;
}
return base.merge(counters).set('relationship', relationship);
return base.merge(counters).withMutations(map => {
map.set('relationship', relationship);
map.set('moved', moved);
});
});
};

View file

@ -917,6 +917,18 @@
background-position: center;
position: relative;
&.inactive {
opacity: 0.5;
.account__header__avatar {
filter: grayscale(100%);
}
.account__header__username {
color: $ui-primary-color;
}
}
& > div {
background: rgba(lighten($ui-base-color, 4%), 0.9);
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;
}
}

View file

@ -34,3 +34,66 @@
.memoriam-strip {
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;
}
}
}
}