Merge branch 'account-fqn' into 'develop'

Make FQN for local accounts configurable

See merge request soapbox-pub/soapbox-fe!471
merge-requests/472/head
Alex Gleason 2021-04-10 21:34:05 +00:00
commit 0b87296c15
11 zmienionych plików z 83 dodań i 26 usunięć

Wyświetl plik

@ -24,6 +24,8 @@ const allowedEmojiRGI = ImmutableList([
'😩', '😩',
]); ]);
const year = new Date().getFullYear();
export const defaultConfig = ImmutableMap({ export const defaultConfig = ImmutableMap({
logo: '', logo: '',
banner: '', banner: '',
@ -34,12 +36,13 @@ export const defaultConfig = ImmutableMap({
}), }),
extensions: ImmutableMap(), extensions: ImmutableMap(),
defaultSettings: ImmutableMap(), defaultSettings: ImmutableMap(),
copyright: '♥2020. Copying is an act of love. Please copy and share.', copyright: `${year}. Copying is an act of love. Please copy and share.`,
navlinks: ImmutableMap({ navlinks: ImmutableMap({
homeFooter: ImmutableList(), homeFooter: ImmutableList(),
}), }),
allowedEmoji: allowedEmoji, allowedEmoji: allowedEmoji,
verifiedCanEditName: false, verifiedCanEditName: false,
displayFqn: true,
}); });
export function getSoapboxConfig(state) { export function getSoapboxConfig(state) {

Wyświetl plik

@ -1,21 +1,31 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import VerificationBadge from './verification_badge'; import VerificationBadge from './verification_badge';
import { acctFull } from '../utils/accounts'; import { getAcct } from '../utils/accounts';
import { List as ImmutableList } from 'immutable'; import { List as ImmutableList } from 'immutable';
import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper'; import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper';
import { displayFqn } from 'soapbox/utils/state';
export default class DisplayName extends React.PureComponent { const mapStateToProps = state => {
return {
displayFqn: displayFqn(state),
};
};
export default @connect(mapStateToProps)
class DisplayName extends React.PureComponent {
static propTypes = { static propTypes = {
account: ImmutablePropTypes.map.isRequired, account: ImmutablePropTypes.map.isRequired,
displayFqn: PropTypes.bool,
others: ImmutablePropTypes.list, others: ImmutablePropTypes.list,
children: PropTypes.node, children: PropTypes.node,
}; };
render() { render() {
const { account, others, children } = this.props; const { account, displayFqn, others, children } = this.props;
let displayName, suffix; let displayName, suffix;
const verified = account.getIn(['pleroma', 'tags'], ImmutableList()).includes('verified'); const verified = account.getIn(['pleroma', 'tags'], ImmutableList()).includes('verified');
@ -38,7 +48,7 @@ export default class DisplayName extends React.PureComponent {
{verified && <VerificationBadge />} {verified && <VerificationBadge />}
</> </>
); );
suffix = <span className='display-name__account'>@{acctFull(account)}</span>; suffix = <span className='display-name__account'>@{getAcct(account, displayFqn)}</span>;
} }
return ( return (

Wyświetl plik

@ -6,13 +6,14 @@ import { injectIntl } from 'react-intl';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import Avatar from 'soapbox/components/avatar'; import Avatar from 'soapbox/components/avatar';
import { acctFull } from 'soapbox/utils/accounts'; import { getAcct } from 'soapbox/utils/accounts';
import { fetchChat, markChatRead } from 'soapbox/actions/chats'; import { fetchChat, markChatRead } from 'soapbox/actions/chats';
import ChatBox from './components/chat_box'; import ChatBox from './components/chat_box';
import Column from 'soapbox/components/column'; import Column from 'soapbox/components/column';
import ColumnBackButton from 'soapbox/components/column_back_button'; import ColumnBackButton from 'soapbox/components/column_back_button';
import { Map as ImmutableMap } from 'immutable'; import { Map as ImmutableMap } from 'immutable';
import { makeGetChat } from 'soapbox/selectors'; import { makeGetChat } from 'soapbox/selectors';
import { displayFqn } from 'soapbox/utils/state';
const mapStateToProps = (state, { params }) => { const mapStateToProps = (state, { params }) => {
const getChat = makeGetChat(); const getChat = makeGetChat();
@ -21,6 +22,7 @@ const mapStateToProps = (state, { params }) => {
return { return {
me: state.get('me'), me: state.get('me'),
chat: getChat(state, chat), chat: getChat(state, chat),
displayFqn: displayFqn(state),
}; };
}; };
@ -32,6 +34,7 @@ class ChatRoom extends ImmutablePureComponent {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
chat: ImmutablePropTypes.map, chat: ImmutablePropTypes.map,
displayFqn: PropTypes.bool,
me: PropTypes.node, me: PropTypes.node,
} }
@ -68,7 +71,7 @@ class ChatRoom extends ImmutablePureComponent {
} }
render() { render() {
const { chat } = this.props; const { chat, displayFqn } = this.props;
if (!chat) return null; if (!chat) return null;
const account = chat.get('account'); const account = chat.get('account');
@ -79,7 +82,7 @@ class ChatRoom extends ImmutablePureComponent {
<Link to={`/@${account.get('acct')}`} className='chatroom__header'> <Link to={`/@${account.get('acct')}`} className='chatroom__header'>
<Avatar account={account} size={18} /> <Avatar account={account} size={18} />
<div className='chatroom__title'> <div className='chatroom__title'>
@{acctFull(account)} @{getAcct(account, displayFqn)}
</div> </div>
</Link> </Link>
</div> </div>

Wyświetl plik

@ -6,7 +6,7 @@ import { injectIntl } from 'react-intl';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import Avatar from 'soapbox/components/avatar'; import Avatar from 'soapbox/components/avatar';
import { acctFull } from 'soapbox/utils/accounts'; import { getAcct } from 'soapbox/utils/accounts';
import IconButton from 'soapbox/components/icon_button'; import IconButton from 'soapbox/components/icon_button';
import { import {
closeChat, closeChat,
@ -14,11 +14,13 @@ import {
} from 'soapbox/actions/chats'; } from 'soapbox/actions/chats';
import ChatBox from './chat_box'; import ChatBox from './chat_box';
import { shortNumberFormat } from 'soapbox/utils/numbers'; import { shortNumberFormat } from 'soapbox/utils/numbers';
import { displayFqn } from 'soapbox/utils/state';
import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper'; import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper';
const mapStateToProps = (state, { pane }) => ({ const mapStateToProps = (state, { pane }) => ({
me: state.get('me'), me: state.get('me'),
chat: state.getIn(['chats', pane.get('chat_id')]), chat: state.getIn(['chats', pane.get('chat_id')]),
displayFqn: displayFqn(state),
}); });
export default @connect(mapStateToProps) export default @connect(mapStateToProps)
@ -32,6 +34,7 @@ class ChatWindow extends ImmutablePureComponent {
idx: PropTypes.number, idx: PropTypes.number,
chat: ImmutablePropTypes.map, chat: ImmutablePropTypes.map,
me: PropTypes.node, me: PropTypes.node,
displayFqn: PropTypes.bool,
} }
state = { state = {
@ -73,7 +76,7 @@ class ChatWindow extends ImmutablePureComponent {
} }
render() { render() {
const { pane, idx, chat } = this.props; const { pane, idx, chat, displayFqn } = this.props;
const account = pane.getIn(['chat', 'account']); const account = pane.getIn(['chat', 'account']);
if (!chat || !account) return null; if (!chat || !account) return null;
@ -99,7 +102,7 @@ class ChatWindow extends ImmutablePureComponent {
<div className='pane__header'> <div className='pane__header'>
{unreadCount > 0 ? unreadIcon : avatar } {unreadCount > 0 ? unreadIcon : avatar }
<button className='pane__title' onClick={this.handleChatToggle(chat.get('id'))}> <button className='pane__title' onClick={this.handleChatToggle(chat.get('id'))}>
@{acctFull(account)} @{getAcct(account, displayFqn)}
</button> </button>
<div className='pane__close'> <div className='pane__close'>
<IconButton icon='close' title='Close chat' onClick={this.handleChatClose(chat.get('id'))} /> <IconButton icon='close' title='Close chat' onClick={this.handleChatClose(chat.get('id'))} />

Wyświetl plik

@ -1,11 +1,18 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import { acctFull } from 'soapbox/utils/accounts'; import { getAcct } from 'soapbox/utils/accounts';
import StillImage from 'soapbox/components/still_image'; import StillImage from 'soapbox/components/still_image';
import VerificationBadge from 'soapbox/components/verification_badge'; import VerificationBadge from 'soapbox/components/verification_badge';
import { List as ImmutableList } from 'immutable'; import { List as ImmutableList } from 'immutable';
import { displayFqn } from 'soapbox/utils/state';
const ProfilePreview = ({ account }) => ( const mapStateToProps = state => ({
displayFqn: displayFqn(state),
});
const ProfilePreview = ({ account, displayFqn }) => (
<div className='card h-card'> <div className='card h-card'>
<a target='_blank' rel='noopener' href={account.get('url')}> <a target='_blank' rel='noopener' href={account.get('url')}>
<div className='card__img'> <div className='card__img'>
@ -23,7 +30,7 @@ const ProfilePreview = ({ account }) => (
{account.getIn(['pleroma', 'tags'], ImmutableList()).includes('verified') && <VerificationBadge />} {account.getIn(['pleroma', 'tags'], ImmutableList()).includes('verified') && <VerificationBadge />}
</strong> </strong>
</bdi> </bdi>
<span>{acctFull(account)}</span> <span>@{getAcct(account, displayFqn)}</span>
</div> </div>
</div> </div>
</a> </a>
@ -32,6 +39,7 @@ const ProfilePreview = ({ account }) => (
ProfilePreview.propTypes = { ProfilePreview.propTypes = {
account: ImmutablePropTypes.map, account: ImmutablePropTypes.map,
displayFqn: PropTypes.bool,
}; };
export default ProfilePreview; export default connect(mapStateToProps)(ProfilePreview);

Wyświetl plik

@ -41,6 +41,7 @@ const messages = defineMessages({
rawJSONLabel: { id: 'soapbox_config.raw_json_label', defaultMessage: 'Advanced: Edit raw JSON data' }, rawJSONLabel: { id: 'soapbox_config.raw_json_label', defaultMessage: 'Advanced: Edit raw JSON data' },
rawJSONHint: { id: 'soapbox_config.raw_json_hint', defaultMessage: 'Edit the settings data directly. Changes made directly to the JSON file will override the form fields above. Click "Save" to apply your changes.' }, rawJSONHint: { id: 'soapbox_config.raw_json_hint', defaultMessage: 'Edit the settings data directly. Changes made directly to the JSON file will override the form fields above. Click "Save" to apply your changes.' },
verifiedCanEditNameLabel: { id: 'soapbox_config.verified_can_edit_name_label', defaultMessage: 'Allow verified users to edit their own display name.' }, verifiedCanEditNameLabel: { id: 'soapbox_config.verified_can_edit_name_label', defaultMessage: 'Allow verified users to edit their own display name.' },
displayFqnLabel: { id: 'soapbox_config.display_fqn_label', defaultMessage: 'Display domain even for local accounts.' },
}); });
const listenerOptions = supportsPassiveEvents ? { passive: true } : false; const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
@ -241,6 +242,12 @@ class SoapboxConfig extends ImmutablePureComponent {
checked={soapbox.get('verifiedCanEditName') === true} checked={soapbox.get('verifiedCanEditName') === true}
onChange={this.handleChange(['verifiedCanEditName'], (e) => e.target.checked)} onChange={this.handleChange(['verifiedCanEditName'], (e) => e.target.checked)}
/> />
<Checkbox
name='verifiedCanEditName'
label={intl.formatMessage(messages.displayFqnLabel)}
checked={soapbox.get('displayFqn') === true}
onChange={this.handleChange(['displayFqn'], (e) => e.target.checked)}
/>
</FieldsGroup> </FieldsGroup>
<FieldsGroup> <FieldsGroup>
<div className='input with_block_label popup'> <div className='input with_block_label popup'>

Wyświetl plik

@ -10,7 +10,8 @@ import Icon from 'soapbox/components/icon';
import VerificationBadge from 'soapbox/components/verification_badge'; import VerificationBadge from 'soapbox/components/verification_badge';
import Badge from 'soapbox/components/badge'; import Badge from 'soapbox/components/badge';
import { List as ImmutableList } from 'immutable'; import { List as ImmutableList } from 'immutable';
import { acctFull, isAdmin, isModerator } from 'soapbox/utils/accounts'; import { getAcct, isAdmin, isModerator } from 'soapbox/utils/accounts';
import { displayFqn } from 'soapbox/utils/state';
import classNames from 'classnames'; import classNames from 'classnames';
const messages = defineMessages({ const messages = defineMessages({
@ -36,10 +37,11 @@ class ProfileInfoPanel extends ImmutablePureComponent {
identity_proofs: ImmutablePropTypes.list, identity_proofs: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
username: PropTypes.string, username: PropTypes.string,
displayFqn: PropTypes.bool,
}; };
render() { render() {
const { account, intl, identity_proofs, username } = this.props; const { account, displayFqn, intl, identity_proofs, username } = this.props;
if (!account) { if (!account) {
return ( return (
@ -73,7 +75,7 @@ class ProfileInfoPanel extends ImmutablePureComponent {
<span dangerouslySetInnerHTML={displayNameHtml} className='profile-info-panel__name-content' /> <span dangerouslySetInnerHTML={displayNameHtml} className='profile-info-panel__name-content' />
{verified && <VerificationBadge />} {verified && <VerificationBadge />}
{account.get('bot') && <Badge slug='bot' title={intl.formatMessage(messages.bot)} />} {account.get('bot') && <Badge slug='bot' title={intl.formatMessage(messages.bot)} />}
{ <small>@{acctFull(account)} {lockedIcon}</small> } { <small>@{getAcct(account, displayFqn)} {lockedIcon}</small> }
</h1> </h1>
</div> </div>
@ -144,6 +146,7 @@ const mapStateToProps = (state, { account }) => {
return { return {
identity_proofs, identity_proofs,
domain: state.getIn(['meta', 'domain']), domain: state.getIn(['meta', 'domain']),
displayFqn: displayFqn(state),
}; };
}; };

Wyświetl plik

@ -8,7 +8,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import Avatar from 'soapbox/components/avatar'; import Avatar from 'soapbox/components/avatar';
import { shortNumberFormat } from 'soapbox/utils/numbers'; import { shortNumberFormat } from 'soapbox/utils/numbers';
import { acctFull } from 'soapbox/utils/accounts'; import { getAcct } from 'soapbox/utils/accounts';
import { displayFqn } from 'soapbox/utils/state';
import StillImage from 'soapbox/components/still_image'; import StillImage from 'soapbox/components/still_image';
import VerificationBadge from 'soapbox/components/verification_badge'; import VerificationBadge from 'soapbox/components/verification_badge';
import { List as ImmutableList } from 'immutable'; import { List as ImmutableList } from 'immutable';
@ -17,12 +18,13 @@ class UserPanel extends ImmutablePureComponent {
static propTypes = { static propTypes = {
account: ImmutablePropTypes.map, account: ImmutablePropTypes.map,
displayFqn: PropTypes.bool,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
domain: PropTypes.string, domain: PropTypes.string,
} }
render() { render() {
const { account, intl, domain } = this.props; const { account, displayFqn, intl, domain } = this.props;
if (!account) return null; if (!account) return null;
const displayNameHtml = { __html: account.get('display_name_html') }; const displayNameHtml = { __html: account.get('display_name_html') };
const acct = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct'); const acct = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct');
@ -49,7 +51,7 @@ class UserPanel extends ImmutablePureComponent {
<Link to={`/@${account.get('acct')}`}> <Link to={`/@${account.get('acct')}`}>
<span className='user-panel__account__name' dangerouslySetInnerHTML={displayNameHtml} /> <span className='user-panel__account__name' dangerouslySetInnerHTML={displayNameHtml} />
{verified && <VerificationBadge />} {verified && <VerificationBadge />}
<small className='user-panel__account__username'>@{acctFull(account)}</small> <small className='user-panel__account__username'>@{getAcct(account, displayFqn)}</small>
</Link> </Link>
</h1> </h1>
</div> </div>
@ -93,6 +95,7 @@ const makeMapStateToProps = () => {
const mapStateToProps = (state, { accountId }) => ({ const mapStateToProps = (state, { accountId }) => ({
account: getAccount(state, accountId), account: getAccount(state, accountId),
displayFqn: displayFqn(state),
}); });
return mapStateToProps; return mapStateToProps;

Wyświetl plik

@ -10,7 +10,8 @@ import LinkFooter from '../features/ui/components/link_footer';
import SignUpPanel from '../features/ui/components/sign_up_panel'; import SignUpPanel from '../features/ui/components/sign_up_panel';
import ProfileInfoPanel from '../features/ui/components/profile_info_panel'; import ProfileInfoPanel from '../features/ui/components/profile_info_panel';
import ProfileMediaPanel from '../features/ui/components/profile_media_panel'; import ProfileMediaPanel from '../features/ui/components/profile_media_panel';
import { acctFull } from 'soapbox/utils/accounts'; import { getAcct } from 'soapbox/utils/accounts';
import { displayFqn } from 'soapbox/utils/state';
import { getFeatures } from 'soapbox/utils/features'; import { getFeatures } from 'soapbox/utils/features';
import { makeGetAccount } from '../selectors'; import { makeGetAccount } from '../selectors';
import { Redirect } from 'react-router-dom'; import { Redirect } from 'react-router-dom';
@ -47,6 +48,7 @@ const mapStateToProps = (state, { params: { username }, withReplies = false }) =
accountUsername, accountUsername,
features: getFeatures(state.get('instance')), features: getFeatures(state.get('instance')),
realAccount, realAccount,
displayFqn: displayFqn(state),
}; };
}; };
@ -56,11 +58,12 @@ class ProfilePage extends ImmutablePureComponent {
static propTypes = { static propTypes = {
account: ImmutablePropTypes.map, account: ImmutablePropTypes.map,
accountUsername: PropTypes.string.isRequired, accountUsername: PropTypes.string.isRequired,
displayFqn: PropTypes.bool,
features: PropTypes.object, features: PropTypes.object,
}; };
render() { render() {
const { children, accountId, account, accountUsername, features, realAccount } = this.props; const { children, accountId, account, displayFqn, accountUsername, features, realAccount } = this.props;
const bg = account ? account.getIn(['customizations', 'background']) : undefined; const bg = account ? account.getIn(['customizations', 'background']) : undefined;
if (realAccount) { if (realAccount) {
@ -70,7 +73,7 @@ class ProfilePage extends ImmutablePureComponent {
return ( return (
<div className={bg && `page page--customization page--${bg}` || 'page'}> <div className={bg && `page page--customization page--${bg}` || 'page'}>
{account && <Helmet> {account && <Helmet>
<title>@{acctFull(account)}</title> <title>@{getAcct(account, displayFqn)}</title>
</Helmet>} </Helmet>}
<div className='page__top'> <div className='page__top'>

Wyświetl plik

@ -16,13 +16,21 @@ export const getDomain = account => {
return domain; return domain;
}; };
// user@domain even for local users export const guessFqn = account => {
export const acctFull = account => {
const [user, domain] = account.get('acct').split('@'); const [user, domain] = account.get('acct').split('@');
if (!domain) return [user, guessDomain(account)].join('@'); if (!domain) return [user, guessDomain(account)].join('@');
return account.get('acct'); return account.get('acct');
}; };
// user@domain even for local users
export const acctFull = account => (
account.get('fqn') || guessFqn(account)
);
export const getAcct = (account, displayFqn) => (
displayFqn === true ? acctFull(account) : account.get('acct')
);
export const isStaff = (account = ImmutableMap()) => ( export const isStaff = (account = ImmutableMap()) => (
[isAdmin, isModerator].some(f => f(account) === true) [isAdmin, isModerator].some(f => f(account) === true)
); );

Wyświetl plik

@ -0,0 +1,6 @@
import { getSoapboxConfig } from'soapbox/actions/soapbox';
export const displayFqn = state => {
const soapbox = getSoapboxConfig(state);
return soapbox.get('displayFqn');
};