mirror of
https://git.kescher.at/CatCatNya/catstodon.git
synced 2024-11-25 09:48:06 +01:00
Merge commit 'de4815afda0809bf999519aabda1cd14c67278da' into glitch-soc/merge-upstream
This commit is contained in:
commit
e46321e63d
88 changed files with 1116 additions and 361 deletions
|
@ -4,6 +4,6 @@ class Api::V1::Apps::CredentialsController < Api::BaseController
|
|||
def show
|
||||
return doorkeeper_render_error unless valid_doorkeeper_token?
|
||||
|
||||
render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key client_id scopes)
|
||||
render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ class Api::V1::AppsController < Api::BaseController
|
|||
|
||||
def create
|
||||
@app = Doorkeeper::Application.create!(application_options)
|
||||
render json: @app, serializer: REST::ApplicationSerializer
|
||||
render json: @app, serializer: REST::CredentialApplicationSerializer
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -24,6 +24,6 @@ class Api::V1::AppsController < Api::BaseController
|
|||
end
|
||||
|
||||
def app_params
|
||||
params.permit(:client_name, :redirect_uris, :scopes, :website)
|
||||
params.permit(:client_name, :scopes, :website, :redirect_uris, redirect_uris: [])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,8 +14,10 @@ import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
|||
import SettingsIcon from '@/material-icons/400-24px/settings.svg?react';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
|
||||
import { useAppHistory } from './router';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -51,12 +53,8 @@ BackButton.propTypes = {
|
|||
};
|
||||
|
||||
class ColumnHeader extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
intl: PropTypes.object.isRequired,
|
||||
title: PropTypes.node,
|
||||
icon: PropTypes.string,
|
||||
|
@ -171,7 +169,7 @@ class ColumnHeader extends PureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
if (this.context.identity.signedIn && (children || (multiColumn && this.props.onPin))) {
|
||||
if (this.props.identity.signedIn && (children || (multiColumn && this.props.onPin))) {
|
||||
collapseButton = (
|
||||
<button
|
||||
className={collapsibleButtonClassName}
|
||||
|
@ -232,4 +230,4 @@ class ColumnHeader extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default injectIntl(withRouter(ColumnHeader));
|
||||
export default injectIntl(withIdentity(withRouter(ColumnHeader)));
|
||||
|
|
|
@ -14,6 +14,7 @@ import CheckIcon from '@/material-icons/400-24px/check.svg?react';
|
|||
import { Icon } from 'mastodon/components/icon';
|
||||
import emojify from 'mastodon/features/emoji/emoji';
|
||||
import Motion from 'mastodon/features/ui/util/optional_motion';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import { RelativeTimestamp } from './relative_timestamp';
|
||||
|
||||
|
@ -38,12 +39,8 @@ const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
|
|||
}, {});
|
||||
|
||||
class Poll extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
poll: ImmutablePropTypes.map,
|
||||
lang: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
|
@ -235,7 +232,7 @@ class Poll extends ImmutablePureComponent {
|
|||
</ul>
|
||||
|
||||
<div className='poll__footer'>
|
||||
{!showResults && <button className='button button-secondary' disabled={disabled || !this.context.identity.signedIn} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}
|
||||
{!showResults && <button className='button button-secondary' disabled={disabled || !this.props.identity.signedIn} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}
|
||||
{!showResults && <><button className='poll__link' onClick={this.handleReveal}><FormattedMessage id='poll.reveal' defaultMessage='See results' /></button> · </>}
|
||||
{showResults && !this.props.disabled && <><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </>}
|
||||
{votesCount}
|
||||
|
@ -247,4 +244,4 @@ class Poll extends ImmutablePureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default injectIntl(Poll);
|
||||
export default injectIntl(withIdentity(Poll));
|
||||
|
|
|
@ -22,6 +22,7 @@ import RepeatActiveIcon from '@/svg-icons/repeat_active.svg?react';
|
|||
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
||||
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
||||
import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.svg?react';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
|
@ -74,12 +75,8 @@ const mapStateToProps = (state, { status }) => ({
|
|||
});
|
||||
|
||||
class StatusActionBar extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
relationship: ImmutablePropTypes.record,
|
||||
onReply: PropTypes.func,
|
||||
|
@ -118,7 +115,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
];
|
||||
|
||||
handleReplyClick = () => {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
this.props.onReply(this.props.status, this.props.history);
|
||||
|
@ -136,7 +133,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
};
|
||||
|
||||
handleFavouriteClick = () => {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
this.props.onFavourite(this.props.status);
|
||||
|
@ -146,7 +143,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
};
|
||||
|
||||
handleReblogClick = e => {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
this.props.onReblog(this.props.status, e);
|
||||
|
@ -250,7 +247,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
|
||||
render () {
|
||||
const { status, relationship, intl, withDismiss, withCounters, scrollKey } = this.props;
|
||||
const { signedIn, permissions } = this.context.identity;
|
||||
const { signedIn, permissions } = this.props.identity;
|
||||
|
||||
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
|
||||
const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility'));
|
||||
|
@ -410,4 +407,4 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(injectIntl(StatusActionBar)));
|
||||
export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusActionBar))));
|
||||
|
|
|
@ -12,8 +12,10 @@ import { connect } from 'react-redux';
|
|||
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import PollContainer from 'mastodon/containers/poll_container';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';
|
||||
|
||||
|
||||
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
|
||||
|
||||
/**
|
||||
|
@ -67,12 +69,8 @@ const mapStateToProps = state => ({
|
|||
});
|
||||
|
||||
class StatusContent extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
statusContent: PropTypes.string,
|
||||
expanded: PropTypes.bool,
|
||||
|
@ -245,7 +243,7 @@ class StatusContent extends PureComponent {
|
|||
const renderReadMore = this.props.onClick && status.get('collapsed');
|
||||
const contentLocale = intl.locale.replace(/[_-].*/, '');
|
||||
const targetLanguages = this.props.languages?.get(status.get('language') || 'und');
|
||||
const renderTranslate = this.props.onTranslate && this.context.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale);
|
||||
const renderTranslate = this.props.onTranslate && this.props.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale);
|
||||
|
||||
const content = { __html: statusContent ?? getStatusContent(status) };
|
||||
const spoilerContent = { __html: status.getIn(['translation', 'spoilerHtml']) || status.get('spoilerHtml') };
|
||||
|
@ -328,4 +326,4 @@ class StatusContent extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(injectIntl(StatusContent)));
|
||||
export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusContent))));
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
|
@ -14,6 +13,7 @@ import { connectUserStream } from 'mastodon/actions/streaming';
|
|||
import ErrorBoundary from 'mastodon/components/error_boundary';
|
||||
import { Router } from 'mastodon/components/router';
|
||||
import UI from 'mastodon/features/ui';
|
||||
import { IdentityContext, createIdentityContext } from 'mastodon/identity_context';
|
||||
import initialState, { title as siteTitle } from 'mastodon/initial_state';
|
||||
import { IntlProvider } from 'mastodon/locales';
|
||||
import { store } from 'mastodon/store';
|
||||
|
@ -28,33 +28,9 @@ if (initialState.meta.me) {
|
|||
store.dispatch(fetchCustomEmojis());
|
||||
}
|
||||
|
||||
const createIdentityContext = state => ({
|
||||
signedIn: !!state.meta.me,
|
||||
accountId: state.meta.me,
|
||||
disabledAccountId: state.meta.disabled_account_id,
|
||||
accessToken: state.meta.access_token,
|
||||
permissions: state.role ? state.role.permissions : 0,
|
||||
});
|
||||
|
||||
export default class Mastodon extends PureComponent {
|
||||
|
||||
static childContextTypes = {
|
||||
identity: PropTypes.shape({
|
||||
signedIn: PropTypes.bool.isRequired,
|
||||
accountId: PropTypes.string,
|
||||
disabledAccountId: PropTypes.string,
|
||||
accessToken: PropTypes.string,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
identity = createIdentityContext(initialState);
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
identity: this.identity,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.identity.signedIn) {
|
||||
this.disconnect = store.dispatch(connectUserStream());
|
||||
|
@ -74,19 +50,21 @@ export default class Mastodon extends PureComponent {
|
|||
|
||||
render () {
|
||||
return (
|
||||
<IntlProvider>
|
||||
<ReduxProvider store={store}>
|
||||
<ErrorBoundary>
|
||||
<Router>
|
||||
<ScrollContext shouldUpdateScroll={this.shouldUpdateScroll}>
|
||||
<Route path='/' component={UI} />
|
||||
</ScrollContext>
|
||||
</Router>
|
||||
<IdentityContext.Provider value={this.identity}>
|
||||
<IntlProvider>
|
||||
<ReduxProvider store={store}>
|
||||
<ErrorBoundary>
|
||||
<Router>
|
||||
<ScrollContext shouldUpdateScroll={this.shouldUpdateScroll}>
|
||||
<Route path='/' component={UI} />
|
||||
</ScrollContext>
|
||||
</Router>
|
||||
|
||||
<Helmet defaultTitle={title} titleTemplate={`%s - ${title}`} />
|
||||
</ErrorBoundary>
|
||||
</ReduxProvider>
|
||||
</IntlProvider>
|
||||
<Helmet defaultTitle={title} titleTemplate={`%s - ${title}`} />
|
||||
</ErrorBoundary>
|
||||
</ReduxProvider>
|
||||
</IntlProvider>
|
||||
</IdentityContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import { IconButton } from 'mastodon/components/icon_button';
|
|||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import { ShortNumber } from 'mastodon/components/short_number';
|
||||
import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { autoPlayGif, me, domain as localDomain } from 'mastodon/initial_state';
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
@ -111,6 +112,7 @@ const dateFormatOptions = {
|
|||
class Header extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
account: ImmutablePropTypes.record,
|
||||
identity_props: ImmutablePropTypes.list,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
|
@ -136,10 +138,6 @@ class Header extends ImmutablePureComponent {
|
|||
...WithRouterPropTypes,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
};
|
||||
|
@ -255,7 +253,7 @@ class Header extends ImmutablePureComponent {
|
|||
|
||||
render () {
|
||||
const { account, hidden, intl } = this.props;
|
||||
const { signedIn, permissions } = this.context.identity;
|
||||
const { signedIn, permissions } = this.props.identity;
|
||||
|
||||
if (!account) {
|
||||
return null;
|
||||
|
@ -516,4 +514,4 @@ class Header extends ImmutablePureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default withRouter(injectIntl(Header));
|
||||
export default withRouter(withIdentity(injectIntl(Header)));
|
||||
|
|
|
@ -9,6 +9,7 @@ import { connect } from 'react-redux';
|
|||
|
||||
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
|
||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { domain } from 'mastodon/initial_state';
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
|
@ -38,16 +39,12 @@ const mapStateToProps = (state, { columnId }) => {
|
|||
};
|
||||
|
||||
class CommunityTimeline extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
|
@ -77,7 +74,7 @@ class CommunityTimeline extends PureComponent {
|
|||
|
||||
componentDidMount () {
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
dispatch(expandCommunityTimeline({ onlyMedia }));
|
||||
|
||||
|
@ -87,7 +84,7 @@ class CommunityTimeline extends PureComponent {
|
|||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (prevProps.onlyMedia !== this.props.onlyMedia) {
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
@ -161,4 +158,4 @@ class CommunityTimeline extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(CommunityTimeline));
|
||||
export default withIdentity(connect(mapStateToProps)(injectIntl(CommunityTimeline)));
|
||||
|
|
|
@ -12,6 +12,7 @@ import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react';
|
|||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { domain, searchEnabled } from 'mastodon/initial_state';
|
||||
import { HASHTAG_REGEX } from 'mastodon/utils/hashtags';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
@ -33,12 +34,8 @@ const labelForRecentSearch = search => {
|
|||
};
|
||||
|
||||
class Search extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
value: PropTypes.string.isRequired,
|
||||
recent: ImmutablePropTypes.orderedSet,
|
||||
submitted: PropTypes.bool,
|
||||
|
@ -276,7 +273,7 @@ class Search extends PureComponent {
|
|||
}
|
||||
|
||||
_calculateOptions (value) {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
const trimmedValue = value.trim();
|
||||
const options = [];
|
||||
|
||||
|
@ -318,7 +315,7 @@ class Search extends PureComponent {
|
|||
render () {
|
||||
const { intl, value, submitted, recent } = this.props;
|
||||
const { expanded, options, selectedOption } = this.state;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
const hasValue = value.length > 0 || submitted;
|
||||
|
||||
|
@ -402,4 +399,4 @@ class Search extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default withRouter(injectIntl(Search));
|
||||
export default withRouter(withIdentity(injectIntl(Search)));
|
||||
|
|
|
@ -13,6 +13,7 @@ import SearchIcon from '@/material-icons/400-24px/search.svg?react';
|
|||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import Search from 'mastodon/features/compose/containers/search_container';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { trendsEnabled } from 'mastodon/initial_state';
|
||||
|
||||
import Links from './links';
|
||||
|
@ -32,12 +33,8 @@ const mapStateToProps = state => ({
|
|||
});
|
||||
|
||||
class Explore extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
intl: PropTypes.object.isRequired,
|
||||
multiColumn: PropTypes.bool,
|
||||
isSearching: PropTypes.bool,
|
||||
|
@ -53,7 +50,7 @@ class Explore extends PureComponent {
|
|||
|
||||
render() {
|
||||
const { intl, multiColumn, isSearching } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
|
||||
|
@ -114,4 +111,4 @@ class Explore extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(Explore));
|
||||
export default withIdentity(connect(mapStateToProps)(injectIntl(Explore)));
|
||||
|
|
|
@ -6,13 +6,14 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
|||
import { Helmet } from 'react-helmet';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
import { useIdentity } from '@/mastodon/identity_context';
|
||||
import PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
||||
import { addColumn } from 'mastodon/actions/columns';
|
||||
import { changeSetting } from 'mastodon/actions/settings';
|
||||
import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming';
|
||||
import { expandPublicTimeline, expandCommunityTimeline } from 'mastodon/actions/timelines';
|
||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
||||
import initialState, { domain } from 'mastodon/initial_state';
|
||||
import { domain } from 'mastodon/initial_state';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
import Column from '../../components/column';
|
||||
|
@ -24,15 +25,6 @@ const messages = defineMessages({
|
|||
title: { id: 'column.firehose', defaultMessage: 'Live feeds' },
|
||||
});
|
||||
|
||||
// TODO: use a proper React context later on
|
||||
const useIdentity = () => ({
|
||||
signedIn: !!initialState.meta.me,
|
||||
accountId: initialState.meta.me,
|
||||
disabledAccountId: initialState.meta.disabled_account_id,
|
||||
accessToken: initialState.meta.access_token,
|
||||
permissions: initialState.role ? initialState.role.permissions : 0,
|
||||
});
|
||||
|
||||
const ColumnSettings = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const settings = useAppSelector((state) => state.getIn(['settings', 'firehose']));
|
||||
|
|
|
@ -24,6 +24,7 @@ import { fetchFollowRequests } from 'mastodon/actions/accounts';
|
|||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import LinkFooter from 'mastodon/features/ui/components/link_footer';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import { me, showTrends } from '../../initial_state';
|
||||
import { NavigationBar } from '../compose/components/navigation_bar';
|
||||
|
@ -75,12 +76,8 @@ const badgeDisplay = (number, limit) => {
|
|||
};
|
||||
|
||||
class GettingStarted extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
intl: PropTypes.object.isRequired,
|
||||
myAccount: ImmutablePropTypes.record,
|
||||
multiColumn: PropTypes.bool,
|
||||
|
@ -91,7 +88,7 @@ class GettingStarted extends ImmutablePureComponent {
|
|||
|
||||
componentDidMount () {
|
||||
const { fetchFollowRequests } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (!signedIn) {
|
||||
return;
|
||||
|
@ -102,7 +99,7 @@ class GettingStarted extends ImmutablePureComponent {
|
|||
|
||||
render () {
|
||||
const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
const navItems = [];
|
||||
|
||||
|
@ -167,4 +164,4 @@ class GettingStarted extends ImmutablePureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(GettingStarted));
|
||||
export default withIdentity(connect(mapStateToProps, mapDispatchToProps)(injectIntl(GettingStarted)));
|
||||
|
|
|
@ -17,6 +17,7 @@ import { fetchHashtag, followHashtag, unfollowHashtag } from 'mastodon/actions/t
|
|||
import { expandHashtagTimeline, clearTimeline } from 'mastodon/actions/timelines';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
|
||||
|
@ -29,14 +30,10 @@ const mapStateToProps = (state, props) => ({
|
|||
});
|
||||
|
||||
class HashtagTimeline extends PureComponent {
|
||||
|
||||
disconnects = [];
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
params: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
|
@ -94,7 +91,7 @@ class HashtagTimeline extends PureComponent {
|
|||
};
|
||||
|
||||
_subscribe (dispatch, id, tags = {}, local) {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (!signedIn) {
|
||||
return;
|
||||
|
@ -168,7 +165,7 @@ class HashtagTimeline extends PureComponent {
|
|||
handleFollow = () => {
|
||||
const { dispatch, params, tag } = this.props;
|
||||
const { id } = params;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (!signedIn) {
|
||||
return;
|
||||
|
@ -185,7 +182,7 @@ class HashtagTimeline extends PureComponent {
|
|||
const { hasUnread, columnId, multiColumn, tag } = this.props;
|
||||
const { id, local } = this.props.params;
|
||||
const pinned = !!columnId;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={`#${id}`}>
|
||||
|
@ -225,4 +222,4 @@ class HashtagTimeline extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(HashtagTimeline);
|
||||
export default connect(mapStateToProps)(withIdentity(HashtagTimeline));
|
||||
|
|
|
@ -14,6 +14,7 @@ import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/an
|
|||
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
|
||||
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
|
||||
import AnnouncementsContainer from 'mastodon/features/getting_started/containers/announcements_container';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { criticalUpdatesPending } from 'mastodon/initial_state';
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
|
@ -40,12 +41,8 @@ const mapStateToProps = state => ({
|
|||
});
|
||||
|
||||
class HomeTimeline extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
|
@ -126,7 +123,7 @@ class HomeTimeline extends PureComponent {
|
|||
render () {
|
||||
const { intl, hasUnread, columnId, multiColumn, hasAnnouncements, unreadAnnouncements, showAnnouncements } = this.props;
|
||||
const pinned = !!columnId;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
const banners = [];
|
||||
|
||||
let announcementsButton;
|
||||
|
@ -190,4 +187,4 @@ class HomeTimeline extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(HomeTimeline));
|
||||
export default connect(mapStateToProps)(withIdentity(injectIntl(HomeTimeline)));
|
||||
|
|
|
@ -5,6 +5,7 @@ import { FormattedMessage } from 'react-intl';
|
|||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'mastodon/permissions';
|
||||
|
||||
import { CheckboxWithLabel } from './checkbox_with_label';
|
||||
|
@ -12,13 +13,9 @@ import ClearColumnButton from './clear_column_button';
|
|||
import GrantPermissionButton from './grant_permission_button';
|
||||
import SettingToggle from './setting_toggle';
|
||||
|
||||
export default class ColumnSettings extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
class ColumnSettings extends PureComponent {
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
pushSettings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
|
@ -215,7 +212,7 @@ export default class ColumnSettings extends PureComponent {
|
|||
</div>
|
||||
</section>
|
||||
|
||||
{((this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && (
|
||||
{((this.props.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && (
|
||||
<section role='group' aria-labelledby='notifications-admin-sign-up'>
|
||||
<h3 id='notifications-status'><FormattedMessage id='notifications.column_settings.admin.sign_up' defaultMessage='New sign-ups:' /></h3>
|
||||
|
||||
|
@ -228,7 +225,7 @@ export default class ColumnSettings extends PureComponent {
|
|||
</section>
|
||||
)}
|
||||
|
||||
{((this.context.identity.permissions & PERMISSION_MANAGE_REPORTS) === PERMISSION_MANAGE_REPORTS) && (
|
||||
{((this.props.identity.permissions & PERMISSION_MANAGE_REPORTS) === PERMISSION_MANAGE_REPORTS) && (
|
||||
<section role='group' aria-labelledby='notifications-admin-report'>
|
||||
<h3 id='notifications-status'><FormattedMessage id='notifications.column_settings.admin.report' defaultMessage='New reports:' /></h3>
|
||||
|
||||
|
@ -245,3 +242,5 @@ export default class ColumnSettings extends PureComponent {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
export default withIdentity(ColumnSettings);
|
||||
|
|
|
@ -17,6 +17,7 @@ import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?
|
|||
import { compareId } from 'mastodon/compare_id';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { submitMarkers } from '../../actions/markers';
|
||||
|
@ -77,12 +78,8 @@ const mapStateToProps = state => ({
|
|||
});
|
||||
|
||||
class Notifications extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
columnId: PropTypes.string,
|
||||
notifications: ImmutablePropTypes.list.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
|
@ -190,7 +187,7 @@ class Notifications extends PureComponent {
|
|||
const { intl, notifications, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, lastReadId, canMarkAsRead, needsNotificationPermission } = this.props;
|
||||
const pinned = !!columnId;
|
||||
const emptyMessage = <FormattedMessage id='empty_column.notifications' defaultMessage="You don't have any notifications yet. When other people interact with you, you will see it here." />;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
let scrollableContent = null;
|
||||
|
||||
|
@ -299,4 +296,4 @@ class Notifications extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(Notifications));
|
||||
export default connect(mapStateToProps)(withIdentity(injectIntl(Notifications)));
|
||||
|
|
|
@ -18,6 +18,7 @@ import { replyCompose } from 'mastodon/actions/compose';
|
|||
import { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { me, boostModal } from 'mastodon/initial_state';
|
||||
import { makeGetStatus } from 'mastodon/selectors';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
@ -47,12 +48,8 @@ const makeMapStateToProps = () => {
|
|||
};
|
||||
|
||||
class Footer extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
statusId: PropTypes.string.isRequired,
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
|
@ -75,7 +72,7 @@ class Footer extends ImmutablePureComponent {
|
|||
|
||||
handleReplyClick = () => {
|
||||
const { dispatch, askReplyConfirmation, status, intl } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (askReplyConfirmation) {
|
||||
|
@ -104,7 +101,7 @@ class Footer extends ImmutablePureComponent {
|
|||
|
||||
handleFavouriteClick = () => {
|
||||
const { dispatch, status } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('favourited')) {
|
||||
|
@ -131,7 +128,7 @@ class Footer extends ImmutablePureComponent {
|
|||
|
||||
handleReblogClick = e => {
|
||||
const { dispatch, status } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('reblogged')) {
|
||||
|
@ -209,4 +206,4 @@ class Footer extends ImmutablePureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps)(withRouter(injectIntl(Footer)));
|
||||
export default connect(makeMapStateToProps)(withIdentity(withRouter(injectIntl(Footer))));
|
||||
|
|
|
@ -9,6 +9,7 @@ import { connect } from 'react-redux';
|
|||
|
||||
import PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { domain } from 'mastodon/initial_state';
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
|
@ -40,16 +41,12 @@ const mapStateToProps = (state, { columnId }) => {
|
|||
};
|
||||
|
||||
class PublicTimeline extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
|
@ -80,7 +77,7 @@ class PublicTimeline extends PureComponent {
|
|||
|
||||
componentDidMount () {
|
||||
const { dispatch, onlyMedia, onlyRemote } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
dispatch(expandPublicTimeline({ onlyMedia, onlyRemote }));
|
||||
|
||||
|
@ -90,7 +87,7 @@ class PublicTimeline extends PureComponent {
|
|||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.onlyRemote !== this.props.onlyRemote) {
|
||||
const { dispatch, onlyMedia, onlyRemote } = this.props;
|
||||
|
@ -164,4 +161,4 @@ class PublicTimeline extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(PublicTimeline));
|
||||
export default connect(mapStateToProps)(withIdentity(injectIntl(PublicTimeline)));
|
||||
|
|
|
@ -21,6 +21,7 @@ import RepeatActiveIcon from '@/svg-icons/repeat_active.svg?react';
|
|||
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
||||
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
||||
import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.svg?react';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
|
@ -67,12 +68,8 @@ const mapStateToProps = (state, { status }) => ({
|
|||
});
|
||||
|
||||
class ActionBar extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
relationship: ImmutablePropTypes.record,
|
||||
onReply: PropTypes.func.isRequired,
|
||||
|
@ -198,7 +195,7 @@ class ActionBar extends PureComponent {
|
|||
|
||||
render () {
|
||||
const { status, relationship, intl } = this.props;
|
||||
const { signedIn, permissions } = this.context.identity;
|
||||
const { signedIn, permissions } = this.props.identity;
|
||||
|
||||
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
|
||||
const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility'));
|
||||
|
@ -326,4 +323,4 @@ class ActionBar extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(injectIntl(ActionBar)));
|
||||
export default withRouter(connect(mapStateToProps)(withIdentity(injectIntl(ActionBar))));
|
||||
|
|
|
@ -20,6 +20,7 @@ import { Icon } from 'mastodon/components/icon';
|
|||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import ScrollContainer from 'mastodon/containers/scroll_container';
|
||||
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
import {
|
||||
|
@ -189,12 +190,8 @@ const titleFromStatus = (intl, status) => {
|
|||
};
|
||||
|
||||
class Status extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
status: ImmutablePropTypes.map,
|
||||
|
@ -244,7 +241,7 @@ class Status extends ImmutablePureComponent {
|
|||
|
||||
handleFavouriteClick = (status) => {
|
||||
const { dispatch } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('favourited')) {
|
||||
|
@ -274,7 +271,7 @@ class Status extends ImmutablePureComponent {
|
|||
|
||||
handleReplyClick = (status) => {
|
||||
const { askReplyConfirmation, dispatch, intl } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (askReplyConfirmation) {
|
||||
|
@ -307,7 +304,7 @@ class Status extends ImmutablePureComponent {
|
|||
|
||||
handleReblogClick = (status, e) => {
|
||||
const { dispatch } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('reblogged')) {
|
||||
|
@ -745,4 +742,4 @@ class Status extends ImmutablePureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default withRouter(injectIntl(connect(makeMapStateToProps)(Status)));
|
||||
export default withRouter(injectIntl(connect(makeMapStateToProps)(withIdentity(Status))));
|
||||
|
|
|
@ -7,16 +7,13 @@ import { changeComposing, mountCompose, unmountCompose } from 'mastodon/actions/
|
|||
import ServerBanner from 'mastodon/components/server_banner';
|
||||
import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container';
|
||||
import SearchContainer from 'mastodon/features/compose/containers/search_container';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import LinkFooter from './link_footer';
|
||||
|
||||
class ComposePanel extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
@ -41,7 +38,7 @@ class ComposePanel extends PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
return (
|
||||
<div className='compose-panel' onFocus={this.onFocus}>
|
||||
|
@ -65,4 +62,4 @@ class ComposePanel extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default connect()(ComposePanel);
|
||||
export default connect()(withIdentity(ComposePanel));
|
||||
|
|
|
@ -13,6 +13,7 @@ import { fetchServer } from 'mastodon/actions/server';
|
|||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { WordmarkLogo, SymbolLogo } from 'mastodon/components/logo';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { registrationsOpen, me, sso_redirect } from 'mastodon/initial_state';
|
||||
|
||||
const Account = connect(state => ({
|
||||
|
@ -41,12 +42,8 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
});
|
||||
|
||||
class Header extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
openClosedRegistrationsModal: PropTypes.func,
|
||||
location: PropTypes.object,
|
||||
signupUrl: PropTypes.string.isRequired,
|
||||
|
@ -60,7 +57,7 @@ class Header extends PureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
const { location, openClosedRegistrationsModal, signupUrl, intl } = this.props;
|
||||
|
||||
let content;
|
||||
|
@ -121,4 +118,4 @@ class Header extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default injectIntl(withRouter(connect(mapStateToProps, mapDispatchToProps)(Header)));
|
||||
export default injectIntl(withRouter(withIdentity(connect(mapStateToProps, mapDispatchToProps)(Header))));
|
||||
|
|
|
@ -8,6 +8,7 @@ import { Link } from 'react-router-dom';
|
|||
import { connect } from 'react-redux';
|
||||
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { domain, version, source_url, statusPageUrl, profile_directory as profileDirectory } from 'mastodon/initial_state';
|
||||
import { PERMISSION_INVITE_USERS } from 'mastodon/permissions';
|
||||
import { logOut } from 'mastodon/utils/log_out';
|
||||
|
@ -32,12 +33,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
});
|
||||
|
||||
class LinkFooter extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
multiColumn: PropTypes.bool,
|
||||
onLogout: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
|
@ -53,7 +50,7 @@ class LinkFooter extends PureComponent {
|
|||
};
|
||||
|
||||
render () {
|
||||
const { signedIn, permissions } = this.context.identity;
|
||||
const { signedIn, permissions } = this.props.identity;
|
||||
const { multiColumn } = this.props;
|
||||
|
||||
const canInvite = signedIn && ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS);
|
||||
|
@ -108,4 +105,4 @@ class LinkFooter extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default injectIntl(connect(null, mapDispatchToProps)(LinkFooter));
|
||||
export default injectIntl(withIdentity(connect(null, mapDispatchToProps)(LinkFooter)));
|
||||
|
|
|
@ -31,6 +31,7 @@ import { fetchFollowRequests } from 'mastodon/actions/accounts';
|
|||
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
|
||||
import { WordmarkLogo } from 'mastodon/components/logo';
|
||||
import { NavigationPortal } from 'mastodon/components/navigation_portal';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { timelinePreview, trendsEnabled } from 'mastodon/initial_state';
|
||||
import { transientSingleColumn } from 'mastodon/is_mobile';
|
||||
|
||||
|
@ -97,12 +98,8 @@ const FollowRequestsLink = () => {
|
|||
};
|
||||
|
||||
class NavigationPanel extends Component {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
@ -112,7 +109,7 @@ class NavigationPanel extends Component {
|
|||
|
||||
render () {
|
||||
const { intl } = this.props;
|
||||
const { signedIn, disabledAccountId } = this.context.identity;
|
||||
const { signedIn, disabledAccountId } = this.props.identity;
|
||||
|
||||
let banner = undefined;
|
||||
|
||||
|
@ -189,4 +186,4 @@ class NavigationPanel extends Component {
|
|||
|
||||
}
|
||||
|
||||
export default injectIntl(NavigationPanel);
|
||||
export default injectIntl(withIdentity(NavigationPanel));
|
||||
|
|
|
@ -15,6 +15,7 @@ import { focusApp, unfocusApp, changeLayout } from 'mastodon/actions/app';
|
|||
import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'mastodon/actions/markers';
|
||||
import { INTRODUCTION_VERSION } from 'mastodon/actions/onboarding';
|
||||
import { PictureInPicture } from 'mastodon/features/picture_in_picture';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { layoutFromWindow } from 'mastodon/is_mobile';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
|
@ -120,12 +121,8 @@ const keyMap = {
|
|||
};
|
||||
|
||||
class SwitchingColumnsArea extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
children: PropTypes.node,
|
||||
location: PropTypes.object,
|
||||
singleColumn: PropTypes.bool,
|
||||
|
@ -160,7 +157,7 @@ class SwitchingColumnsArea extends PureComponent {
|
|||
|
||||
render () {
|
||||
const { children, singleColumn } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
const pathName = this.props.location.pathname;
|
||||
|
||||
let redirect;
|
||||
|
@ -252,12 +249,8 @@ class SwitchingColumnsArea extends PureComponent {
|
|||
}
|
||||
|
||||
class UI extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
children: PropTypes.node,
|
||||
isComposing: PropTypes.bool,
|
||||
|
@ -309,7 +302,7 @@ class UI extends PureComponent {
|
|||
this.dragTargets.push(e.target);
|
||||
}
|
||||
|
||||
if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files') && this.props.canUploadMore && this.context.identity.signedIn) {
|
||||
if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files') && this.props.canUploadMore && this.props.identity.signedIn) {
|
||||
this.setState({ draggingOver: true });
|
||||
}
|
||||
};
|
||||
|
@ -337,7 +330,7 @@ class UI extends PureComponent {
|
|||
this.setState({ draggingOver: false });
|
||||
this.dragTargets = [];
|
||||
|
||||
if (e.dataTransfer && e.dataTransfer.files.length >= 1 && this.props.canUploadMore && this.context.identity.signedIn) {
|
||||
if (e.dataTransfer && e.dataTransfer.files.length >= 1 && this.props.canUploadMore && this.props.identity.signedIn) {
|
||||
this.props.dispatch(uploadCompose(e.dataTransfer.files));
|
||||
}
|
||||
};
|
||||
|
@ -389,7 +382,7 @@ class UI extends PureComponent {
|
|||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
window.addEventListener('focus', this.handleWindowFocus, false);
|
||||
window.addEventListener('blur', this.handleWindowBlur, false);
|
||||
|
@ -586,7 +579,7 @@ class UI extends PureComponent {
|
|||
<div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef}>
|
||||
<Header />
|
||||
|
||||
<SwitchingColumnsArea location={location} singleColumn={layout === 'mobile' || layout === 'single-column'}>
|
||||
<SwitchingColumnsArea identity={this.props.identity} location={location} singleColumn={layout === 'mobile' || layout === 'single-column'}>
|
||||
{children}
|
||||
</SwitchingColumnsArea>
|
||||
|
||||
|
@ -602,4 +595,4 @@ class UI extends PureComponent {
|
|||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(withRouter(UI)));
|
||||
export default connect(mapStateToProps)(injectIntl(withRouter(withIdentity(UI))));
|
||||
|
|
74
app/javascript/mastodon/identity_context.tsx
Normal file
74
app/javascript/mastodon/identity_context.tsx
Normal file
|
@ -0,0 +1,74 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import hoistStatics from 'hoist-non-react-statics';
|
||||
|
||||
import type { InitialState } from 'mastodon/initial_state';
|
||||
|
||||
export interface IdentityContextType {
|
||||
signedIn: boolean;
|
||||
accountId: string | undefined;
|
||||
disabledAccountId: string | undefined;
|
||||
accessToken: string | undefined;
|
||||
permissions: number;
|
||||
}
|
||||
|
||||
export const identityContextPropShape = PropTypes.shape({
|
||||
signedIn: PropTypes.bool.isRequired,
|
||||
accountId: PropTypes.string,
|
||||
disabledAccountId: PropTypes.string,
|
||||
accessToken: PropTypes.string,
|
||||
}).isRequired;
|
||||
|
||||
export const createIdentityContext = (state: InitialState) => ({
|
||||
signedIn: !!state.meta.me,
|
||||
accountId: state.meta.me,
|
||||
disabledAccountId: state.meta.disabled_account_id,
|
||||
accessToken: state.meta.access_token,
|
||||
permissions: state.role?.permissions ?? 0,
|
||||
});
|
||||
|
||||
export const IdentityContext = createContext<IdentityContextType>({
|
||||
signedIn: false,
|
||||
permissions: 0,
|
||||
accountId: undefined,
|
||||
disabledAccountId: undefined,
|
||||
accessToken: undefined,
|
||||
});
|
||||
|
||||
export const useIdentity = () => useContext(IdentityContext);
|
||||
|
||||
export interface IdentityProps {
|
||||
ref?: unknown;
|
||||
wrappedComponentRef?: unknown;
|
||||
}
|
||||
|
||||
/* Injects an `identity` props into the wrapped component to be able to use the new context in class components */
|
||||
export function withIdentity<
|
||||
ComponentType extends React.ComponentType<IdentityProps>,
|
||||
>(Component: ComponentType) {
|
||||
const displayName = `withIdentity(${Component.displayName ?? Component.name})`;
|
||||
const C = (props: React.ComponentProps<ComponentType>) => {
|
||||
const { wrappedComponentRef, ...remainingProps } = props;
|
||||
|
||||
return (
|
||||
<IdentityContext.Consumer>
|
||||
{(context) => {
|
||||
return (
|
||||
// @ts-expect-error - Dynamic covariant generic components are tough to type.
|
||||
<Component
|
||||
{...remainingProps}
|
||||
identity={context}
|
||||
ref={wrappedComponentRef}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</IdentityContext.Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
C.displayName = displayName;
|
||||
C.WrappedComponent = Component;
|
||||
|
||||
return hoistStatics(C, Component);
|
||||
}
|
|
@ -44,12 +44,22 @@
|
|||
* @property {string} sso_redirect
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef Role
|
||||
* @property {string} id
|
||||
* @property {string} name
|
||||
* @property {string} permissions
|
||||
* @property {string} color
|
||||
* @property {boolean} highlighted
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef InitialState
|
||||
* @property {Record<string, import("./api_types/accounts").ApiAccountJSON>} accounts
|
||||
* @property {InitialStateLanguage[]} languages
|
||||
* @property {boolean=} critical_updates_pending
|
||||
* @property {InitialStateMeta} meta
|
||||
* @property {Role?} role
|
||||
*/
|
||||
|
||||
const element = document.getElementById('initial-state');
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"account.block_domain": "Blocar dominio {domain}",
|
||||
"account.block_short": "Blocar",
|
||||
"account.blocked": "Blocate",
|
||||
"account.browse_more_on_origin_server": "Navigar plus sur le profilo original",
|
||||
"account.browse_more_on_origin_server": "Percurrer plus sur le profilo original",
|
||||
"account.cancel_follow_request": "Cancellar sequimento",
|
||||
"account.copy": "Copiar ligamine a profilo",
|
||||
"account.direct": "Mentionar privatemente @{name}",
|
||||
|
@ -122,7 +122,7 @@
|
|||
"column.direct": "Mentiones private",
|
||||
"column.directory": "Navigar profilos",
|
||||
"column.domain_blocks": "Dominios blocate",
|
||||
"column.favourites": "Favoritos",
|
||||
"column.favourites": "Favorites",
|
||||
"column.firehose": "Fluxos in directo",
|
||||
"column.follow_requests": "Requestas de sequimento",
|
||||
"column.home": "Initio",
|
||||
|
@ -204,7 +204,7 @@
|
|||
"disabled_account_banner.account_settings": "Parametros de conto",
|
||||
"disabled_account_banner.text": "Tu conto {disabledAccount} es actualmente disactivate.",
|
||||
"dismissable_banner.community_timeline": "Ecce le messages public le plus recente del personas con contos sur {domain}.",
|
||||
"dismissable_banner.dismiss": "Dimitter",
|
||||
"dismissable_banner.dismiss": "Clauder",
|
||||
"dismissable_banner.explore_links": "Istes es le articulos de novas que se condivide le plus sur le rete social hodie. Le articulos de novas le plus recente, publicate per plus personas differente, se classifica plus in alto.",
|
||||
"dismissable_banner.explore_statuses": "Ecce le messages de tote le rete social que gania popularitate hodie. Le messages plus nove con plus impulsos e favorites se classifica plus in alto.",
|
||||
"dismissable_banner.explore_tags": "Ecce le hashtags que gania popularitate sur le rete social hodie. Le hashtags usate per plus personas differente se classifica plus in alto.",
|
||||
|
@ -212,8 +212,8 @@
|
|||
"domain_block_modal.block": "Blocar le servitor",
|
||||
"domain_block_modal.block_account_instead": "Blocar @{name} in su loco",
|
||||
"domain_block_modal.they_can_interact_with_old_posts": "Le personas de iste servitor pote interager con tu messages ancian.",
|
||||
"domain_block_modal.they_cant_follow": "Nulle persona ab iste servitor pote sequer te.",
|
||||
"domain_block_modal.they_wont_know": "Illes non sapera que illes ha essite blocate.",
|
||||
"domain_block_modal.they_cant_follow": "Necuno de iste servitor pote sequer te.",
|
||||
"domain_block_modal.they_wont_know": "Ille non sapera que ille ha essite blocate.",
|
||||
"domain_block_modal.title": "Blocar dominio?",
|
||||
"domain_block_modal.you_will_lose_followers": "Omne sequitores ab iste servitor essera removite.",
|
||||
"domain_block_modal.you_wont_see_posts": "Tu non videra messages e notificationes ab usatores sur iste servitor.",
|
||||
|
@ -307,7 +307,7 @@
|
|||
"follow_request.reject": "Rejectar",
|
||||
"follow_requests.unlocked_explanation": "Benque tu conto non es serrate, le personal de {domain} pensa que es un bon idea que tu revide manualmente le sequente requestas de iste contos.",
|
||||
"follow_suggestions.curated_suggestion": "Selection del equipa",
|
||||
"follow_suggestions.dismiss": "Non monstrar novemente",
|
||||
"follow_suggestions.dismiss": "Non monstrar de novo",
|
||||
"follow_suggestions.featured_longer": "Seligite con cura per le equipa de {domain}",
|
||||
"follow_suggestions.friends_of_friends_longer": "Popular inter le gente que tu seque",
|
||||
"follow_suggestions.hints.featured": "Iste profilo ha essite seligite manualmente per le equipa de {domain}.",
|
||||
|
@ -412,7 +412,7 @@
|
|||
"lightbox.next": "Sequente",
|
||||
"lightbox.previous": "Precedente",
|
||||
"limited_account_hint.action": "Monstrar profilo in omne caso",
|
||||
"limited_account_hint.title": "Iste profilo esseva celate per le moderatores de {domain}.",
|
||||
"limited_account_hint.title": "Iste profilo ha essite celate per le moderatores de {domain}.",
|
||||
"link_preview.author": "Per {name}",
|
||||
"lists.account.add": "Adder al lista",
|
||||
"lists.account.remove": "Remover del lista",
|
||||
|
@ -432,12 +432,12 @@
|
|||
"loading_indicator.label": "Cargante…",
|
||||
"media_gallery.toggle_visible": "{number, plural, one {Celar imagine} other {Celar imagines}}",
|
||||
"moved_to_account_banner.text": "Tu conto {disabledAccount} es actualmente disactivate perque tu ha cambiate de conto a {movedToAccount}.",
|
||||
"mute_modal.hide_from_notifications": "Celar ab notificationes",
|
||||
"mute_modal.hide_from_notifications": "Celar in notificationes",
|
||||
"mute_modal.hide_options": "Celar optiones",
|
||||
"mute_modal.indefinite": "Usque io dissilentia iste persona",
|
||||
"mute_modal.show_options": "Monstrar optiones",
|
||||
"mute_modal.they_can_mention_and_follow": "Illes pote mentionar te e sequer te, ma tu non potera vider los.",
|
||||
"mute_modal.they_wont_know": "Illes non sapera que illes ha essite silentiate.",
|
||||
"mute_modal.they_can_mention_and_follow": "Ille pote mentionar te e sequer te, ma tu non potera vider le.",
|
||||
"mute_modal.they_wont_know": "Ille non sapera que ille ha essite silentiate.",
|
||||
"mute_modal.title": "Silentiar le usator?",
|
||||
"mute_modal.you_wont_see_mentions": "Tu non videra le messages que mentiona iste persona.",
|
||||
"mute_modal.you_wont_see_posts": "Iste persona pote totevia vider tu messages, ma tu non videra le sues.",
|
||||
|
@ -451,13 +451,13 @@
|
|||
"navigation_bar.discover": "Discoperir",
|
||||
"navigation_bar.domain_blocks": "Dominios blocate",
|
||||
"navigation_bar.explore": "Explorar",
|
||||
"navigation_bar.favourites": "Favoritos",
|
||||
"navigation_bar.favourites": "Favorites",
|
||||
"navigation_bar.filters": "Parolas silentiate",
|
||||
"navigation_bar.follow_requests": "Requestas de sequimento",
|
||||
"navigation_bar.followed_tags": "Hashtags sequite",
|
||||
"navigation_bar.follows_and_followers": "Sequites e sequitores",
|
||||
"navigation_bar.lists": "Listas",
|
||||
"navigation_bar.logout": "Clauder le session",
|
||||
"navigation_bar.logout": "Clauder session",
|
||||
"navigation_bar.mutes": "Usatores silentiate",
|
||||
"navigation_bar.opened_in_classic_interface": "Messages, contos e altere paginas specific es aperite per predefinition in le interfacie web classic.",
|
||||
"navigation_bar.personal": "Personal",
|
||||
|
@ -501,7 +501,7 @@
|
|||
"notifications.column_settings.admin.report": "Nove signalationes:",
|
||||
"notifications.column_settings.admin.sign_up": "Nove inscriptiones:",
|
||||
"notifications.column_settings.alert": "Notificationes de scriptorio",
|
||||
"notifications.column_settings.favourite": "Favoritos:",
|
||||
"notifications.column_settings.favourite": "Favorites:",
|
||||
"notifications.column_settings.filter_bar.advanced": "Monstrar tote le categorias",
|
||||
"notifications.column_settings.filter_bar.category": "Barra de filtro rapide",
|
||||
"notifications.column_settings.follow": "Nove sequitores:",
|
||||
|
@ -518,7 +518,7 @@
|
|||
"notifications.column_settings.update": "Modificationes:",
|
||||
"notifications.filter.all": "Toto",
|
||||
"notifications.filter.boosts": "Impulsos",
|
||||
"notifications.filter.favourites": "Favoritos",
|
||||
"notifications.filter.favourites": "Favorites",
|
||||
"notifications.filter.follows": "Sequites",
|
||||
"notifications.filter.mentions": "Mentiones",
|
||||
"notifications.filter.polls": "Resultatos del sondage",
|
||||
|
@ -717,7 +717,7 @@
|
|||
"status.edited": "Ultime modification le {date}",
|
||||
"status.edited_x_times": "Modificate {count, plural, one {{count} vice} other {{count} vices}}",
|
||||
"status.embed": "Incastrar",
|
||||
"status.favourite": "Adder al favoritos",
|
||||
"status.favourite": "Adder al favorites",
|
||||
"status.favourites": "{count, plural, one {favorite} other {favorites}}",
|
||||
"status.filter": "Filtrar iste message",
|
||||
"status.filtered": "Filtrate",
|
||||
|
|
|
@ -468,6 +468,7 @@
|
|||
"notification.follow": "{name} подписался (-лась) на вас",
|
||||
"notification.follow_request": "{name} отправил запрос на подписку",
|
||||
"notification.mention": "{name} упомянул(а) вас",
|
||||
"notification.moderation_warning.action_delete_statuses": "Некоторые из ваших публикаций были удалены.",
|
||||
"notification.own_poll": "Ваш опрос закончился",
|
||||
"notification.poll": "Опрос, в котором вы приняли участие, завершился",
|
||||
"notification.reblog": "{name} продвинул(а) ваш пост",
|
||||
|
|
|
@ -474,6 +474,7 @@
|
|||
"notification.follow_request": "{name} vam želi slediti",
|
||||
"notification.mention": "{name} vas je omenil/a",
|
||||
"notification.moderation-warning.learn_more": "Več o tem",
|
||||
"notification.moderation_warning": "Prejeli ste opozorilo moderatorjev",
|
||||
"notification.moderation_warning.action_delete_statuses": "Nekatere vaše objave so odstranjene.",
|
||||
"notification.moderation_warning.action_disable": "Vaš račun je bil onemogočen.",
|
||||
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Nekatere vaše objave so bile označene kot občutljive.",
|
||||
|
|
|
@ -158,7 +158,7 @@
|
|||
"compose_form.poll.option_placeholder": "ตัวเลือก {number}",
|
||||
"compose_form.poll.single": "เลือกอย่างใดอย่างหนึ่ง",
|
||||
"compose_form.poll.switch_to_multiple": "เปลี่ยนการสำรวจความคิดเห็นเป็นอนุญาตหลายตัวเลือก",
|
||||
"compose_form.poll.switch_to_single": "เปลี่ยนการสำรวจความคิดเห็นเป็นอนุญาตตัวเลือกเดี่ยว",
|
||||
"compose_form.poll.switch_to_single": "เปลี่ยนการสำรวจความคิดเห็นเป็นอนุญาตตัวเลือกเดียว",
|
||||
"compose_form.poll.type": "ลักษณะ",
|
||||
"compose_form.publish": "โพสต์",
|
||||
"compose_form.publish_form": "โพสต์ใหม่",
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { Component } from 'react';
|
||||
|
||||
import { IntlProvider } from 'react-intl';
|
||||
|
||||
import { MemoryRouter } from 'react-router';
|
||||
|
@ -9,44 +5,27 @@ import { MemoryRouter } from 'react-router';
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { render as rtlRender } from '@testing-library/react';
|
||||
|
||||
class FakeIdentityWrapper extends Component<
|
||||
PropsWithChildren<{ signedIn: boolean }>
|
||||
> {
|
||||
static childContextTypes = {
|
||||
identity: PropTypes.shape({
|
||||
signedIn: PropTypes.bool.isRequired,
|
||||
accountId: PropTypes.string,
|
||||
disabledAccountId: PropTypes.string,
|
||||
accessToken: PropTypes.string,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
identity: {
|
||||
signedIn: this.props.signedIn,
|
||||
accountId: '123',
|
||||
accessToken: 'test-access-token',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
import { IdentityContext } from './identity_context';
|
||||
|
||||
function render(
|
||||
ui: React.ReactElement,
|
||||
{ locale = 'en', signedIn = true, ...renderOptions } = {},
|
||||
) {
|
||||
const fakeIdentity = {
|
||||
signedIn: signedIn,
|
||||
accountId: '123',
|
||||
accessToken: 'test-access-token',
|
||||
disabledAccountId: undefined,
|
||||
permissions: 0,
|
||||
};
|
||||
|
||||
const Wrapper = (props: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<IntlProvider locale={locale}>
|
||||
<FakeIdentityWrapper signedIn={signedIn}>
|
||||
<IdentityContext.Provider value={fakeIdentity}>
|
||||
{props.children}
|
||||
</FakeIdentityWrapper>
|
||||
</IdentityContext.Provider>
|
||||
</IntlProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
|
|
@ -23,6 +23,12 @@ module ApplicationExtension
|
|||
redirect_uri.lines.first.strip
|
||||
end
|
||||
|
||||
def redirect_uris
|
||||
# Doorkeeper stores the redirect_uri value as a newline delimeted list in
|
||||
# the database:
|
||||
redirect_uri.split
|
||||
end
|
||||
|
||||
def push_to_streaming_api
|
||||
# TODO: #28793 Combine into a single topic
|
||||
payload = Oj.dump(event: :kill)
|
||||
|
|
|
@ -9,10 +9,10 @@ class Vacuum::ImportsVacuum
|
|||
private
|
||||
|
||||
def clean_unconfirmed_imports!
|
||||
BulkImport.state_unconfirmed.where('created_at <= ?', 10.minutes.ago).reorder(nil).in_batches.delete_all
|
||||
BulkImport.state_unconfirmed.where(created_at: ..10.minutes.ago).reorder(nil).in_batches.delete_all
|
||||
end
|
||||
|
||||
def clean_old_imports!
|
||||
BulkImport.where('created_at <= ?', 1.week.ago).reorder(nil).in_batches.delete_all
|
||||
BulkImport.where(created_at: ..1.week.ago).reorder(nil).in_batches.delete_all
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,7 +34,7 @@ class Vacuum::StatusesVacuum
|
|||
def statuses_scope
|
||||
Status.unscoped.kept
|
||||
.joins(:account).merge(Account.remote)
|
||||
.where('statuses.id < ?', retention_period_as_id)
|
||||
.where(statuses: { id: ...retention_period_as_id })
|
||||
end
|
||||
|
||||
def retention_period_as_id
|
||||
|
|
|
@ -4,7 +4,7 @@ module Expireable
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
scope :expired, -> { where.not(expires_at: nil).where('expires_at < ?', Time.now.utc) }
|
||||
scope :expired, -> { where.not(expires_at: nil).where(expires_at: ...Time.now.utc) }
|
||||
|
||||
def expires_in
|
||||
return @expires_in if defined?(@expires_in)
|
||||
|
|
|
@ -24,7 +24,7 @@ class Invite < ApplicationRecord
|
|||
belongs_to :user, inverse_of: :invites
|
||||
has_many :users, inverse_of: :invite, dependent: nil
|
||||
|
||||
scope :available, -> { where(expires_at: nil).or(where('expires_at >= ?', Time.now.utc)) }
|
||||
scope :available, -> { where(expires_at: nil).or(where(expires_at: Time.now.utc..)) }
|
||||
|
||||
validates :comment, length: { maximum: COMMENT_SIZE_LIMIT }
|
||||
|
||||
|
|
|
@ -4,6 +4,6 @@ class BackupPolicy < ApplicationPolicy
|
|||
MIN_AGE = 6.days
|
||||
|
||||
def create?
|
||||
user_signed_in? && current_user.backups.where('created_at >= ?', MIN_AGE.ago).count.zero?
|
||||
user_signed_in? && current_user.backups.where(created_at: MIN_AGE.ago..).count.zero?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class REST::ApplicationSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :website, :scopes, :redirect_uri,
|
||||
:client_id, :client_secret
|
||||
attributes :id, :name, :website, :scopes, :redirect_uris
|
||||
|
||||
# NOTE: Deprecated in 4.3.0, needs to be removed in 5.0.0
|
||||
attribute :vapid_key
|
||||
|
||||
# We should consider this property deprecated for 4.3.0
|
||||
attribute :redirect_uri
|
||||
|
||||
def id
|
||||
object.id.to_s
|
||||
end
|
||||
|
||||
def client_id
|
||||
object.uid
|
||||
end
|
||||
|
||||
def client_secret
|
||||
object.secret
|
||||
end
|
||||
|
||||
def website
|
||||
object.website.presence
|
||||
end
|
||||
|
|
13
app/serializers/rest/credential_application_serializer.rb
Normal file
13
app/serializers/rest/credential_application_serializer.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class REST::CredentialApplicationSerializer < REST::ApplicationSerializer
|
||||
attributes :client_id, :client_secret
|
||||
|
||||
def client_id
|
||||
object.uid
|
||||
end
|
||||
|
||||
def client_secret
|
||||
object.secret
|
||||
end
|
||||
end
|
|
@ -56,7 +56,7 @@ class FetchLinkCardService < BaseService
|
|||
|
||||
@html_charset = res.charset
|
||||
|
||||
res.body_with_limit
|
||||
res.truncated_body
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@ class Scheduler::IpCleanupScheduler
|
|||
private
|
||||
|
||||
def clean_ip_columns!
|
||||
SessionActivation.where('updated_at < ?', SESSION_RETENTION_PERIOD.ago).in_batches.destroy_all
|
||||
SessionActivation.where('updated_at < ?', IP_RETENTION_PERIOD.ago).in_batches.update_all(ip: nil)
|
||||
User.where('current_sign_in_at < ?', IP_RETENTION_PERIOD.ago).in_batches.update_all(sign_up_ip: nil)
|
||||
LoginActivity.where('created_at < ?', IP_RETENTION_PERIOD.ago).in_batches.destroy_all
|
||||
Doorkeeper::AccessToken.where('last_used_at < ?', IP_RETENTION_PERIOD.ago).in_batches.update_all(last_used_ip: nil)
|
||||
SessionActivation.where(updated_at: ...SESSION_RETENTION_PERIOD.ago).in_batches.destroy_all
|
||||
SessionActivation.where(updated_at: ...IP_RETENTION_PERIOD.ago).in_batches.update_all(ip: nil)
|
||||
User.where(current_sign_in_at: ...IP_RETENTION_PERIOD.ago).in_batches.update_all(sign_up_ip: nil)
|
||||
LoginActivity.where(created_at: ...IP_RETENTION_PERIOD.ago).in_batches.destroy_all
|
||||
Doorkeeper::AccessToken.where(last_used_at: ...IP_RETENTION_PERIOD.ago).in_batches.update_all(last_used_ip: nil)
|
||||
end
|
||||
|
||||
def clean_expired_ip_blocks!
|
||||
|
|
|
@ -20,7 +20,7 @@ class Scheduler::ScheduledStatusesScheduler
|
|||
end
|
||||
|
||||
def due_statuses
|
||||
ScheduledStatus.where('scheduled_at <= ?', Time.now.utc + PostStatusService::MIN_SCHEDULE_OFFSET)
|
||||
ScheduledStatus.where(scheduled_at: ..Time.now.utc + PostStatusService::MIN_SCHEDULE_OFFSET)
|
||||
end
|
||||
|
||||
def publish_scheduled_announcements!
|
||||
|
|
|
@ -25,7 +25,7 @@ class Scheduler::UserCleanupScheduler
|
|||
end
|
||||
|
||||
def clean_discarded_statuses!
|
||||
Status.unscoped.discarded.where('deleted_at <= ?', DISCARDED_STATUSES_MAX_AGE_DAYS.days.ago).find_in_batches do |statuses|
|
||||
Status.unscoped.discarded.where(deleted_at: ..DISCARDED_STATUSES_MAX_AGE_DAYS.days.ago).find_in_batches do |statuses|
|
||||
RemovalWorker.push_bulk(statuses) do |status|
|
||||
[status.id, { 'immediate' => true, 'skip_streaming' => true }]
|
||||
end
|
||||
|
|
|
@ -51,6 +51,9 @@ if ENV.keys.any? { |name| name.match?(/OTEL_.*_ENDPOINT/) }
|
|||
use_rack_events: false, # instead of events, use middleware; allows for untraced_endpoints to ignore child spans
|
||||
untraced_endpoints: ['/health'],
|
||||
},
|
||||
'OpenTelemetry::Instrumentation::Sidekiq' => {
|
||||
span_naming: :job_class, # Use the job class as the span name, otherwise this is the queue name and not very helpful
|
||||
},
|
||||
})
|
||||
|
||||
prefix = ENV.fetch('OTEL_SERVICE_NAME_PREFIX', 'mastodon')
|
||||
|
|
|
@ -285,6 +285,7 @@ bg:
|
|||
update_custom_emoji_html: "%{name} обнови емоджито %{target}"
|
||||
update_domain_block_html: "%{name} обнови блокирането на домейна за %{target}"
|
||||
update_ip_block_html: "%{name} промени правило за IP на %{target}"
|
||||
update_report_html: "%{name} осъвремени доклад %{target}"
|
||||
update_status_html: "%{name} обнови публикация от %{target}"
|
||||
update_user_role_html: "%{name} промени ролята %{target}"
|
||||
deleted_account: изтрит акаунт
|
||||
|
|
|
@ -285,6 +285,7 @@ ca:
|
|||
update_custom_emoji_html: "%{name} ha actualitzat l'emoji %{target}"
|
||||
update_domain_block_html: "%{name} ha actualitzat el bloqueig de domini per a %{target}"
|
||||
update_ip_block_html: "%{name} ha canviat la norma per la IP %{target}"
|
||||
update_report_html: "%{name} ha actualitzat l'informe %{target}"
|
||||
update_status_html: "%{name} ha actualitzat l'estat de %{target}"
|
||||
update_user_role_html: "%{name} ha canviat el rol %{target}"
|
||||
deleted_account: compte eliminat
|
||||
|
|
|
@ -285,6 +285,7 @@ da:
|
|||
update_custom_emoji_html: "%{name} opdaterede emoji %{target}"
|
||||
update_domain_block_html: "%{name} opdaterede domæneblokeringen for %{target}"
|
||||
update_ip_block_html: "%{name} ændrede reglen for IP'en %{target}"
|
||||
update_report_html: "%{name} opdaterede rapporten %{target}"
|
||||
update_status_html: "%{name} opdaterede indlægget fra %{target}"
|
||||
update_user_role_html: "%{name} ændrede %{target}-rolle"
|
||||
deleted_account: slettet konto
|
||||
|
|
|
@ -285,6 +285,7 @@ de:
|
|||
update_custom_emoji_html: "%{name} bearbeitete das Emoji %{target}"
|
||||
update_domain_block_html: "%{name} aktualisierte die Domain-Sperre für %{target}"
|
||||
update_ip_block_html: "%{name} änderte die Regel für die IP-Adresse %{target}"
|
||||
update_report_html: "%{name} überarbeitete die Meldung %{target}"
|
||||
update_status_html: "%{name} überarbeitete einen Beitrag von %{target}"
|
||||
update_user_role_html: "%{name} änderte die Rolle von %{target}"
|
||||
deleted_account: gelöschtes Konto
|
||||
|
|
|
@ -6,11 +6,11 @@ ia:
|
|||
send_instructions: Tu recipera un e-mail con instructiones pro confirmar tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe.
|
||||
send_paranoid_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un e-mail con instructiones pro confirmar tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe.
|
||||
failure:
|
||||
already_authenticated: Tu jam initiava le session.
|
||||
inactive: Tu conto ancora non es activate.
|
||||
already_authenticated: Tu ha jam aperite session.
|
||||
inactive: Tu conto non es ancora activate.
|
||||
invalid: "%{authentication_keys} o contrasigno non valide."
|
||||
last_attempt: Tu ha solmente un altere tentativa ante que tu conto es serrate.
|
||||
locked: Tu conto es blocate.
|
||||
locked: Tu conto es serrate.
|
||||
not_found_in_database: "%{authentication_keys} o contrasigno non valide."
|
||||
omniauth_user_creation_failure: Error creante un conto pro iste identitate.
|
||||
pending: Tu conto es ancora sub revision.
|
||||
|
@ -51,12 +51,12 @@ ia:
|
|||
explanation: Ora es possibile aperir session con solmente le adresse de e-mail e contrasigno.
|
||||
subject: 'Mastodon: Authentication bifactorial disactivate'
|
||||
subtitle: Le authentication bifactorial ha essite disactivate pro tu conto.
|
||||
title: 2FA disactivate
|
||||
title: A2F disactivate
|
||||
two_factor_enabled:
|
||||
explanation: Pro le apertura de session essera necessari un token generate per le application TOTP accopulate.
|
||||
subject: 'Mastodon: Authentication bifactorial activate'
|
||||
subtitle: Le authentication bifactorial ha essite activate pro tu conto.
|
||||
title: 2FA activate
|
||||
title: A2F activate
|
||||
two_factor_recovery_codes_changed:
|
||||
explanation: Le ancian codices de recuperation ha essite invalidate e nove codices ha essite generate.
|
||||
subject: 'Mastodon: Codices de recuperation regenerate'
|
||||
|
@ -66,11 +66,11 @@ ia:
|
|||
subject: 'Mastodon: Instructiones pro disblocar'
|
||||
webauthn_credential:
|
||||
added:
|
||||
explanation: Le sequente clave de securitate esseva addite a tu conto
|
||||
explanation: Le sequente clave de securitate ha essite addite a tu conto
|
||||
subject: 'Mastodon: Nove clave de securitate'
|
||||
title: Un nove clave de securitate esseva addite
|
||||
title: Un nove clave de securitate ha essite addite
|
||||
deleted:
|
||||
explanation: Le sequente clave de securitate esseva delite de tu conto
|
||||
explanation: Le sequente clave de securitate ha essite delite de tu conto
|
||||
subject: 'Mastodon: Clave de securitate delite'
|
||||
title: Un de tu claves de securitate ha essite delite
|
||||
webauthn_disabled:
|
||||
|
@ -81,18 +81,41 @@ ia:
|
|||
webauthn_enabled:
|
||||
explanation: Le authentication con claves de securitate ha essite activate pro tu conto.
|
||||
extra: Tu clave de securitate pote ora esser usate pro aperir session.
|
||||
subject: 'Mastodon: authentication de clave de securitate activate'
|
||||
title: Claves de securitate activate
|
||||
omniauth_callbacks:
|
||||
failure: Impossibile authenticar te ab %{kind} perque “%{reason}”.
|
||||
success: Authenticate con successo ab conto %{kind}.
|
||||
passwords:
|
||||
no_token: Tu non pote acceder iste pagina sin venir ab un email de redefinition de contrasigno. Si tu veni ab un email de redefinition de contrasigno, verifica que tu usava le integre URL fornite.
|
||||
send_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un ligamine de recuperation de contrasigno in tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe.
|
||||
send_paranoid_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un ligamine de recuperation de contrasigno in tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe.
|
||||
updated: Tu contrasigno ha essite cambiate. Tu ha ora aperite session.
|
||||
updated_not_active: Tu contrasigno ha essite cambiate.
|
||||
registrations:
|
||||
destroyed: A revider! Tu conto esseva cancellate con successo. Nos spera vider te novemente tosto.
|
||||
signed_up_but_pending: Un message con un ligamine de confirmation esseva inviate a tu conto de email. Post que tu clicca le ligamine, nos revidera tu application. Tu essera notificate si illo es approbate.
|
||||
destroyed: A revider! Tu conto ha essite cancellate. Nos spera vider te de novo tosto.
|
||||
signed_up: Benvenite! Tu te ha inscribite con successo.
|
||||
signed_up_but_inactive: Tu te ha inscribite con successo. Nonobstante, nos non poteva aperir tu session perque tu conto non es ancora activate.
|
||||
signed_up_but_locked: Tu te ha inscribite con successo. Nonobstante, nos non poteva aperir tu session perque tu conto es serrate.
|
||||
signed_up_but_pending: Un message con un ligamine de confirmation ha essite inviate a tu adresse de email. Post que tu clicca sur le ligamine, nos revidera tu demanda. Tu essera notificate si illo es approbate.
|
||||
signed_up_but_unconfirmed: Un message con un ligamine de confirmation ha essite inviate a tu adresse de e-mail. Per favor seque le ligamine pro activar tu conto. Verifica tu dossier de spam si tu non recipe iste e-mail.
|
||||
update_needs_confirmation: Tu ha actualisate tu conto con successo, ma nos debe verificar tu nove adresse de e-mail. Accede a tu e-mail e seque le ligamine de confirmation pro confirmar tu nove adresse de e-mail. Verifica tu dossier de spam si tu non recipe iste e-mail.
|
||||
updated: Tu conto ha essite actualisate con successo.
|
||||
sessions:
|
||||
signed_in: Connexe con successo.
|
||||
signed_out: Disconnexe con successo.
|
||||
already_signed_out: Session claudite con successo.
|
||||
signed_in: Session aperite con successo.
|
||||
signed_out: Session claudite con successo.
|
||||
unlocks:
|
||||
unlocked: Tu conto ha essite disblocate con successo. Initia session a continuar.
|
||||
send_instructions: Tu recipera un e-mail con instructiones explicante como disserrar tu conto in alcun minutas. Verifica tu dossier de spam si tu non recipe iste e-mail.
|
||||
send_paranoid_instructions: Si tu conto existe, tu recipera un email con instructiones explicante como disserrar lo in alcun minutas. Verifica tu dossier de spam si tu non recipe iste e-mail.
|
||||
unlocked: Tu conto ha essite disserrate con successo. Aperi session pro continuar.
|
||||
errors:
|
||||
messages:
|
||||
already_confirmed: jam esseva confirmate, tenta initiar session
|
||||
already_confirmed: jam esseva confirmate, tenta aperir session
|
||||
confirmation_period_expired: debe esser confirmate in %{period}, per favor requesta un nove
|
||||
expired: ha expirate, per favor requesta un nove
|
||||
not_found: non trovate
|
||||
not_locked: non era blocate
|
||||
not_locked: non esseva serrate
|
||||
not_saved:
|
||||
one: '1 error ha impedite a iste %{resource} de esser salvate:'
|
||||
other: "%{count} errores ha impedite a iste %{resource} de esser salvate:"
|
||||
|
|
|
@ -3,28 +3,40 @@ ia:
|
|||
activerecord:
|
||||
attributes:
|
||||
doorkeeper/application:
|
||||
name: Nomine de application
|
||||
name: Nomine del application
|
||||
redirect_uri: URI de redirection
|
||||
scopes: Ambitos
|
||||
website: Sito web de application
|
||||
website: Sito web del application
|
||||
errors:
|
||||
models:
|
||||
doorkeeper/application:
|
||||
attributes:
|
||||
redirect_uri:
|
||||
fragment_present: non pote continer un fragmento.
|
||||
invalid_uri: debe esser un URI valide.
|
||||
relative_uri: debe esser un URI absolute.
|
||||
secured_uri: debe esser un URI HTTPS/SSL.
|
||||
doorkeeper:
|
||||
applications:
|
||||
buttons:
|
||||
authorize: Autorisar
|
||||
cancel: Cancellar
|
||||
destroy: Destruer
|
||||
edit: Modificar
|
||||
submit: Submitter
|
||||
confirmations:
|
||||
destroy: Es tu secur?
|
||||
edit:
|
||||
title: Modificar application
|
||||
form:
|
||||
error: Oops! Verifica tu formulario pro possibile errores
|
||||
help:
|
||||
native_redirect_uri: Usar %{native_redirect_uri} pro tests local
|
||||
redirect_uri: Usar un linea per URI
|
||||
scopes: Separa ambitos con spatios. Lassa vacue pro usar le ambitos predefinite.
|
||||
index:
|
||||
application: Application
|
||||
callback_url: URL de retorno
|
||||
delete: Deler
|
||||
empty: Tu non ha applicationes.
|
||||
name: Nomine
|
||||
|
@ -37,17 +49,22 @@ ia:
|
|||
show:
|
||||
actions: Actiones
|
||||
application_id: Clave del cliente
|
||||
callback_urls: URLs de retorno
|
||||
scopes: Ambitos
|
||||
secret: Secreto del application
|
||||
title: 'Application: %{name}'
|
||||
authorizations:
|
||||
buttons:
|
||||
authorize: Autorisar
|
||||
deny: Negar
|
||||
error:
|
||||
title: Ocurreva un error
|
||||
title: Un error ha occurrite
|
||||
new:
|
||||
prompt_html: "%{client_name} vole haber le permission de acceder a tu conto. Illo es un application tertie. <strong>Si tu non confide in illo, alora tu non deberea autorisar lo.</strong>"
|
||||
review_permissions: Revisionar le permissos
|
||||
title: Autorisation necessari
|
||||
show:
|
||||
title: Copia iste codice de autorisation e colla lo in le application.
|
||||
authorized_applications:
|
||||
buttons:
|
||||
revoke: Revocar
|
||||
|
@ -55,11 +72,35 @@ ia:
|
|||
revoke: Es tu secur?
|
||||
index:
|
||||
authorized_at: Autorisate le %{date}
|
||||
description_html: Ecce applicationes que pote acceder tu conto per le API. Si il ha applicationes que tu non recognosce ci, o un application que se comporta mal, tu pote revocar su accesso.
|
||||
last_used_at: Ultime uso in %{date}
|
||||
never_used: Nunquam usate
|
||||
scopes: Permissiones
|
||||
superapp: Interne
|
||||
title: Tu applicationes autorisate
|
||||
errors:
|
||||
messages:
|
||||
access_denied: Le proprietario del ressource o servitor de autorisation ha refusate le requesta.
|
||||
credential_flow_not_configured: Le processo de credentiales de contrasigno del proprietario del ressource ha fallite perque Doorkeeper.configure.resource_owner_from_credentials non es configurate.
|
||||
invalid_client: Le authentication del cliente ha fallite perque le cliente es incognite, necun authentication de cliente es includite, o le methodo de authentication non es supportate.
|
||||
invalid_grant: Le concession de autorisation fornite es invalide, expirate, revocate, non corresponde al URI de redirection usate in le requesta de autorisation, o ha essite emittite a un altere cliente.
|
||||
invalid_redirect_uri: Le URI de redirection includite non es valide.
|
||||
invalid_request:
|
||||
missing_param: 'Parametro requirite mancante: %{value}.'
|
||||
request_not_authorized: Le requesta debe esser autorisate. Un parametro requirite pro autorisar le requesta manca o non es valide.
|
||||
unknown: Le requesta non include un parametro requirite, include un valor de parametro non supportate, o es alteremente mal formate.
|
||||
invalid_resource_owner: Le credentiales del proprietario del ressource fornite non es valide, o le proprietario del ressource non pote esser trovate
|
||||
invalid_scope: Le ambito requirite es invalide, incognite, o mal formate.
|
||||
invalid_token:
|
||||
expired: Le token de accesso ha expirate
|
||||
revoked: Le token de accesso ha essite revocate
|
||||
unknown: Le token de accesso non es valide
|
||||
resource_owner_authenticator_not_configured: Impossibile trovar le proprietario del ressource perque Doorkeeper.configure.resource_owner_authenticator non es configurate.
|
||||
server_error: Le servitor de autorisation ha incontrate un condition impreviste que lo ha impedite de complir le requesta.
|
||||
temporarily_unavailable: Le servitor de autorisation actualmente non pote gerer le requesta a causa de un supercarga temporari o de mantenentia del servitor.
|
||||
unauthorized_client: Le application non es autorisate a exequer iste requesta usante iste methodo.
|
||||
unsupported_grant_type: Le typo de concession de autorisation non es supportate per le servitor de autorisation.
|
||||
unsupported_response_type: Le servitor de autorisation non supporta iste typo de responsa.
|
||||
flash:
|
||||
applications:
|
||||
create:
|
||||
|
@ -73,20 +114,22 @@ ia:
|
|||
notice: Application revocate.
|
||||
grouped_scopes:
|
||||
access:
|
||||
read: Accesso de sol lectura
|
||||
read: Accesso de lectura sol
|
||||
read/write: Accesso de lectura e scriptura
|
||||
write: Accesso de sol scriptura
|
||||
write: Accesso de scriptura sol
|
||||
title:
|
||||
accounts: Contos
|
||||
admin/accounts: Gestion de contos
|
||||
admin/all: Tote le functiones administrative
|
||||
admin/reports: Gestion de reportos
|
||||
all: Accesso plen a tu conto de Mastodon
|
||||
all: Accesso complete a tu conto de Mastodon
|
||||
blocks: Blocadas
|
||||
bookmarks: Marcapaginas
|
||||
conversations: Conversationes
|
||||
favourites: Favoritos
|
||||
crypto: Cryptation de puncta a puncta
|
||||
favourites: Favorites
|
||||
filters: Filtros
|
||||
follow: Sequites, silentiates e blocates
|
||||
follows: Sequites
|
||||
lists: Listas
|
||||
media: Annexos multimedial
|
||||
|
@ -101,21 +144,41 @@ ia:
|
|||
nav:
|
||||
applications: Applicationes
|
||||
oauth2_provider: Fornitor OAuth2
|
||||
application:
|
||||
title: Autorisation OAuth necessari
|
||||
scopes:
|
||||
admin:read: leger tote le datos in le servitor
|
||||
admin:read:accounts: leger information sensibile de tote le contos
|
||||
admin:read:canonical_email_blocks: leger datos sensibile de tote le blocadas de email canonic
|
||||
admin:read:domain_allows: leger informationes sensibile de tote le dominios permittite
|
||||
admin:read:domain_blocks: leger informationes sensibile de tote le blocadas de dominio
|
||||
admin:read:email_domain_blocks: leger informationes sensibile de tote le blocadas de dominio email
|
||||
admin:read:ip_blocks: leger informationes sensibile de tote le blocadas de IP
|
||||
admin:read:reports: leger information sensibile de tote le reportos e contos signalate
|
||||
admin:write: modificar tote le datos in le servitor
|
||||
admin:write:accounts: exequer action de moderation sur contos
|
||||
admin:write:canonical_email_blocks: exequer actiones de moderation sur blocadas de email canonic
|
||||
admin:write:domain_allows: exequer actiones de moderation sur dominios permittite
|
||||
admin:write:domain_blocks: exequer actiones de moderation sur blocadas de dominio
|
||||
admin:write:email_domain_blocks: exequer actiones de moderation sur blocadas de dominio email
|
||||
admin:write:ip_blocks: exequer actiones de moderation sur blocadas de IP
|
||||
admin:write:reports: exequer action de moderation sur reportos
|
||||
crypto: usar cryptation de extremo-a-extremo
|
||||
follow: modificar relationes del contos
|
||||
push: reciper tu notificationes push
|
||||
read: leger tote le datos de tu conto
|
||||
read:accounts: vider informationes de conto
|
||||
read:blocks: vider tu blocadas
|
||||
read:bookmarks: vider tu marcapaginas
|
||||
read:favourites: vider tu favoritos
|
||||
read:filters: vider tu filtros
|
||||
read:follows: vider tu sequites
|
||||
read:lists: vider tu listas
|
||||
read:me: leger solmente le information basic de tu conto
|
||||
read:mutes: vider tu silentiates
|
||||
read:notifications: vider tu notificationes
|
||||
read:reports: vider tu reportos
|
||||
read:search: cercar in tu nomine
|
||||
read:statuses: vider tote le messages
|
||||
write: modificar tote le datos de tu conto
|
||||
write:accounts: modificar tu profilo
|
||||
|
|
|
@ -285,6 +285,7 @@ es-AR:
|
|||
update_custom_emoji_html: "%{name} actualizó el emoji %{target}"
|
||||
update_domain_block_html: "%{name} actualizó el bloqueo de dominio para %{target}"
|
||||
update_ip_block_html: "%{name} cambió la regla para la dirección IP %{target}"
|
||||
update_report_html: "%{name} actualizó la denuncia %{target}"
|
||||
update_status_html: "%{name} actualizó el mensaje de %{target}"
|
||||
update_user_role_html: "%{name} cambió el rol %{target}"
|
||||
deleted_account: cuenta eliminada
|
||||
|
|
|
@ -285,6 +285,7 @@ es-MX:
|
|||
update_custom_emoji_html: "%{name} actualizó el emoji %{target}"
|
||||
update_domain_block_html: "%{name} actualizó el bloqueo de dominio para %{target}"
|
||||
update_ip_block_html: "%{name} cambió la regla para la IP %{target}"
|
||||
update_report_html: "%{name} actualizó el informe %{target}"
|
||||
update_status_html: "%{name} actualizó el estado de %{target}"
|
||||
update_user_role_html: "%{name} cambió el rol %{target}"
|
||||
deleted_account: cuenta eliminada
|
||||
|
|
|
@ -285,6 +285,7 @@ es:
|
|||
update_custom_emoji_html: "%{name} actualizó el emoji %{target}"
|
||||
update_domain_block_html: "%{name} actualizó el bloqueo de dominio para %{target}"
|
||||
update_ip_block_html: "%{name} cambió la regla para la IP %{target}"
|
||||
update_report_html: "%{name} actualizó el informe %{target}"
|
||||
update_status_html: "%{name} actualizó la publicación de %{target}"
|
||||
update_user_role_html: "%{name} cambió el rol %{target}"
|
||||
deleted_account: cuenta eliminada
|
||||
|
|
|
@ -285,6 +285,7 @@ fi:
|
|||
update_custom_emoji_html: "%{name} päivitti emojin %{target}"
|
||||
update_domain_block_html: "%{name} päivitti verkkotunnuksen %{target} eston"
|
||||
update_ip_block_html: "%{name} muutti sääntöä IP-osoitteelle %{target}"
|
||||
update_report_html: "%{name} päivitti raportin %{target}"
|
||||
update_status_html: "%{name} päivitti käyttäjän %{target} julkaisun"
|
||||
update_user_role_html: "%{name} muutti roolia %{target}"
|
||||
deleted_account: poisti tilin
|
||||
|
|
|
@ -285,6 +285,7 @@ fo:
|
|||
update_custom_emoji_html: "%{name} dagførdi kensluteknið %{target}"
|
||||
update_domain_block_html: "%{name} dagførdi navnaøkisblokeringina hjá %{target}"
|
||||
update_ip_block_html: "%{name} broytti IP-reglurnar %{target}"
|
||||
update_report_html: "%{name} dagførdi meldingina %{target}"
|
||||
update_status_html: "%{name} dagførdi postin hjá %{target}"
|
||||
update_user_role_html: "%{name} broyttir %{target} leiklutir"
|
||||
deleted_account: strikað konta
|
||||
|
|
|
@ -285,6 +285,7 @@ gl:
|
|||
update_custom_emoji_html: "%{name} actualizou o emoji %{target}"
|
||||
update_domain_block_html: "%{name} actualizou o bloqueo do dominio para %{target}"
|
||||
update_ip_block_html: "%{name} cambiou a regra para IP %{target}"
|
||||
update_report_html: "%{name} actualizou a denuncia %{target}"
|
||||
update_status_html: "%{name} actualizou a publicación de %{target}"
|
||||
update_user_role_html: "%{name} cambiou o rol %{target}"
|
||||
deleted_account: conta eliminada
|
||||
|
|
|
@ -291,6 +291,7 @@ he:
|
|||
update_custom_emoji_html: "%{name} עדכן/ה אמוג'י %{target}"
|
||||
update_domain_block_html: "%{name} עדכן/ה חסימת דומיין עבור %{target}"
|
||||
update_ip_block_html: "%{name} שינה כלל עבור IP %{target}"
|
||||
update_report_html: '%{name} עדכן/ה דו"ח %{target}'
|
||||
update_status_html: "%{name} עדכן/ה הודעה של %{target}"
|
||||
update_user_role_html: "%{name} שינה את התפקיד של %{target}"
|
||||
deleted_account: חשבון מחוק
|
||||
|
|
|
@ -285,6 +285,7 @@ hu:
|
|||
update_custom_emoji_html: "%{name} frissítette az emodzsit: %{target}"
|
||||
update_domain_block_html: "%{name} frissítette a %{target} domain tiltását"
|
||||
update_ip_block_html: "%{name} módosította a(z) %{target} IP-címre vonatkozó szabályt"
|
||||
update_report_html: "%{name} frissítette a %{target} bejelentést"
|
||||
update_status_html: "%{name} frissítette %{target} felhasználó bejegyzését"
|
||||
update_user_role_html: "%{name} módosította a(z) %{target} szerepkört"
|
||||
deleted_account: törölt fiók
|
||||
|
|
|
@ -285,6 +285,7 @@ ia:
|
|||
update_custom_emoji_html: "%{name} actualisava le emoticone %{target}"
|
||||
update_domain_block_html: "%{name} actualisava le blocada de dominio pro %{target}"
|
||||
update_ip_block_html: "%{name} cambiava le regula pro IP %{target}"
|
||||
update_report_html: "%{name} actualisava le reporto %{target}"
|
||||
update_status_html: "%{name} actualisava le message per %{target}"
|
||||
update_user_role_html: "%{name} cambiava le rolo de %{target}"
|
||||
deleted_account: conto delite
|
||||
|
@ -973,6 +974,7 @@ ia:
|
|||
webhook: Crocs web
|
||||
admin_mailer:
|
||||
auto_close_registrations:
|
||||
body: Per un carentia recente de activate de moderator, le registrationes sur %{instance} ha essite automaticamente mutate a besoniante revision manual, pro impedir %{instance} de esser usate como un platteforma pro potential mal actores. Tu pote mutar lo retro pro sempre aperir le registrationes.
|
||||
subject: Le registrationes pro %{instance} ha essite automaticamente mutate a besoniante de approbation
|
||||
new_appeal:
|
||||
actions:
|
||||
|
@ -1054,19 +1056,27 @@ ia:
|
|||
clicking_this_link: cliccante iste ligamine
|
||||
login_link: acceder
|
||||
proceed_to_login_html: Ora tu pote continuar a %{login_link}.
|
||||
redirect_to_app_html: Tu deberea haber essite re-dirigite al app <strong>%{app_name}</strong>. Si isto non eveni, tenta %{clicking_this_link} o manualmente retorna al app.
|
||||
registration_complete: Tu registration sur %{domain} es ora complete!
|
||||
welcome_title: Benvenite, %{name}!
|
||||
wrong_email_hint: Si ille adresse email non es correcte, tu pote cambiar lo in parametros de conto.
|
||||
delete_account: Deler le conto
|
||||
delete_account_html: Si tu vole a dele tu conto, tu pote <a href="%{path}">continuar ci</a>. Te sera demandate confirmation.
|
||||
description:
|
||||
prefix_invited_by_user: "@%{name} te invita a junger te a iste servitor de Mastodon!"
|
||||
prefix_sign_up: Inscribe te sur Mastodon hodie!
|
||||
suffix: Con un conto, tu potera sequer personas, messages de actualisation e excambios de messages con usatores de ulle servitor de Mastodon e plus!
|
||||
didnt_get_confirmation: Non recipeva tu un ligamine de confirmation?
|
||||
dont_have_your_security_key: Non ha tu le clave de securitate?
|
||||
forgot_password: Contrasigno oblidate?
|
||||
invalid_reset_password_token: Pete un nove.
|
||||
link_to_otp: Insere un codice a duo factores o un codice de recuperation ab tu telephono
|
||||
link_to_webauth: Usa tu apparato clave de securitate
|
||||
log_in_with: Accede con
|
||||
login: Accede
|
||||
logout: Clauder le session
|
||||
migrate_account: Move a un conto differente
|
||||
migrate_account_html: Si tu vole re-adressar iste conto a un altere, tu pote <a href="%{path}">configurar lo ci</a>.
|
||||
or_log_in_with: O accede con
|
||||
privacy_policy_agreement_html: Io ha legite e acceptar le <a href="<a href="%{privacy_policy_path}" target="_blank">politica de confidentialitate</a>
|
||||
progress:
|
||||
|
@ -1192,6 +1202,7 @@ ia:
|
|||
invalid_domain: non es un nomine de dominio valide
|
||||
edit_profile:
|
||||
basic_information: Information basic
|
||||
hint_html: "<strong>Personalisa lo que le personas vide sur tu profilo public e presso tu messages.</strong> Il es plus probabile que altere personas te seque e interage con te quando tu ha un profilo compilate e un photo de profilo."
|
||||
other: Alteres
|
||||
errors:
|
||||
'400': Le requesta que tu inviava era non valide o mal formate.
|
||||
|
@ -1230,6 +1241,7 @@ ia:
|
|||
add_new: Adder nove
|
||||
errors:
|
||||
limit: Tu ha jam consiliate le maxime numero de hashtags
|
||||
hint_html: "<strong>Consilia tu plus importante hashtags sur tu profilo.</strong> Un grande instrumento pro tener tracia de tu labores creative e projectos de longe-tempore, le hashtags consiliate es monstrate prominentemente sur tu profilo e permitte accesso rapide a tu proprie messages."
|
||||
filters:
|
||||
contexts:
|
||||
account: Profilos
|
||||
|
@ -1241,8 +1253,10 @@ ia:
|
|||
add_keyword: Adder parola clave
|
||||
keywords: Parolas clave
|
||||
statuses: Messages individual
|
||||
statuses_hint_html: Iste filtro se applica a seliger messages singule sin reguardo si illes concorda le parolas clave infra. <a href="%{path}">Revide o remove le messages ab le filtro</a>.
|
||||
title: Modificar filtro
|
||||
errors:
|
||||
deprecated_api_multiple_keywords: Iste parametros non pote esser cambiate ab iste application perque illos se applica a plus que un sol parola clave del filtro. Usa un application plus recente o le interfacie web.
|
||||
invalid_context: Nulle o non valide contexto supplite
|
||||
index:
|
||||
contexts: Filtros in %{contexts}
|
||||
|
@ -1272,6 +1286,12 @@ ia:
|
|||
title: Messages filtrate
|
||||
generic:
|
||||
all: Toto
|
||||
all_items_on_page_selected_html:
|
||||
one: "<strong>%{count}</strong> elemento sur iste pagina es seligite."
|
||||
other: Tote le <strong>%{count}</strong> elementos sur iste pagina es seligite.
|
||||
all_matching_items_selected_html:
|
||||
one: "<strong>%{count}</strong> elemento concordante que tu cerca es seligite."
|
||||
other: Tote le <strong>%{count}</strong> elementos concordante que tu cerca es seligite.
|
||||
cancel: Cancellar
|
||||
changes_saved_msg: Cambios salveguardate con successo!
|
||||
confirm: Confirmar
|
||||
|
@ -1299,13 +1319,24 @@ ia:
|
|||
imported: Importate
|
||||
mismatched_types_warning: Il appare que tu pote haber seligite le typo errate pro iste importation, controla duo vices.
|
||||
modes:
|
||||
merge: Funder
|
||||
merge_long: Mantene le registrationes existente e adde illos nove
|
||||
overwrite: Superscriber
|
||||
overwrite_long: Reimplaciar registros actual con le noves
|
||||
overwrite_preambles:
|
||||
blocking_html: Tu es sur le puncto de <strong>reimplaciar tu lista de blocadas</strong> per usque a <strong>%{total_items} contos</strong> proveniente de <strong>%{filename}</strong>.
|
||||
bookmarks_html: Tu va <strong>reimplaciar tu lista de blocadas</strong> per usque a <strong>%{total_items} contos</strong> proveniente de <strong>%{filename}</strong>.
|
||||
domain_blocking_html: Tu es sur le puncto de <strong>reimplaciar tu lista de blocadas de dominio</strong> per usque a <strong>%{total_items} dominios</strong> proveniente de <strong>%{filename}</strong>.
|
||||
following_html: Tu va <strong>sequer</strong> usque <strong>%{total_items} contos</strong> de <strong>%{filename}</strong> e <strong>cessar de sequer ulle altere</strong>.
|
||||
lists_html: Tu va <strong>reimplaciar tu lista</strong> con contentos de <strong>%{filename}</strong>. Usque <strong>%{total_items} contos</strong> sera addite a nove listas.
|
||||
muting_html: Tu va <strong>reimplaciar tu lista de contos silentiate</strong> con usque <strong>%{total_items} contos</strong> ab <strong>%{filename}</strong>.
|
||||
preambles:
|
||||
blocking_html: Tu es sur le puncto de <strong>blocar</strong> usque a <strong>%{total_items} contos</strong> a partir de <strong>%{filename}</strong>.
|
||||
bookmarks_html: Tu va adder usque <strong>%{total_items} messages</strong> de <strong>%{filename}</strong> a tu <strong>marcapaginas</strong>.
|
||||
domain_blocking_html: Tu es sur le puncto de <strong>blocar</strong> usque a <strong>%{total_items} dominios</strong> a partir de <strong>%{filename}</strong>.
|
||||
following_html: Tu va <strong>blocar</strong> usque a <strong>%{total_items} dominios</strong> ab <strong>%{filename}</strong>.
|
||||
lists_html: Tu va adder usque <strong>%{total_items} contos</strong> ab <strong>%{filename}</strong> a tu <strong>lista</strong>. Nove listas sera create si il non ha lista a adder.
|
||||
muting_html: Tu va <strong>silentiar</strong> usque <strong>%{total_items} contos</strong> ab <strong>%{filename}</strong>.
|
||||
preface: Tu pote importar datos que tu ha exportate de un altere servitor, como un lista de personas que tu seque o bloca.
|
||||
recent_imports: Importationes recente
|
||||
states:
|
||||
|
@ -1348,16 +1379,30 @@ ia:
|
|||
expires_in_prompt: Nunquam
|
||||
generate: Generar ligamine de invitation
|
||||
invalid: Iste invitation non es valide
|
||||
invited_by: 'Tu ha essite invitate per:'
|
||||
max_uses:
|
||||
one: un uso
|
||||
other: "%{count} usos"
|
||||
max_uses_prompt: Nulle limite
|
||||
prompt: Genera e comparti ligamines con alteres pro conceder accesso a iste servitor
|
||||
table:
|
||||
expires_at: Expira
|
||||
uses: Usos
|
||||
title: Invitar personas
|
||||
lists:
|
||||
errors:
|
||||
limit: Tu ha attingite le maxime numero de listas
|
||||
login_activities:
|
||||
authentication_methods:
|
||||
otp: app pro authentication a duo factores
|
||||
password: contrasigno
|
||||
sign_in_token: codice de securitate de e-mail
|
||||
webauthn: claves de securitate
|
||||
description_html: Si tu vide activitate que tu non recognosce, considera de cambiar tu contrasigno e activar le authentication a duo factores.
|
||||
empty: Nulle chronologia de authentication disponibile
|
||||
failed_sign_in_html: Tentativa de authentication fallite con %{method} ab %{ip} (%{browser})
|
||||
successful_sign_in_html: Apertura de session con successo con %{method} ab %{ip} (%{browser})
|
||||
title: Chronologia de authentication
|
||||
mail_subscriptions:
|
||||
unsubscribe:
|
||||
action: Si, desubscriber
|
||||
|
@ -1373,32 +1418,110 @@ ia:
|
|||
resubscribe_html: Si tu ha cancellate le subscription in error, tu pote resubscriber te a partir del <a href="%{settings_path}">parametros de notification in e-mail</a>.
|
||||
success_html: Tu non recipera plus %{type} pro Mastodon sur %{domain} a tu adresse de e-mail %{email}.
|
||||
title: Desubcriber
|
||||
media_attachments:
|
||||
validations:
|
||||
images_and_video: Impossibile annexar un video a un message que jam contine imagines
|
||||
not_ready: Impossibile annexar un video a un message que jam contine imagines. Retenta post un momento!
|
||||
too_many: Impossibile annexar plus que 4 files
|
||||
migrations:
|
||||
acct: Movite a
|
||||
cancel: Cancellar redirection
|
||||
cancel_explanation: Cancellar le redirection reactivara tu conto actual, ma non reportara sequaces que ha essite movite in ille conto.
|
||||
cancelled_msg: Redirection cancellate con successo.
|
||||
errors:
|
||||
already_moved: is the same account you have already moved to
|
||||
missing_also_known_as: non es un alias de iste conto
|
||||
move_to_self: non pote esser le conto actual
|
||||
not_found: non poterea esser trovate
|
||||
on_cooldown: Tu es in pausa
|
||||
followers_count: Sequaces a tempore de mover
|
||||
incoming_migrations: Movente ab un conto differente
|
||||
incoming_migrations_html: Pro mover ab un altere conto a isto, primo tu debe <a href="%{path}">crear un alias de conto</a>.
|
||||
moved_msg: Tu conto ora es redirigite a %{acct} e tu sequaces es movite super.
|
||||
not_redirecting: Tu conto actualmente non es redirigite a ulle altere conto.
|
||||
on_cooldown: Tu recentemente ha migrate tu conto. Iste function de novo sera disponibile in %{count} dies.
|
||||
past_migrations: Migrationes passate
|
||||
proceed_with_move: Mover sequaces
|
||||
redirected_msg: Tu conto es ora redirigite a %{acct}.
|
||||
redirecting_to: Tu conto es redirigite a %{acct}.
|
||||
set_redirect: Predefinir redirection
|
||||
warning:
|
||||
backreference_required: Le nove conto debe primo esser configurate pro referer se a isto
|
||||
before: 'Ante de continuar, lege iste notas accuratemente:'
|
||||
cooldown: Post le movimento il ha un periodo de pausa durante le qual tu non potera mover te ancora
|
||||
disabled_account: Tu conto actual non sera plenmente usabile postea. Comocunque, tu habera accesso a exportation de datos e re-activation.
|
||||
followers: Iste action movera tote le sequaces ab le conto actual al nove conto
|
||||
only_redirect_html: In alternativa, tu pote <a href="%{path}">solo superponer un redirection sur tu profilo</a>.
|
||||
other_data: Nulle altere datos sera movite automaticamente
|
||||
redirect: Le profilo de tu conto actual sera actualisate con un aviso de redirection e sera excludite de recercas
|
||||
moderation:
|
||||
title: Moderation
|
||||
move_handler:
|
||||
carry_blocks_over_text: Iste usator ha cambiate de conto desde %{acct}, que tu habeva blocate.
|
||||
carry_mutes_over_text: Iste usator moveva ab %{acct}, que tu habeva silentiate.
|
||||
copy_account_note_text: 'Iste usator moveva ab %{acct}, ci era tu previe notas re ille:'
|
||||
navigation:
|
||||
toggle_menu: Mutar menu
|
||||
notification_mailer:
|
||||
admin:
|
||||
report:
|
||||
subject: "%{name} inviava un reporto"
|
||||
sign_up:
|
||||
subject: "%{name} se ha inscribite"
|
||||
favourite:
|
||||
body: 'Tu message era favorite per %{name}:'
|
||||
subject: "%{name} favoriva tu message"
|
||||
title: Nove preferito
|
||||
follow:
|
||||
body: "%{name} ora te seque!"
|
||||
subject: "%{name} ora te seque"
|
||||
title: Nove sequitor
|
||||
follow_request:
|
||||
action: Gere requestas de sequer
|
||||
body: "%{name} ha demandate de sequer te"
|
||||
subject: 'Sequace pendente: %{name}'
|
||||
title: Nove requesta de sequimento
|
||||
mention:
|
||||
action: Responder
|
||||
body: 'Tu era mentionate per %{name} in:'
|
||||
subject: Tu ha essite mentionate per %{name}
|
||||
title: Nove mention
|
||||
poll:
|
||||
subject: Un inquesta de %{name} ha finite
|
||||
reblog:
|
||||
body: 'Tu message ha essite impulsate per %{name}:'
|
||||
subject: "%{name} ha impulsate tu message"
|
||||
title: Nove impulso
|
||||
status:
|
||||
subject: "%{name} justo ha publicate"
|
||||
update:
|
||||
subject: "%{name} ha modificate un message"
|
||||
notifications:
|
||||
administration_emails: Avisos de email per administrator
|
||||
email_events: Eventos pro avisos de email
|
||||
email_events_hint: 'Selige eventos pro que tu vole reciper avisos:'
|
||||
number:
|
||||
human:
|
||||
decimal_units:
|
||||
format: "%n%u"
|
||||
units:
|
||||
billion: B
|
||||
million: M
|
||||
quadrillion: Q
|
||||
thousand: K
|
||||
trillion: T
|
||||
otp_authentication:
|
||||
code_hint: Insere le codice generate per tu app de authentication pro confirmar
|
||||
description_html: Si tu activa <strong>le authentication a duo factores</strong> per un app de authentication, le authentication requirera que tu es in possession de tu telephono, que generara testimonios pro facer te entrar.
|
||||
enable: Activar
|
||||
instructions_html: "<strong>Scande iste codice QR in Google Authenticator o un simile app TOTP sur tu telephono</strong>. Desde ora in avante, ille app generara testimonios que tu debera inserer quando tu te authenticara."
|
||||
manual_instructions: 'Si tu non pote scander le codice QR e besonia de inserer lo manualmente, ecce le texto-simple secrete:'
|
||||
setup: Configurar
|
||||
wrong_code: Le codice inserite non era valide! Es tempore de servitor e tempore de apparato correcte?
|
||||
pagination:
|
||||
newer: Plus recente
|
||||
next: Sequente
|
||||
older: Plus vetere
|
||||
prev: Previe
|
||||
truncate: "…"
|
||||
polls:
|
||||
|
@ -1418,9 +1541,13 @@ ia:
|
|||
posting_defaults: Publicationes predefinite
|
||||
public_timelines: Chronologias public
|
||||
privacy:
|
||||
hint_html: "<strong>Personalisa como tu vole que tu profilo e tu messages a es trovate.</strong> Un varietate de functiones in Mastodon pote adjutar te attinger un plus large auditorio si activate. Prende un momento pro revider iste parametros pro assecurar te que illos se adapta a tu caso de uso."
|
||||
privacy: Confidentialitate
|
||||
privacy_hint_html: Controla quanto tu vole divulgar pro le beneficio de alteres. Le gente discoperi profilos e applicationes interessante percurrente le profilos sequite per altere personas e vidente a partir de qual applicationes illos publica lor messages, ma tu pote preferer de mantener tal information private.
|
||||
reach: Portata
|
||||
reach_hint_html: Controla si tu vole esser discoperite e sequite per nove personas. Vole tu que tu messages appare sur le schermo Explorar? Vole tu que altere personas te vide in lor recommendationes de sequimento? Vole tu acceptar automaticamente tote le nove sequitores o prefere tu haber le controlo granular super cata un?
|
||||
search: Cercar
|
||||
search_hint_html: Controla como tu vole esser trovate. Vole tu que le gente te trova per medio del contento de tu messages public? Vole tu que personas foras de Mastodon trova tu profilo quando illes cerca in le web? Nota ben que non es possibile garantir le exclusion total de tu information public del motores de recerca.
|
||||
title: Confidentialitate e portata
|
||||
privacy_policy:
|
||||
title: Politica de confidentialitate
|
||||
|
@ -1521,35 +1648,96 @@ ia:
|
|||
aliases: Aliases de conto
|
||||
appearance: Apparentia
|
||||
authorized_apps: Apps autorisate
|
||||
back: Tornar a Mastodon
|
||||
delete: Deletion de conto
|
||||
development: Disveloppamento
|
||||
edit_profile: Modificar profilo
|
||||
export: Exportation de datos
|
||||
featured_tags: Hashtags eminente
|
||||
import: Importar
|
||||
import_and_export: Importar e exportar
|
||||
migrate: Migration de conto
|
||||
notifications: Notificationes de e-mail
|
||||
preferences: Preferentias
|
||||
profile: Profilo public
|
||||
relationships: Sequites e sequitores
|
||||
severed_relationships: Relationes rupte
|
||||
statuses_cleanup: Deletion de message automatic
|
||||
strikes: Admonitiones de moderation
|
||||
two_factor_authentication: Authentication a duo factores
|
||||
webauthn_authentication: Claves de securitate
|
||||
severed_relationships:
|
||||
download: Discargar (%{count})
|
||||
event_type:
|
||||
account_suspension: Suspension del conto (%{target_name})
|
||||
domain_block: Suspension del servitor (%{target_name})
|
||||
user_domain_block: Tu ha blocate %{target_name}
|
||||
lost_followers: Sequitores perdite
|
||||
lost_follows: Sequites perdite
|
||||
preamble: Tu pote perder sequites e sequitores quando tu bloca un dominio o quando tu moderatores decide suspender un servitor remote. Quando isto occurre, tu potera discargar listas de relationes rumpite, a inspectar e eventualmente importar in un altere servitor.
|
||||
purged: Le information re iste servitor ha essite purgate per le administratores de tu servitor.
|
||||
type: Evento
|
||||
statuses:
|
||||
attached:
|
||||
audio:
|
||||
one: "%{count} audio"
|
||||
other: "%{count} audio"
|
||||
description: 'Attachate: %{attached}'
|
||||
image:
|
||||
one: "%{count} imagine"
|
||||
other: "%{count} imagines"
|
||||
video:
|
||||
one: "%{count} video"
|
||||
other: "%{count} videos"
|
||||
boosted_from_html: Impulsate desde %{acct_link}
|
||||
content_warning: 'Advertimento de contento: %{warning}'
|
||||
default_language: Mesme como lingua de interfacie
|
||||
disallowed_hashtags:
|
||||
one: 'contineva un hashtag non autorisate: %{tags}'
|
||||
other: 'contineva le hashtags non autorisate: %{tags}'
|
||||
edited_at_html: Modificate le %{date}
|
||||
errors:
|
||||
in_reply_not_found: Le message a que tu tenta responder non pare exister.
|
||||
open_in_web: Aperir in le web
|
||||
over_character_limit: limite de characteres de %{max} excedite
|
||||
pin_errors:
|
||||
direct: Messages que es solo visibile a usatores mentionate non pote esser appunctate
|
||||
limit: Tu ha jam appunctate le maxime numero de messages
|
||||
ownership: Le message de alcuno altere non pote esser appunctate
|
||||
reblog: Un impulso non pote esser affixate
|
||||
poll:
|
||||
total_people:
|
||||
one: "%{count} persona"
|
||||
other: "%{count} personas"
|
||||
total_votes:
|
||||
one: "%{count} voto"
|
||||
other: "%{count} votos"
|
||||
vote: Votar
|
||||
show_more: Monstrar plus
|
||||
show_thread: Monstrar argumento
|
||||
title: '%{name}: "%{quote}"'
|
||||
visibilities:
|
||||
direct: Directe
|
||||
private: Solo-sequaces
|
||||
private_long: Solmente monstrar a sequitores
|
||||
public: Public
|
||||
public_long: Omnes pote vider
|
||||
unlisted: Non listate
|
||||
unlisted_long: Omnes pote vider, ma non es listate in le chronologias public
|
||||
statuses_cleanup:
|
||||
enabled: Deler automaticamente le messages ancian
|
||||
enabled_hint: Dele automaticamente tu messages un vice que illos attinge un limine de etate specificate, salvo que illes concorda un del exceptiones infra
|
||||
exceptions: Exceptiones
|
||||
explanation: Pois que deler messages es un operation costose, isto es facite lentemente in le tempore quando le servitor non es alteremente occupate. Pro iste ration, tu messages pote esser delite un poco post que illos attinge le limine de etate.
|
||||
ignore_favs: Ignorar favoritos
|
||||
ignore_reblogs: Ignorar impulsos
|
||||
interaction_exceptions: Exceptiones basate super interactiones
|
||||
interaction_exceptions_explanation: Nota que il non ha garantia que le messages essera delite si illos va sub le limine de favorites o impulsos post haber lo superate un vice.
|
||||
keep_direct: Mantener le messages directe
|
||||
keep_direct_hint: Non dele alcuno de tu messages directe
|
||||
keep_media: Mantener messages con annexos de medios
|
||||
keep_media_hint: Non dele alcuno de tu messages que ha annexos de medios
|
||||
keep_pinned: Mantener messages appunctate
|
||||
keep_pinned_hint: Non dele alcuno de tu messages appunctate
|
||||
keep_polls: Mantener sondages
|
||||
keep_polls_hint: Non dele ulle de tu sondages
|
||||
|
@ -1567,32 +1755,94 @@ ia:
|
|||
'63113904': 2 annos
|
||||
'7889238': 3 menses
|
||||
min_age_label: Limine de etate
|
||||
min_favs: Mantener messages favorite al minus
|
||||
min_favs_hint: Non deler alcuno de tu messages que ha recipite al minus iste numero de favoritos. Lassar blanc pro deler messages sin reguardo de lor numero de favoritos
|
||||
min_reblogs: Mantener messages impulsate al minus
|
||||
min_reblogs_hint: Non dele alcun de tu messages que ha essite impulsate al minus iste numero de vices. Lassar vacue pro deler messages independentemente de lor numero de impulsos
|
||||
stream_entries:
|
||||
sensitive_content: Contento sensibile
|
||||
strikes:
|
||||
errors:
|
||||
too_late: Es troppo tarde pro facer appello contra iste admonition
|
||||
tags:
|
||||
does_not_match_previous_name: non concorda le nomine previe
|
||||
themes:
|
||||
contrast: Mastodon (Alte contrasto)
|
||||
default: Mastodon (Obscur)
|
||||
mastodon-light: Mastodon (Clar)
|
||||
system: Automatic (usar thema del systema)
|
||||
time:
|
||||
formats:
|
||||
default: "%d %b %Y, %H:%M"
|
||||
month: "%b %Y"
|
||||
time: "%H:%M"
|
||||
with_time_zone: "%b %d, %Y, %H:%M %Z"
|
||||
translation:
|
||||
errors:
|
||||
quota_exceeded: Le quota de utilisation del servitor pro le servicio de traduction ha essite excedite.
|
||||
too_many_requests: Il ha habite troppe requestas al servicio de traduction recentemente.
|
||||
two_factor_authentication:
|
||||
add: Adder
|
||||
disable: Disactivar 2FA
|
||||
disabled_success: Authentication a duo factores disactivate con successo
|
||||
edit: Modificar
|
||||
enabled: Le authentication a duo factores es activate
|
||||
enabled_success: Authentication a duo factores activate con successo
|
||||
generate_recovery_codes: Generar codices de recuperation
|
||||
lost_recovery_codes: Le codices de recuperation te permitte de reganiar accesso a tu conto si tu perde tu telephono. Si tu ha perdite tu codices de recuperation, tu pote regenerar los ci. Tu vetere codices de recuperation sera invalidate.
|
||||
methods: Methodos a duo factores
|
||||
otp: App de authenticator
|
||||
recovery_codes: Salveguardar codices de recuperation
|
||||
recovery_codes_regenerated: Codices de recuperation regenerate con successo
|
||||
recovery_instructions_html: Si tu perde le accesso a tu telephono, tu pote usar un del codices de recuperation hic infra pro reganiar le accesso a tu conto. <strong>Mantene le codices de recuperation secur.</strong> Per exemplo, tu pote imprimer los e guardar los con altere documentos importante.
|
||||
webauthn: Claves de securitate
|
||||
user_mailer:
|
||||
appeal_approved:
|
||||
action: Parametros de conto
|
||||
explanation: Le appello contra le admonition contra tu conto del %{strike_date}, que tu ha submittite le %{appeal_date}, ha essite approbate. Tu conto ha de novo un bon reputation.
|
||||
subject: Tu appello ab %{date} ha essite approbate
|
||||
subtitle: Tu conto es ancora un vice in regula.
|
||||
title: Appello approbate
|
||||
appeal_rejected:
|
||||
explanation: Le appello contra le admonition contra tu conto del %{strike_date}, que tu ha submittite le %{appeal_date}, ha essite rejectate.
|
||||
subject: Tu appello ab %{date} ha essite rejectate
|
||||
subtitle: Tu appello ha essite rejectate.
|
||||
title: Appello rejectate
|
||||
backup_ready:
|
||||
explanation: Tu ha requestate un copia de securitate complete de tu conto de Mastodon.
|
||||
extra: Isto es preste pro discargar!
|
||||
subject: Tu archivo es preste pro discargar
|
||||
title: Discargar archivo
|
||||
failed_2fa:
|
||||
details: 'Hic es le detalios del tentativa de initio de session:'
|
||||
explanation: Alcuno ha tentate aperir session a tu conto ma ha fornite un secunde factor de authentication non valide.
|
||||
further_actions_html: Si non se tractava de te, nos recommenda %{action} immediatemente perque illo pote esser compromittite.
|
||||
subject: Fallimento del authentication de duo factores
|
||||
title: Falleva le authentication de duo factores
|
||||
suspicious_sign_in:
|
||||
change_password: cambiar tu contrasigno
|
||||
details: 'Hic es le detalios del initio de session:'
|
||||
explanation: Nos ha detegite un initio de session a tu conto ab un nove adresse IP.
|
||||
further_actions_html: Si non se tractava de te, nos recommenda %{action} immediatemente e activar le authentication bifactorial pro mantener tu conto secur.
|
||||
subject: Alcuno ha accedite a tu conto desde un nove adresse IP
|
||||
title: Un nove initio de session
|
||||
warning:
|
||||
appeal: Submitter un appello
|
||||
appeal_description: Si tu crede que se tracta de un error, tu pote presentar un appello al personal de %{instance}.
|
||||
categories:
|
||||
spam: Spam
|
||||
violation: Le contento viola le sequente regulas del communitate
|
||||
explanation:
|
||||
delete_statuses: Alcunes de tu messages ha essite judicate contrari a un o plus directivas communitari e ha dunque essite removite per le moderatores de %{instance}.
|
||||
disable: Tu non pote plus usar tu conto, ma tu profilo e altere datos remane intacte. Tu pote requestar un copia de reserva de tu datos, cambiar le parametros del conto o deler le conto.
|
||||
mark_statuses_as_sensitive: Alcunes de tu messages ha essite marcate como sensibile per le moderatores de %{instance}. Isto vole dicer que le gente debe toccar le objectos multimedial in le messages ante que un previsualisation appare. Tu pote marcar objectos multimedial como sensibile tu mesme quando tu publica messages in futuro.
|
||||
sensitive: A partir de iste momento, tote le files multimedial que tu incarga essera marcate como sensibile e le gente debera cliccar sur un advertimento ante de poter vider los.
|
||||
silence: Tu pote ancora usar tu conto ma solmente le personas qui ja te seque videra tu messages sur iste servitor, e tu pote esser excludite de varie functiones de discoperta. Nonobstante, altere personas pote ancora sequer te manualmente.
|
||||
suspend: Tu non pote plus usar tu conto, e tu profilo e altere datos non es plus accessibile. Tu pote ancora aperir session pro requestar un copia de reserva de tu datos usque lor elimination in circa 30 dies. Nos retenera certe datos de base pro impedir que tu evade le suspension.
|
||||
reason: 'Ration:'
|
||||
statuses: 'Message citate:'
|
||||
subject:
|
||||
delete_statuses: Tu messages sur %{acct} esseva removite
|
||||
disable: Tu conto %{acct} ha essite gelate
|
||||
mark_statuses_as_sensitive: Tu messages sur %{acct} ha essite marcate como sensibile
|
||||
none: Advertimento pro %{acct}
|
||||
|
@ -1612,20 +1862,71 @@ ia:
|
|||
apps_ios_action: Discargar sur le App Store
|
||||
apps_step: Discarga nostre applicationes official.
|
||||
apps_title: Applicationes de Mastodon
|
||||
checklist_subtitle: 'Comencia tu aventura sur le web social:'
|
||||
checklist_title: Prime passos
|
||||
edit_profile_action: Personalisar
|
||||
edit_profile_step: Impulsa tu interactiones con un profilo comprehensive.
|
||||
edit_profile_title: Personalisar tu profilo
|
||||
explanation: Ecce alcun consilios pro initiar
|
||||
feature_action: Apprender plus
|
||||
feature_audience: Mastodon te presenta le possibilitate unic de gerer tu audientia sin intermediarios. Mastodon, installate sur tu proprie infrastructura, te permitte sequer, e esser sequite per, personas sur qualcunque altere servitor Mastodon in linea, e necuno lo controla salvo tu.
|
||||
feature_audience_title: Crea tu auditorio in fiducia
|
||||
feature_control: Tu sape melio lo que tu vole vider sur tu fluxo de initio. Nulle algorithmos o annuncios dissipa tu tempore. Seque quicinque sur qualcunque servitor Mastodon desde un sol conto, recipe lor messages in ordine chronologic, e face te un angulo del internet ubi tu te senti a casa.
|
||||
feature_control_title: Mantene le controlo de tu proprie chronologia
|
||||
feature_creativity: Mastodon supporta messages con audio, video e imagines, descriptiones de accessibilitate, sondages, advertimentos de contento, avatares con animation, emojis personalisate, controlo de retalio de miniaturas, e plus, pro adjutar te a exprimer te in linea. Que tu publica tu arte, tu musica o tu podcast, Mastodon existe pro te.
|
||||
feature_creativity_title: Creativitate sin parallel
|
||||
feature_moderation: Mastodon remitte le controlo in tu manos. Cata servitor crea su proprie regulas e directivas, applicate localmente e non de maniera vertical como le medios social corporative, rendente lo flexibile in responder al necessitates de differente gruppos de personas. Adhere a un servitor con regulas que te place, o alberga le tue.
|
||||
feature_moderation_title: Moderation como deberea esser
|
||||
follow_action: Sequer
|
||||
follow_step: Sequer personas interessante es le ration de esser de Mastodon.
|
||||
follow_title: Personalisa tu fluxo de initio
|
||||
follows_subtitle: Seque contos popular
|
||||
follows_title: Qui sequer
|
||||
follows_view_more: Vider plus de personas a sequer
|
||||
hashtags_recent_count:
|
||||
one: "%{people} persona in le passate duo dies"
|
||||
other: "%{people} personas in le passate duo diea"
|
||||
hashtags_subtitle: Explora le tendentias del passate 2 dies
|
||||
hashtags_title: Hashtags in tendentia
|
||||
hashtags_view_more: Vider plus de hashtags in tendentia
|
||||
post_action: Scriber
|
||||
post_step: Saluta le mundo con texto, photos, videos o sondages.
|
||||
post_title: Face tu prime message
|
||||
share_action: Compartir
|
||||
share_step: Face saper a tu amicos como trovar te sur Mastodon.
|
||||
share_title: Compartir tu profilo de Mastodon
|
||||
sign_in_action: Initiar session
|
||||
subject: Benvenite in Mastodon
|
||||
title: Benvenite a bordo, %{name}!
|
||||
users:
|
||||
follow_limit_reached: Tu non pote sequer plus de %{limit} personas
|
||||
go_to_sso_account_settings: Vader al parametros de conto de tu fornitor de identitate
|
||||
invalid_otp_token: Codice de duo factores non valide
|
||||
otp_lost_help_html: Si tu ha perdite le accesso a ambes, tu pote contactar %{email}
|
||||
rate_limited: Troppo de tentativas de authentication. Per favor reessaya plus tarde.
|
||||
seamless_external_login: Tu ha aperite session per medio de un servicio externe. Le parametros de contrasigno e de e-mail es dunque indisponibile.
|
||||
signed_in_as: 'Session aperite como:'
|
||||
verification:
|
||||
extra_instructions_html: <strong>Consilio:</strong> Le ligamine sur tu sito web pote esser invisibile. Le parte importante es <code>rel="me"</code> que impedi le usurpation de identitate sur sitos web con contento generate per usatores. Tu pote mesmo usar un etiquetta <code>link</code> in le capite del pagina in vice de <code>a</code>, ma le codice HTML debe esser accessibile sin executar JavaScript.
|
||||
here_is_how: Ecce como
|
||||
hint_html: "<strong>Omnes pote verificar lor identitate sur Mastodon.</strong> Isto es basate sur standards web aperte e es gratuite, ora e pro sempre. Tote lo que es necessari es un sito web personal que le gente recognosce como le tue. Quando tu liga a iste sito web desde tu profilo, le systema verificara que le sito web liga retro a tu profilo e monstrara un indicator visual de iste facto."
|
||||
instructions_html: Copia e colla le codice hic infra in le HTML de tu sito web. Alora adde le adresse de tu sito web in un del campos supplementari sur tu profilo desde le scheda “Modificar profilo” e salva le cambiamentos.
|
||||
verification: Verification
|
||||
verified_links: Tu ligamines verificate
|
||||
webauthn_credentials:
|
||||
add: Adder un nove clave de securitate
|
||||
create:
|
||||
error: Il habeva un problema in adder tu clave de securitate. Tenta novemente.
|
||||
success: Tu clave de securitate ha essite addite con successo.
|
||||
delete: Deler
|
||||
delete_confirmation: Es tu secur que tu vole deler iste clave de securitate?
|
||||
description_html: Si tu activa le <strong>authentication per clave de securitate</strong>, le apertura de session requirera que tu usa un de tu claves de securitate.
|
||||
destroy:
|
||||
error: Il habeva un problema in deler tu clave de securitate. Tenta novemente.
|
||||
success: Tu clave de securitate ha essite delite con successo.
|
||||
invalid_credential: Clave de securitate non valide
|
||||
nickname_hint: Insere le pseudonymo de tu nove clave de securitate
|
||||
not_enabled: Tu ancora non ha activate WebAuthn
|
||||
not_supported: Iste navigator non supporta claves de securitate
|
||||
otp_required: Pro usar le claves de securitate activa prime le authentication de duo factores.
|
||||
registered_on: Registrate le %{date}
|
||||
|
|
|
@ -285,6 +285,7 @@ it:
|
|||
update_custom_emoji_html: "%{name} ha aggiornato emoji %{target}"
|
||||
update_domain_block_html: "%{name} ha aggiornato il blocco dominio per %{target}"
|
||||
update_ip_block_html: "%{name} ha cambiato la regola per l'IP %{target}"
|
||||
update_report_html: "%{name} ha aggiornato la segnalazione %{target}"
|
||||
update_status_html: "%{name} ha aggiornato lo status di %{target}"
|
||||
update_user_role_html: "%{name} ha modificato il ruolo %{target}"
|
||||
deleted_account: account eliminato
|
||||
|
|
|
@ -282,6 +282,7 @@ ko:
|
|||
update_custom_emoji_html: "%{name} 님이 에모지 %{target}를 업데이트 했습니다"
|
||||
update_domain_block_html: "%{name} 님이 %{target}에 대한 도메인 차단을 갱신했습니다"
|
||||
update_ip_block_html: "%{name} 님이 IP 규칙 %{target}을 수정했습니다"
|
||||
update_report_html: "%{name} 님이 신고 %{target}를 업데이트 했습니다"
|
||||
update_status_html: "%{name} 님이 %{target}의 게시물을 업데이트했습니다"
|
||||
update_user_role_html: "%{name} 님이 %{target} 역할을 수정했습니다"
|
||||
deleted_account: 계정을 삭제했습니다
|
||||
|
|
|
@ -285,6 +285,7 @@ lad:
|
|||
update_custom_emoji_html: "%{name} aktualizo el emoji %{target}"
|
||||
update_domain_block_html: "%{name} aktualizo el bloko de domeno para %{target}"
|
||||
update_ip_block_html: "\"%{name} troko la regla de IP %{target}"
|
||||
update_report_html: "%{name} aktualizo el raporto %{target}"
|
||||
update_status_html: "%{name} aktualizo la publikasyon de %{target}"
|
||||
update_user_role_html: "%{name} troko el rolo %{target}"
|
||||
deleted_account: kuento supremido
|
||||
|
|
|
@ -285,6 +285,7 @@ nl:
|
|||
update_custom_emoji_html: Emoji %{target} is door %{name} bijgewerkt
|
||||
update_domain_block_html: "%{name} heeft de domeinblokkade bijgewerkt voor %{target}"
|
||||
update_ip_block_html: "%{name} wijzigde de IP-regel voor %{target}"
|
||||
update_report_html: Rapportage %{target} is door %{name} bijgewerkt
|
||||
update_status_html: "%{name} heeft de berichten van %{target} bijgewerkt"
|
||||
update_user_role_html: "%{name} wijzigde de rol %{target}"
|
||||
deleted_account: verwijderd account
|
||||
|
|
|
@ -291,6 +291,7 @@ pl:
|
|||
update_custom_emoji_html: Zaktualizowane emoji %{target} przez %{name}
|
||||
update_domain_block_html: Zaktualizowano blokadę domeny dla %{target} przez %{name}
|
||||
update_ip_block_html: "%{name} stworzył(a) regułę dla IP %{target}"
|
||||
update_report_html: "%{target} zaktualizowany przez %{name}"
|
||||
update_status_html: "%{name} zaktualizował(a) wpis użytkownika %{target}"
|
||||
update_user_role_html: "%{name} zmienił rolę %{target}"
|
||||
deleted_account: usunięte konto
|
||||
|
|
|
@ -285,6 +285,7 @@ pt-PT:
|
|||
update_custom_emoji_html: "%{name} atualizou o emoji %{target}"
|
||||
update_domain_block_html: "%{name} atualizou o bloqueio de domínio para %{target}"
|
||||
update_ip_block_html: "%{name} alterou regra para IP %{target}"
|
||||
update_report_html: "%{name} atualizou a denúncia %{target}"
|
||||
update_status_html: "%{name} atualizou o estado de %{target}"
|
||||
update_user_role_html: "%{name} alterou a função %{target}"
|
||||
deleted_account: conta apagada
|
||||
|
|
|
@ -78,14 +78,14 @@ fi:
|
|||
form_admin_settings:
|
||||
activity_api_enabled: Paikallisesti julkaistujen julkaisujen, aktiivisten käyttäjien ja rekisteröitymisten viikoittainen määrä
|
||||
app_icon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen mobiililaitteiden sovelluskuvakkeen omalla kuvakkeella.
|
||||
backups_retention_period: Käyttäjillä on mahdollisuus arkistoida julkaisujaan myöhemmin ladattaviksi. Kun tämä on asetettu positiiviseksi arvoksi, nämä arkistot poistetaan automaattisesti asetetun päivien määrän jälkeen.
|
||||
backups_retention_period: Käyttäjillä on mahdollisuus arkistoida julkaisujaan myöhemmin ladattaviksi. Kun arvo on positiivinen, nämä arkistot poistuvat automaattisesti, kun määritetty määrä päiviä on kulunut.
|
||||
bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien seuraamissuosituslistojen alkuun.
|
||||
closed_registrations_message: Näkyy, kun rekisteröityminen on suljettu
|
||||
content_cache_retention_period: Kaikki muiden palvelimien viestit (mukaan lukien tehostukset ja vastaukset) poistetaan määritetyn päivien lukumäärän jälkeen, ottamatta huomioon paikallisen käyttäjän vuorovaikutusta kyseisten viestien kanssa. Sisältää viestit, jossa paikallinen käyttäjä on merkinnyt kirjanmerkiksi tai suosikeiksi. Myös yksityiset maininnat eri käyttäjien välillä menetetään, eikä niitä voi palauttaa. Tämän asetuksen käyttö on tarkoitettu erityisiin tapauksiin ja se rikkoo monia käyttäjien odotuksia, kun se toteutetaan yleistarkoituksiin.
|
||||
content_cache_retention_period: Kaikki muiden palvelinten julkaisut (mukaan lukien tehostukset ja vastaukset) poistuvat, kun määritetty määrä päiviä on kulunut, ottamatta huomioon paikallisen käyttäjän vuorovaikutusta näiden julkaisujen kanssa. Sisältää julkaisut, jotka paikallinen käyttäjä on merkinnyt kirjanmerkiksi tai suosikiksi. Myös yksityiset maininnat eri palvelinten käyttäjien välillä menetetään, eikä niitä voi palauttaa. Tämä asetus on tarkoitettu käytettäväksi erityistapauksissa ja rikkoo monia käyttäjien odotuksia, kun sitä käytetään yleistarkoituksiin.
|
||||
custom_css: Voit käyttää mukautettuja tyylejä Mastodonin verkkoversiossa.
|
||||
favicon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen Mastodonin suosikkikuvakkeen omalla kuvakkeella.
|
||||
mascot: Ohittaa kuvituksen edistyneessä selainkäyttöliittymässä.
|
||||
media_cache_retention_period: Mediatiedostot käyttäjien tekemistä viesteistä ovat välimuistissa palvelimellasi. Kun arvo on positiivinen, media poistetaan määritetyn ajan jälkeen. Jos mediaa pyydetään sen poistamisen jälkeen, ne ladataan uudelleen, jos lähdesisältö on vielä saatavilla. Koska linkkien katselun kyselyitä kolmansien osapuolien sivustoille on rajoitettu, on suositeltavaa asettaa tämä arvo vähintään 14 päivään tai linkkien kortteja ei päivitetä pyynnöstä ennen tätä aikaa.
|
||||
media_cache_retention_period: Käyttäjien tekemien julkaisujen mediatiedostot ovat välimuistissa palvelimellasi. Kun arvo on positiivinen, media poistuu, kun määritetty määrä päiviä on kulunut. Jos mediaa pyydetään sen poistamisen jälkeen, se ladataan uudelleen, jos lähdesisältö on vielä saatavilla. Koska linkkien esikatselun kyselyitä kolmansien osapuolien sivustoille on rajoitettu, on suositeltavaa asettaa tämä arvo vähintään 14 päivään, tai linkkien kortteja ei päivitetä pyynnöstä ennen tätä ajankohtaa.
|
||||
peers_api_enabled: Luettelo verkkotunnuksista, jotka tämä palvelin on kohdannut fediversumissa. Se ei kerro, oletko liitossa tietyn palvelimen kanssa, vaan että palvelimesi on ylipäätään tietoinen siitä. Tätä tietoa käytetään palveluissa, jotka keräävät tilastoja federoinnista yleisellä tasolla.
|
||||
profile_directory: Profiilihakemisto lueteloi kaikki käyttäjät, jotka ovat ilmoittaneet olevansa löydettävissä.
|
||||
require_invite_text: Kun rekisteröityminen vaatii manuaalisen hyväksynnän, tee ”Miksi haluat liittyä?” -tekstikentästä pakollinen vapaaehtoisen sijaan
|
||||
|
|
|
@ -77,10 +77,15 @@ sl:
|
|||
warn: Skrij filtrirano vsebino za opozorilom, ki pomenja naslov filtra
|
||||
form_admin_settings:
|
||||
activity_api_enabled: Številke krajevno objavljenih objav, dejavnih uporabnikov in novih registracij na tedenskih seznamih
|
||||
app_icon: WEBP, PNG, GIF ali JPG. Zamenja privzeto ikono programa na mobilnih napravah z ikono po meri.
|
||||
backups_retention_period: Uporabniki lahko ustvarijo arhive svojih objav za kasnejši prenos k sebi. Ko je nastavljeno na pozitivno vrednost, bodo ti arhivi po nastavljenem številu dni samodejno izbrisani.
|
||||
bootstrap_timeline_accounts: Ti računi bodo pripeti na vrh priporočenih sledenj za nove uporabnike.
|
||||
closed_registrations_message: Prikazano, ko so registracije zaprte
|
||||
content_cache_retention_period: Vse objave z drugih strežnikov (vključno z izpostavitvami in odgovori) bodo izbrisani po nastavljenem številu dni, ne glede na krajevne interakcije s temi objavami. To vključuje objave, ki jih je krajevni uporabnik dodal med zaznamke ali priljubljene. Zasebne omembe med uporabniki na različnih strežnikih bodo prav tako izgubljene in jih ne bo moč obnoviti. Uporaba te nastavitve je namenjena strežnikom s posebnim namenom in nasprotuje mnogim pričakovanjem uporabnikov na strežnikih za splošni namen.
|
||||
custom_css: Spletni različici Mastodona lahko uveljavite sloge po meri.
|
||||
favicon: WEBP, PNG, GIF ali JPG. Zamenja privzeto ikono spletne strani Mastodon z ikono po meri.
|
||||
mascot: Preglasi ilustracijo v naprednem spletnem vmesniku.
|
||||
media_cache_retention_period: Predstavnostne datoteke iz objav uporabnikov na ostalih strežnikih se začasno hranijo na tem strežniku. Ko je nastavljeno na pozitivno vrednost, bodo predstavnostne datoteke izbrisane po nastavljenem številu dni. Če bo predstavnostna datoteka zahtevana po izbrisu, bo ponovno prenešena, če bo vir še vedno na voljo. Zaradi omejitev pogostosti prejemanja predogledov povezav z drugih strani je priporočljivo to vrednost nastaviti na vsaj 14 dni. V nasprotnem predogledi povezav pred tem časom ne bodo osveženi na zahtevo.
|
||||
peers_api_enabled: Seznam imen domen, na katere je ta strežnik naletel v fediverzumu. Sem niso vključeni podatki o tem, ali ste v federaciji z danim strežnikom, zgolj to, ali vaš strežnik ve zanj. To uporabljajo storitve, ki zbirajo statistične podatke o federaciji v splošnem smislu.
|
||||
profile_directory: Imenik profilov izpiše vse uporabnike, ki so dovolili, da so v njem navedeni.
|
||||
require_invite_text: Če registracije zahtevajo ročno potrditev, nastavite vnos besedila pod »Zakaj se želite pridružiti?« za obveznega.
|
||||
|
@ -240,6 +245,7 @@ sl:
|
|||
backups_retention_period: Obdobje hrambe arhivov uporabnikov
|
||||
bootstrap_timeline_accounts: Vedno priporočaj te račune novim uporabnikom
|
||||
closed_registrations_message: Sporočilo po meri, ko registracije niso na voljo
|
||||
content_cache_retention_period: Obdobje hranjenja vsebine z ostalih strežnikov
|
||||
custom_css: CSS po meri
|
||||
mascot: Maskota po meri (opuščeno)
|
||||
media_cache_retention_period: Obdobje hrambe predpomnilnika predstavnosti
|
||||
|
|
|
@ -291,6 +291,7 @@ sl:
|
|||
update_custom_emoji_html: "%{name} je posodobil/a emotikone %{target}"
|
||||
update_domain_block_html: "%{name} je posodobil/a domenski blok za %{target}"
|
||||
update_ip_block_html: "%{name} je spremenil/a pravilo za IP %{target}"
|
||||
update_report_html: "%{name} je posodobil poročilo %{target}"
|
||||
update_status_html: "%{name} je posodobil/a objavo uporabnika %{target}"
|
||||
update_user_role_html: "%{name} je spremenil/a vlogo %{target}"
|
||||
deleted_account: izbrisan račun
|
||||
|
|
|
@ -288,6 +288,7 @@ sr-Latn:
|
|||
update_custom_emoji_html: "%{name} je ažurirao/-la emodži %{target}"
|
||||
update_domain_block_html: "%{name} je ažurirao/-la blok domena %{target}"
|
||||
update_ip_block_html: "%{name} je promenio/-la IP uslov za %{target}"
|
||||
update_report_html: "%{name} je ažurirao izveštaj %{target}"
|
||||
update_status_html: "%{name} je ažurirao/-la objavu korisnika %{target}"
|
||||
update_user_role_html: "%{name} je promenio/-la poziciju %{target}"
|
||||
deleted_account: obrisan nalog
|
||||
|
|
|
@ -288,6 +288,7 @@ sr:
|
|||
update_custom_emoji_html: "%{name} је ажурирао/-ла емоџи %{target}"
|
||||
update_domain_block_html: "%{name} је ажурирао/-ла блок домена %{target}"
|
||||
update_ip_block_html: "%{name} је променио/-ла IP услов за %{target}"
|
||||
update_report_html: "%{name} је ажурирао извештај %{target}"
|
||||
update_status_html: "%{name} је ажурирао/-ла објаву корисника %{target}"
|
||||
update_user_role_html: "%{name} је променио/-ла позицију %{target}"
|
||||
deleted_account: обрисан налог
|
||||
|
|
|
@ -285,6 +285,7 @@ sv:
|
|||
update_custom_emoji_html: "%{name} uppdaterade emoji %{target}"
|
||||
update_domain_block_html: "%{name} uppdaterade domän-block för %{target}"
|
||||
update_ip_block_html: "%{name} ändrade regel för IP %{target}"
|
||||
update_report_html: "%{name} uppdaterade rapporten %{target}"
|
||||
update_status_html: "%{name} uppdaterade inlägget av %{target}"
|
||||
update_user_role_html: "%{name} ändrade rollen %{target}"
|
||||
deleted_account: raderat konto
|
||||
|
|
|
@ -282,6 +282,7 @@ th:
|
|||
update_custom_emoji_html: "%{name} ได้อัปเดตอีโมจิ %{target}"
|
||||
update_domain_block_html: "%{name} ได้อัปเดตการปิดกั้นโดเมนสำหรับ %{target}"
|
||||
update_ip_block_html: "%{name} ได้เปลี่ยนกฎสำหรับ IP %{target}"
|
||||
update_report_html: "%{name} ได้อัปเดตรายงาน %{target}"
|
||||
update_status_html: "%{name} ได้อัปเดตโพสต์โดย %{target}"
|
||||
update_user_role_html: "%{name} ได้เปลี่ยนบทบาท %{target}"
|
||||
deleted_account: บัญชีที่ลบแล้ว
|
||||
|
@ -1838,6 +1839,7 @@ th:
|
|||
feature_action: เรียนรู้เพิ่มเติม
|
||||
feature_audience: Mastodon มีความพิเศษที่ให้คุณจัดการผู้รับสารของคุณได้โดยไม่มีตัวกลาง นอกจากนี้ การติดตั้ง Mastodon บนโครงสร้างพื้นฐานของคุณจะทำให้คุณสามารถติดตาม (และติดตามโดย) เซิร์ฟเวอร์ Mastodon แห่งไหนก็ได้ที่ทำงานอยู่ โดยไม่มีใครสามารถควบคุมได้นอกจากคุณ
|
||||
feature_audience_title: สร้างผู้ชมของคุณด้วยความมั่นใจ
|
||||
feature_control: คุณทราบดีที่สุดถึงสิ่งที่คุณต้องการเห็นในฟีดหน้าแรกของคุณ ไม่มีอัลกอริทึมหรือโฆษณาให้เสียเวลาของคุณ ติดตามใครก็ตามทั่วทั้งเซิร์ฟเวอร์ Mastodon ใด ๆ จากบัญชีเดียวและรับโพสต์ของเขาตามลำดับเวลา และทำให้มุมอินเทอร์เน็ตของคุณเป็นเหมือนคุณมากขึ้นอีกนิด
|
||||
feature_control_title: การควบคุมเส้นเวลาของคุณเอง
|
||||
feature_creativity_title: ความคิดสร้างสรรค์ที่ไม่มีใครเทียบได้
|
||||
feature_moderation_title: การกลั่นกรองในแบบที่ควรจะเป็น
|
||||
|
|
|
@ -285,6 +285,7 @@ tr:
|
|||
update_custom_emoji_html: "%{name}, %{target} emojisini güncelledi"
|
||||
update_domain_block_html: "%{name}, %{target} alan adının engelini güncelledi"
|
||||
update_ip_block_html: "%{name}, %{target} IP adresi için kuralı güncelledi"
|
||||
update_report_html: "%{name}, %{target} raporunu güncelledi"
|
||||
update_status_html: "%{name}, %{target} kullanıcısının gönderisini güncelledi"
|
||||
update_user_role_html: "%{name}, %{target} rolünü değiştirdi"
|
||||
deleted_account: hesap silindi
|
||||
|
|
|
@ -282,6 +282,7 @@ vi:
|
|||
update_custom_emoji_html: "%{name} đã cập nhật emoji %{target}"
|
||||
update_domain_block_html: "%{name} cập nhật chặn máy chủ %{target}"
|
||||
update_ip_block_html: "%{name} cập nhật chặn IP %{target}"
|
||||
update_report_html: "%{name} cập nhật báo cáo %{target}"
|
||||
update_status_html: "%{name} cập nhật tút của %{target}"
|
||||
update_user_role_html: "%{name} đã thay đổi vai trò %{target}"
|
||||
deleted_account: tài khoản đã xóa
|
||||
|
|
|
@ -282,6 +282,7 @@ zh-CN:
|
|||
update_custom_emoji_html: "%{name} 更新了自定义表情 %{target}"
|
||||
update_domain_block_html: "%{name} 更新了对 %{target} 的域名屏蔽"
|
||||
update_ip_block_html: "%{name} 修改了对 IP %{target} 的规则"
|
||||
update_report_html: "%{name} 更新了举报 %{target}"
|
||||
update_status_html: "%{name} 刷新了 %{target} 的嘟文"
|
||||
update_user_role_html: "%{name} 更改了 %{target} 角色"
|
||||
deleted_account: 账号已注销
|
||||
|
|
|
@ -282,6 +282,7 @@ zh-TW:
|
|||
update_custom_emoji_html: "%{name} 已更新自訂 emoji 表情符號 %{target}"
|
||||
update_domain_block_html: "%{name} 已更新 %{target} 之網域封鎖"
|
||||
update_ip_block_html: "%{name} 已變更 IP %{target} 之規則"
|
||||
update_report_html: "%{name} 已更新 %{target} 的檢舉"
|
||||
update_status_html: "%{name} 已更新 %{target} 的嘟文"
|
||||
update_user_role_html: "%{name} 已變更 %{target} 角色"
|
||||
deleted_account: 已刪除帳號
|
||||
|
|
|
@ -29,7 +29,7 @@ module Mastodon::CLI
|
|||
link = options[:link] ? 'link-type ' : ''
|
||||
scope = PreviewCard.cached
|
||||
scope = scope.where(type: :link) if options[:link]
|
||||
scope = scope.where('updated_at < ?', time_ago)
|
||||
scope = scope.where(updated_at: ...time_ago)
|
||||
|
||||
processed, aggregate = parallelize_with_progress(scope) do |preview_card|
|
||||
next if preview_card.image.blank?
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
"@formatjs/intl-pluralrules": "^5.2.2",
|
||||
"@gamestdio/websocket": "^0.3.2",
|
||||
"@github/webauthn-json": "^2.1.1",
|
||||
"@rails/ujs": "7.1.3-3",
|
||||
"@rails/ujs": "7.1.3",
|
||||
"@reduxjs/toolkit": "^2.0.1",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"arrow-key-navigation": "^1.2.0",
|
||||
|
|
70
spec/helpers/self_destruct_helper_spec.rb
Normal file
70
spec/helpers/self_destruct_helper_spec.rb
Normal file
|
@ -0,0 +1,70 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SelfDestructHelper do
|
||||
describe 'self_destruct?' do
|
||||
context 'when SELF_DESTRUCT is unset' do
|
||||
it 'returns false' do
|
||||
expect(helper.self_destruct?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when SELF_DESTRUCT is set to an invalid value' do
|
||||
around do |example|
|
||||
ClimateControl.modify SELF_DESTRUCT: 'true' do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(helper.self_destruct?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when SELF_DESTRUCT is set to value signed for the wrong purpose' do
|
||||
around do |example|
|
||||
ClimateControl.modify(
|
||||
SELF_DESTRUCT: Rails.application.message_verifier('foo').generate('example.com'),
|
||||
LOCAL_DOMAIN: 'example.com'
|
||||
) do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(helper.self_destruct?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when SELF_DESTRUCT is set to value signed for the wrong domain' do
|
||||
around do |example|
|
||||
ClimateControl.modify(
|
||||
SELF_DESTRUCT: Rails.application.message_verifier('self-destruct').generate('foo.com'),
|
||||
LOCAL_DOMAIN: 'example.com'
|
||||
) do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(helper.self_destruct?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when SELF_DESTRUCT is set to a correctly-signed value' do
|
||||
around do |example|
|
||||
ClimateControl.modify(
|
||||
SELF_DESTRUCT: Rails.application.message_verifier('self-destruct').generate('example.com'),
|
||||
LOCAL_DOMAIN: 'example.com'
|
||||
) do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(helper.self_destruct?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -125,4 +125,22 @@ RSpec.describe AdminMailer do
|
|||
.and(have_header('X-Priority', '1'))
|
||||
end
|
||||
end
|
||||
|
||||
describe '.auto_close_registrations' do
|
||||
let(:recipient) { Fabricate(:account, username: 'Bob') }
|
||||
let(:mail) { described_class.with(recipient: recipient).auto_close_registrations }
|
||||
|
||||
before do
|
||||
recipient.user.update(locale: :en)
|
||||
end
|
||||
|
||||
it 'renders the email' do
|
||||
expect(mail)
|
||||
.to be_present
|
||||
.and(deliver_to(recipient.user_email))
|
||||
.and(deliver_from('notifications@localhost'))
|
||||
.and(have_subject('Registrations for cb6e6126.ngrok.io have been automatically switched to requiring approval'))
|
||||
.and(have_body_text('have been automatically switched'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,4 +32,9 @@ class AdminMailerPreview < ActionMailer::Preview
|
|||
def new_critical_software_updates
|
||||
AdminMailer.with(recipient: Account.first).new_critical_software_updates
|
||||
end
|
||||
|
||||
# Preview this email at http://localhost:3000/rails/mailers/admin_mailer/auto_close_registrations
|
||||
def auto_close_registrations
|
||||
AdminMailer.with(recipient: Account.first).auto_close_registrations
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,14 +20,26 @@ describe 'Credentials' do
|
|||
|
||||
expect(body_as_json).to match(
|
||||
a_hash_including(
|
||||
id: token.application.id.to_s,
|
||||
name: token.application.name,
|
||||
website: token.application.website,
|
||||
vapid_key: Rails.configuration.x.vapid_public_key,
|
||||
scopes: token.application.scopes.map(&:to_s),
|
||||
client_id: token.application.uid
|
||||
redirect_uris: token.application.redirect_uris,
|
||||
# Deprecated properties as of 4.3:
|
||||
redirect_uri: token.application.redirect_uri.split.first,
|
||||
vapid_key: Rails.configuration.x.vapid_public_key
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not expose the client_id or client_secret' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
expect(body_as_json[:client_id]).to_not be_present
|
||||
expect(body_as_json[:client_secret]).to_not be_present
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a non-read scoped oauth token' do
|
||||
|
@ -46,11 +58,14 @@ describe 'Credentials' do
|
|||
|
||||
expect(body_as_json).to match(
|
||||
a_hash_including(
|
||||
id: token.application.id.to_s,
|
||||
name: token.application.name,
|
||||
website: token.application.website,
|
||||
vapid_key: Rails.configuration.x.vapid_public_key,
|
||||
scopes: token.application.scopes.map(&:to_s),
|
||||
client_id: token.application.uid
|
||||
redirect_uris: token.application.redirect_uris,
|
||||
# Deprecated properties as of 4.3:
|
||||
redirect_uri: token.application.redirect_uri.split.first,
|
||||
vapid_key: Rails.configuration.x.vapid_public_key
|
||||
)
|
||||
)
|
||||
end
|
||||
|
|
|
@ -9,8 +9,9 @@ RSpec.describe 'Apps' do
|
|||
end
|
||||
|
||||
let(:client_name) { 'Test app' }
|
||||
let(:scopes) { nil }
|
||||
let(:redirect_uris) { 'urn:ietf:wg:oauth:2.0:oob' }
|
||||
let(:scopes) { 'read write' }
|
||||
let(:redirect_uri) { 'urn:ietf:wg:oauth:2.0:oob' }
|
||||
let(:redirect_uris) { [redirect_uri] }
|
||||
let(:website) { nil }
|
||||
|
||||
let(:params) do
|
||||
|
@ -26,13 +27,63 @@ RSpec.describe 'Apps' do
|
|||
it 'creates an OAuth app', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
app = Doorkeeper::Application.find_by(name: client_name)
|
||||
|
||||
expect(app).to be_present
|
||||
expect(app.scopes.to_s).to eq scopes
|
||||
expect(app.redirect_uris).to eq redirect_uris
|
||||
|
||||
expect(body_as_json).to match(
|
||||
a_hash_including(
|
||||
id: app.id.to_s,
|
||||
client_id: app.uid,
|
||||
client_secret: app.secret,
|
||||
name: client_name,
|
||||
website: website,
|
||||
scopes: ['read', 'write'],
|
||||
redirect_uris: redirect_uris,
|
||||
# Deprecated properties as of 4.3:
|
||||
redirect_uri: redirect_uri,
|
||||
vapid_key: Rails.configuration.x.vapid_public_key
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without scopes being supplied' do
|
||||
let(:scopes) { nil }
|
||||
|
||||
it 'creates an OAuth App with the default scope' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(Doorkeeper::Application.find_by(name: client_name)).to be_present
|
||||
|
||||
body = body_as_json
|
||||
|
||||
expect(body[:client_id]).to be_present
|
||||
expect(body[:client_secret]).to be_present
|
||||
expect(body[:scopes]).to eq Doorkeeper.config.default_scopes.to_a
|
||||
end
|
||||
end
|
||||
|
||||
# FIXME: This is a bug: https://github.com/mastodon/mastodon/issues/30152
|
||||
context 'with scopes as an array' do
|
||||
let(:scopes) { %w(read write follow) }
|
||||
|
||||
it 'creates an OAuth App with the default scope' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
app = Doorkeeper::Application.find_by(name: client_name)
|
||||
|
||||
expect(app).to be_present
|
||||
expect(app.scopes.to_s).to eq 'read'
|
||||
|
||||
body = body_as_json
|
||||
|
||||
expect(body[:scopes]).to eq ['read']
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -77,8 +128,8 @@ RSpec.describe 'Apps' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with a too-long redirect_uris' do
|
||||
let(:redirect_uris) { "https://foo.bar/#{'hoge' * 2_000}" }
|
||||
context 'with a too-long redirect_uri' do
|
||||
let(:redirect_uris) { "https://app.example/#{'hoge' * 2_000}" }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
@ -87,8 +138,80 @@ RSpec.describe 'Apps' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'without required params' do
|
||||
let(:client_name) { '' }
|
||||
# NOTE: This spec currently tests the same as the "with a too-long redirect_uri test case"
|
||||
context 'with too many redirect_uris' do
|
||||
let(:redirect_uris) { (0...500).map { |i| "https://app.example/#{i}/callback" } }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple redirect_uris as a string' do
|
||||
let(:redirect_uris) { "https://redirect1.example/\napp://redirect2.example/" }
|
||||
|
||||
it 'creates an OAuth application with multiple redirect URIs' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
app = Doorkeeper::Application.find_by(name: client_name)
|
||||
|
||||
expect(app).to be_present
|
||||
expect(app.redirect_uri).to eq redirect_uris
|
||||
expect(app.redirect_uris).to eq redirect_uris.split
|
||||
|
||||
body = body_as_json
|
||||
|
||||
expect(body[:redirect_uri]).to eq redirect_uris
|
||||
expect(body[:redirect_uris]).to eq redirect_uris.split
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple redirect_uris as an array' do
|
||||
let(:redirect_uris) { ['https://redirect1.example/', 'app://redirect2.example/'] }
|
||||
|
||||
it 'creates an OAuth application with multiple redirect URIs' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
app = Doorkeeper::Application.find_by(name: client_name)
|
||||
|
||||
expect(app).to be_present
|
||||
expect(app.redirect_uri).to eq redirect_uris.join "\n"
|
||||
expect(app.redirect_uris).to eq redirect_uris
|
||||
|
||||
body = body_as_json
|
||||
|
||||
expect(body[:redirect_uri]).to eq redirect_uris.join "\n"
|
||||
expect(body[:redirect_uris]).to eq redirect_uris
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an empty redirect_uris array' do
|
||||
let(:redirect_uris) { [] }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with just a newline as the redirect_uris string' do
|
||||
let(:redirect_uris) { "\n" }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an empty redirect_uris string' do
|
||||
let(:redirect_uris) { '' }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
|
@ -97,5 +220,30 @@ RSpec.describe 'Apps' do
|
|||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without a required param' do
|
||||
let(:client_name) { '' }
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a website' do
|
||||
let(:website) { 'https://app.example/' }
|
||||
|
||||
it 'creates an OAuth application with the website specified' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
app = Doorkeeper::Application.find_by(name: client_name)
|
||||
|
||||
expect(app).to be_present
|
||||
expect(app.website).to eq website
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
92
spec/requests/self_destruct_spec.rb
Normal file
92
spec/requests/self_destruct_spec.rb
Normal file
|
@ -0,0 +1,92 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe 'Self-destruct mode' do
|
||||
before do
|
||||
allow(SelfDestructHelper).to receive(:self_destruct?).and_return(true)
|
||||
end
|
||||
|
||||
shared_examples 'generic logged out request' do |path|
|
||||
it 'returns 410 gone and mentions self-destruct' do
|
||||
get path, headers: { 'Accept' => 'text/html' }
|
||||
|
||||
expect(response).to have_http_status(410)
|
||||
expect(response.body).to include(I18n.t('self_destruct.title'))
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'accessible logged-in endpoint' do |path|
|
||||
it 'returns 200 ok' do
|
||||
get path
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'ActivityPub request' do |path|
|
||||
context 'without signature' do
|
||||
it 'returns 410 gone' do
|
||||
get path, headers: {
|
||||
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(410)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid signature' do
|
||||
it 'returns 410 gone' do
|
||||
get path, headers: {
|
||||
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
'Signature' => 'keyId="https://remote.domain/users/bob#main-key",algorithm="rsa-sha256",headers="date host (request-target)",signature="bar"',
|
||||
}
|
||||
|
||||
expect(response).to have_http_status(410)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when requesting various unavailable endpoints' do
|
||||
it_behaves_like 'generic logged out request', '/'
|
||||
it_behaves_like 'generic logged out request', '/about'
|
||||
it_behaves_like 'generic logged out request', '/public'
|
||||
end
|
||||
|
||||
context 'when requesting a suspended account' do
|
||||
let(:suspended) { Fabricate(:account, username: 'suspended') }
|
||||
|
||||
before do
|
||||
suspended.suspend!
|
||||
end
|
||||
|
||||
it_behaves_like 'generic logged out request', '/@suspended'
|
||||
it_behaves_like 'ActivityPub request', '/users/suspended'
|
||||
it_behaves_like 'ActivityPub request', '/users/suspended/followers'
|
||||
it_behaves_like 'ActivityPub request', '/users/suspended/outbox'
|
||||
end
|
||||
|
||||
context 'when requesting a non-suspended account' do
|
||||
before do
|
||||
Fabricate(:account, username: 'bob')
|
||||
end
|
||||
|
||||
it_behaves_like 'generic logged out request', '/@bob'
|
||||
it_behaves_like 'ActivityPub request', '/users/bob'
|
||||
it_behaves_like 'ActivityPub request', '/users/bob/followers'
|
||||
it_behaves_like 'ActivityPub request', '/users/bob/outbox'
|
||||
end
|
||||
|
||||
context 'when accessing still-enabled endpoints when logged in' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'accessible logged-in endpoint', '/auth/edit'
|
||||
it_behaves_like 'accessible logged-in endpoint', '/settings/export'
|
||||
it_behaves_like 'accessible logged-in endpoint', '/settings/login_activities'
|
||||
it_behaves_like 'accessible logged-in endpoint', '/settings/exports/follows.csv'
|
||||
end
|
||||
end
|
|
@ -163,7 +163,7 @@ describe Scheduler::AccountsStatusesCleanupScheduler do
|
|||
def cleanable_statuses_count
|
||||
Status
|
||||
.where(account_id: [account_alice, account_chris, account_erin]) # Accounts with enabled policies
|
||||
.where('created_at < ?', 2.weeks.ago) # Policy defaults is 2.weeks
|
||||
.where(created_at: ...2.weeks.ago) # Policy defaults is 2.weeks
|
||||
.count
|
||||
end
|
||||
end
|
||||
|
|
46
yarn.lock
46
yarn.lock
|
@ -2215,13 +2215,13 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"@formatjs/cli@npm:^6.1.1":
|
||||
version: 6.2.10
|
||||
resolution: "@formatjs/cli@npm:6.2.10"
|
||||
version: 6.2.12
|
||||
resolution: "@formatjs/cli@npm:6.2.12"
|
||||
peerDependencies:
|
||||
"@glimmer/env": ^0.1.7
|
||||
"@glimmer/reference": ^0.91.1
|
||||
"@glimmer/syntax": ^0.91.1
|
||||
"@glimmer/validator": ^0.91.1
|
||||
"@glimmer/reference": ^0.91.1 || ^0.92.0
|
||||
"@glimmer/syntax": ^0.92.0
|
||||
"@glimmer/validator": ^0.92.0
|
||||
"@vue/compiler-core": ^3.4.0
|
||||
content-tag: ^2.0.1
|
||||
ember-template-recast: ^6.1.4
|
||||
|
@ -2245,7 +2245,7 @@ __metadata:
|
|||
optional: true
|
||||
bin:
|
||||
formatjs: bin/formatjs
|
||||
checksum: 10c0/34b1b0b3be25d945111c1f57913f50da7308ecd05501a27eaca210a774eb50c616b5706ba796d37ffa223ac4c5cddd5f36fe0ca8d31ad8c8ade79cdd497ccfb9
|
||||
checksum: 10c0/3bd05a9fad6c837e22988e6638f426c128efa46ab80ff88cf2ad81fb3bc10cf4f228907577fc01e24c2d7d505cfabfaa69f0496d2ec8f0ab2d6b5eaccb5e475c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -2758,7 +2758,7 @@ __metadata:
|
|||
"@formatjs/intl-pluralrules": "npm:^5.2.2"
|
||||
"@gamestdio/websocket": "npm:^0.3.2"
|
||||
"@github/webauthn-json": "npm:^2.1.1"
|
||||
"@rails/ujs": "npm:7.1.3-3"
|
||||
"@rails/ujs": "npm:7.1.3"
|
||||
"@reduxjs/toolkit": "npm:^2.0.1"
|
||||
"@svgr/webpack": "npm:^5.5.0"
|
||||
"@testing-library/jest-dom": "npm:^6.0.0"
|
||||
|
@ -3045,10 +3045,10 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rails/ujs@npm:7.1.3-3":
|
||||
version: 7.1.3-3
|
||||
resolution: "@rails/ujs@npm:7.1.3-3"
|
||||
checksum: 10c0/9eee95372b72d8f704b67f14a3bf9f2681ab5b11c7b79919bfde3341f2970771876af5b40de5b3e4fca6a97c76a41046eff71d96490617c1fc80ef3ad8bbac47
|
||||
"@rails/ujs@npm:7.1.3":
|
||||
version: 7.1.3
|
||||
resolution: "@rails/ujs@npm:7.1.3"
|
||||
checksum: 10c0/68112d9add9dbc59b40c2ec1bc095a67445c57d20d0ab7d817ce3de0cd90374e2690af8ad54ce6ecc2d1c748b34c0c44d0fbd2f515ce2c443d7c5d23d00b9ce5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -3708,9 +3708,9 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"@types/lodash@npm:^4.14.195":
|
||||
version: 4.17.1
|
||||
resolution: "@types/lodash@npm:4.17.1"
|
||||
checksum: 10c0/af2ad8a3c8d7deb170a7ec6e18afc5ae8980576e5f7fe798d8a95a1df7222c15bdf967a25a35879f575a3b64743de00145710ee461a0051e055e94e4fe253f45
|
||||
version: 4.17.4
|
||||
resolution: "@types/lodash@npm:4.17.4"
|
||||
checksum: 10c0/0124c64cb9fe7a0f78b6777955abd05ef0d97844d49118652eae45f8fa57bfb7f5a7a9bccc0b5a84c0a6dc09631042e4590cb665acb9d58dfd5e6543c75341ec
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -14293,14 +14293,14 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"react-dom@npm:^18.2.0":
|
||||
version: 18.2.0
|
||||
resolution: "react-dom@npm:18.2.0"
|
||||
version: 18.3.1
|
||||
resolution: "react-dom@npm:18.3.1"
|
||||
dependencies:
|
||||
loose-envify: "npm:^1.1.0"
|
||||
scheduler: "npm:^0.23.0"
|
||||
scheduler: "npm:^0.23.2"
|
||||
peerDependencies:
|
||||
react: ^18.2.0
|
||||
checksum: 10c0/66dfc5f93e13d0674e78ef41f92ed21dfb80f9c4ac4ac25a4b51046d41d4d2186abc915b897f69d3d0ebbffe6184e7c5876f2af26bfa956f179225d921be713a
|
||||
react: ^18.3.1
|
||||
checksum: 10c0/a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -14703,11 +14703,11 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"react@npm:^18.2.0":
|
||||
version: 18.2.0
|
||||
resolution: "react@npm:18.2.0"
|
||||
version: 18.3.1
|
||||
resolution: "react@npm:18.3.1"
|
||||
dependencies:
|
||||
loose-envify: "npm:^1.1.0"
|
||||
checksum: 10c0/b562d9b569b0cb315e44b48099f7712283d93df36b19a39a67c254c6686479d3980b7f013dc931f4a5a3ae7645eae6386b4aa5eea933baa54ecd0f9acb0902b8
|
||||
checksum: 10c0/283e8c5efcf37802c9d1ce767f302dd569dd97a70d9bb8c7be79a789b9902451e0d16334b05d73299b20f048cbc3c7d288bbbde10b701fa194e2089c237dbea3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -15368,7 +15368,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"scheduler@npm:^0.23.0, scheduler@npm:^0.23.2":
|
||||
"scheduler@npm:^0.23.2":
|
||||
version: 0.23.2
|
||||
resolution: "scheduler@npm:0.23.2"
|
||||
dependencies:
|
||||
|
|
Loading…
Reference in a new issue