Compare commits
34 Commits
fixes/serv
...
main
Author | SHA1 | Date |
---|---|---|
github-actions[bot] | a918208ec6 | |
renovate[bot] | bf1d452978 | |
Ricardo Trindade | 33f8c1c5eb | |
Matt Jankowski | eae5c7334a | |
Matt Jankowski | 2e6bf60f15 | |
Jonathan de Jong | 1cc512909c | |
Claire | 93e4cdc31b | |
SouthFox | 08bdd5751e | |
renovate[bot] | 15ef654e9a | |
Renaud Chaput | 13d310e64d | |
Matt Jankowski | 1f5187e2e2 | |
renovate[bot] | 37929b9707 | |
github-actions[bot] | 8ca16f032e | |
Claire | bbf46cc418 | |
Jeong Arm | 8f998cd96a | |
Eugen Rochko | fa7e64df1d | |
Matt Jankowski | 12550a6a28 | |
Matt Jankowski | 4aa05d45fc | |
Simon Rapilly | 2d8f759a34 | |
Claire | d2f52f7f64 | |
Mark T. Tomczak | ba8dcb50fe | |
Claire | 75255c01fc | |
github-actions[bot] | 3427b51d63 | |
Renaud Chaput | 537442853f | |
Matt Jankowski | 3ca974e101 | |
renovate[bot] | 400f5c9174 | |
renovate[bot] | 6e018f7228 | |
Claire | 49b8433c56 | |
Matt Jankowski | 9a3d047f3e | |
Claire | 235a4cfdc8 | |
Renaud Chaput | a4e6fe36cb | |
Matt Jankowski | 70dbf84b9b | |
Claire | fa65c8244f | |
Matt Jankowski | c926f5fd67 |
|
@ -70,7 +70,7 @@ services:
|
|||
hard: -1
|
||||
|
||||
libretranslate:
|
||||
image: libretranslate/libretranslate:v1.3.12
|
||||
image: libretranslate/libretranslate:v1.4.1
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- lt-data:/home/libretranslate/.local
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# This configuration was generated by
|
||||
# `haml-lint --auto-gen-config`
|
||||
# on 2023-10-24 14:08:37 -0400 using Haml-Lint version 0.51.0.
|
||||
# on 2023-10-25 08:29:48 -0400 using Haml-Lint version 0.51.0.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the lints are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
|
@ -11,61 +11,10 @@ linters:
|
|||
LineLength:
|
||||
enabled: false
|
||||
|
||||
# Offense count: 22
|
||||
UnnecessaryStringOutput:
|
||||
exclude:
|
||||
- 'app/views/accounts/show.html.haml'
|
||||
- 'app/views/admin/custom_emojis/_custom_emoji.html.haml'
|
||||
- 'app/views/admin/relays/_relay.html.haml'
|
||||
- 'app/views/admin/rules/_rule.html.haml'
|
||||
- 'app/views/admin/statuses/index.html.haml'
|
||||
- 'app/views/auth/registrations/_session.html.haml'
|
||||
- 'app/views/disputes/strikes/show.html.haml'
|
||||
- 'app/views/notification_mailer/_status.html.haml'
|
||||
- 'app/views/settings/two_factor_authentication_methods/index.html.haml'
|
||||
- 'app/views/statuses/_detailed_status.html.haml'
|
||||
- 'app/views/statuses/_poll.html.haml'
|
||||
- 'app/views/statuses/_simple_status.html.haml'
|
||||
- 'app/views/user_mailer/suspicious_sign_in.html.haml'
|
||||
- 'app/views/user_mailer/webauthn_credential_added.html.haml'
|
||||
- 'app/views/user_mailer/webauthn_credential_deleted.html.haml'
|
||||
- 'app/views/user_mailer/welcome.html.haml'
|
||||
|
||||
# Offense count: 45
|
||||
# Offense count: 10
|
||||
RuboCop:
|
||||
exclude:
|
||||
- 'app/views/admin/accounts/_account.html.haml'
|
||||
- 'app/views/admin/accounts/_buttons.html.haml'
|
||||
- 'app/views/admin/accounts/_local_account.html.haml'
|
||||
- 'app/views/admin/accounts/_remote_account.html.haml'
|
||||
- 'app/views/admin/accounts/index.html.haml'
|
||||
- 'app/views/admin/accounts/show.html.haml'
|
||||
- 'app/views/admin/custom_emojis/index.html.haml'
|
||||
- 'app/views/admin/dashboard/index.html.haml'
|
||||
- 'app/views/admin/domain_blocks/confirm_suspension.html.haml'
|
||||
- 'app/views/admin/follow_recommendations/show.html.haml'
|
||||
- 'app/views/admin/invites/_invite.html.haml'
|
||||
- 'app/views/admin/invites/index.html.haml'
|
||||
- 'app/views/admin/ip_blocks/index.html.haml'
|
||||
- 'app/views/admin/reports/_status.html.haml'
|
||||
- 'app/views/admin/reports/show.html.haml'
|
||||
- 'app/views/admin/roles/_form.html.haml'
|
||||
- 'app/views/admin/software_updates/index.html.haml'
|
||||
- 'app/views/admin/status_edits/_status_edit.html.haml'
|
||||
- 'app/views/admin/statuses/index.html.haml'
|
||||
- 'app/views/admin/tags/show.html.haml'
|
||||
- 'app/views/admin/trends/tags/_tag.html.haml'
|
||||
- 'app/views/auth/registrations/_session.html.haml'
|
||||
- 'app/views/auth/registrations/new.html.haml'
|
||||
- 'app/views/auth/sessions/two_factor.html.haml'
|
||||
- 'app/views/auth/shared/_progress.html.haml'
|
||||
- 'app/views/disputes/strikes/_card.html.haml'
|
||||
- 'app/views/filters/statuses/index.html.haml'
|
||||
- 'app/views/invites/_invite.html.haml'
|
||||
- 'app/views/layouts/application.html.haml'
|
||||
- 'app/views/layouts/error.html.haml'
|
||||
- 'app/views/statuses/_detailed_status.html.haml'
|
||||
- 'app/views/statuses/_og_image.html.haml'
|
||||
- 'app/views/statuses/_simple_status.html.haml'
|
||||
- 'app/views/statuses_cleanup/show.html.haml'
|
||||
- 'app/views/user_mailer/warning.html.haml'
|
||||
|
|
|
@ -532,7 +532,7 @@ GEM
|
|||
public_suffix (5.0.3)
|
||||
puma (6.4.0)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.3.0)
|
||||
pundit (2.3.1)
|
||||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.7.1)
|
||||
|
|
|
@ -67,7 +67,7 @@ Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Stre
|
|||
|
||||
### Requirements
|
||||
|
||||
- **PostgreSQL** 9.5+
|
||||
- **PostgreSQL** 12+
|
||||
- **Redis** 4+
|
||||
- **Ruby** 2.7+
|
||||
- **Node.js** 16+
|
||||
|
|
|
@ -21,7 +21,7 @@ module Admin
|
|||
account_action.save!
|
||||
|
||||
if account_action.with_report?
|
||||
redirect_to admin_reports_path, notice: I18n.t('admin.reports.processed_msg', id: params[:report_id])
|
||||
redirect_to admin_reports_path, notice: I18n.t('admin.reports.processed_msg', id: resource_params[:report_id])
|
||||
else
|
||||
redirect_to admin_account_path(@account.id)
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@ class Admin::Disputes::AppealsController < Admin::BaseController
|
|||
authorize @appeal, :approve?
|
||||
log_action :reject, @appeal
|
||||
@appeal.reject!(current_account)
|
||||
UserMailer.appeal_rejected(@appeal.account.user, @appeal)
|
||||
UserMailer.appeal_rejected(@appeal.account.user, @appeal).deliver_later
|
||||
redirect_to disputes_strike_path(@appeal.strike)
|
||||
end
|
||||
|
||||
|
|
|
@ -39,6 +39,12 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
|
|||
show
|
||||
end
|
||||
|
||||
def redirect_to_app?
|
||||
truthy_param?(:redirect_to_app)
|
||||
end
|
||||
|
||||
helper_method :redirect_to_app?
|
||||
|
||||
private
|
||||
|
||||
def require_captcha_if_needed!
|
||||
|
@ -82,7 +88,7 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
|
|||
end
|
||||
|
||||
def after_confirmation_path_for(_resource_name, user)
|
||||
if user.created_by_application && truthy_param?(:redirect_to_app)
|
||||
if user.created_by_application && redirect_to_app?
|
||||
user.created_by_application.confirmation_redirect_uri
|
||||
elsif user_signed_in?
|
||||
web_url('start')
|
||||
|
|
|
@ -92,18 +92,10 @@ module CacheConcern
|
|||
arguments
|
||||
end
|
||||
|
||||
if Rails.gem_version >= Gem::Version.new('7.0')
|
||||
def attributes_for_database(record)
|
||||
attributes = record.attributes_for_database
|
||||
attributes.transform_values! { |attr| attr.is_a?(::ActiveModel::Type::Binary::Data) ? attr.to_s : attr }
|
||||
attributes
|
||||
end
|
||||
else
|
||||
def attributes_for_database(record)
|
||||
attributes = record.instance_variable_get(:@attributes).send(:attributes).transform_values(&:value_for_database)
|
||||
attributes.transform_values! { |attr| attr.is_a?(::ActiveModel::Type::Binary::Data) ? attr.to_s : attr }
|
||||
attributes
|
||||
end
|
||||
def attributes_for_database(record)
|
||||
attributes = record.attributes_for_database
|
||||
attributes.transform_values! { |attr| attr.is_a?(::ActiveModel::Type::Binary::Data) ? attr.to_s : attr }
|
||||
attributes
|
||||
end
|
||||
|
||||
def deserialize_record(class_name, attributes_from_database, new_record = false) # rubocop:disable Style/OptionalBooleanParameter
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { render, fireEvent, screen } from '@testing-library/react';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import { render, fireEvent, screen } from 'mastodon/test_helpers';
|
||||
|
||||
import { Button } from '../button';
|
||||
|
||||
describe('<Button />', () => {
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
export class ColumnBackButton extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
multiColumn: PropTypes.bool,
|
||||
onClick: PropTypes.func,
|
||||
...WithRouterPropTypes,
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
const { onClick, history } = this.props;
|
||||
|
||||
if (onClick) {
|
||||
onClick();
|
||||
} else if (history.location?.state?.fromMastodon) {
|
||||
history.goBack();
|
||||
} else {
|
||||
history.push('/');
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { multiColumn } = this.props;
|
||||
|
||||
const component = (
|
||||
<button onClick={this.handleClick} className='column-back-button'>
|
||||
<Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
|
||||
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
|
||||
</button>
|
||||
);
|
||||
|
||||
if (multiColumn) {
|
||||
return component;
|
||||
} else {
|
||||
// The portal container and the component may be rendered to the DOM in
|
||||
// the same React render pass, so the container might not be available at
|
||||
// the time `render()` is called.
|
||||
const container = document.getElementById('tabs-bar__portal');
|
||||
if (container === null) {
|
||||
// The container wasn't available, force a re-render so that the
|
||||
// component can eventually be inserted in the container and not scroll
|
||||
// with the rest of the area.
|
||||
this.forceUpdate();
|
||||
return component;
|
||||
} else {
|
||||
return createPortal(component, container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(ColumnBackButton);
|
|
@ -0,0 +1,45 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context';
|
||||
|
||||
import { useAppHistory } from './router';
|
||||
|
||||
type OnClickCallback = () => void;
|
||||
|
||||
function useHandleClick(onClick?: OnClickCallback) {
|
||||
const history = useAppHistory();
|
||||
|
||||
return useCallback(() => {
|
||||
if (onClick) {
|
||||
onClick();
|
||||
} else if (history.location.state?.fromMastodon) {
|
||||
history.goBack();
|
||||
} else {
|
||||
history.push('/');
|
||||
}
|
||||
}, [history, onClick]);
|
||||
}
|
||||
|
||||
export const ColumnBackButton: React.FC<{ onClick: OnClickCallback }> = ({
|
||||
onClick,
|
||||
}) => {
|
||||
const handleClick = useHandleClick(onClick);
|
||||
|
||||
const component = (
|
||||
<button onClick={handleClick} className='column-back-button'>
|
||||
<Icon
|
||||
id='chevron-left'
|
||||
icon={ArrowBackIcon}
|
||||
className='column-back-button__icon'
|
||||
/>
|
||||
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
|
||||
</button>
|
||||
);
|
||||
|
||||
return <ButtonInTabsBar>{component}</ButtonInTabsBar>;
|
||||
};
|
|
@ -1,20 +0,0 @@
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
|
||||
import { ColumnBackButton } from './column_back_button';
|
||||
|
||||
export default class ColumnBackButtonSlim extends ColumnBackButton {
|
||||
render () {
|
||||
return (
|
||||
<div className='column-back-button--slim'>
|
||||
<div role='button' tabIndex={0} onClick={this.handleClick} className='column-back-button column-back-button--slim-button'>
|
||||
<Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
|
||||
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { PureComponent, useCallback } from 'react';
|
||||
|
||||
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
||||
|
||||
|
@ -15,8 +14,11 @@ import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/
|
|||
import { ReactComponent as TuneIcon } from '@material-symbols/svg-600/outlined/tune.svg';
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { ButtonInTabsBar, useColumnsContext } from 'mastodon/features/ui/util/columns_context';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
import { useAppHistory } from './router';
|
||||
|
||||
const messages = defineMessages({
|
||||
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
||||
hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
|
||||
|
@ -24,6 +26,34 @@ const messages = defineMessages({
|
|||
moveRight: { id: 'column_header.moveRight_settings', defaultMessage: 'Move column to the right' },
|
||||
});
|
||||
|
||||
const BackButton = ({ pinned, show }) => {
|
||||
const history = useAppHistory();
|
||||
const { multiColumn } = useColumnsContext();
|
||||
|
||||
const handleBackClick = useCallback(() => {
|
||||
if (history.location?.state?.fromMastodon) {
|
||||
history.goBack();
|
||||
} else {
|
||||
history.push('/');
|
||||
}
|
||||
}, [history]);
|
||||
|
||||
const showButton = history && !pinned && ((multiColumn && history.location?.state?.fromMastodon) || show);
|
||||
|
||||
if(!showButton) return null;
|
||||
|
||||
return (<button onClick={handleBackClick} className='column-header__back-button'>
|
||||
<Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
|
||||
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
|
||||
</button>);
|
||||
|
||||
};
|
||||
|
||||
BackButton.propTypes = {
|
||||
pinned: PropTypes.bool,
|
||||
show: PropTypes.bool,
|
||||
};
|
||||
|
||||
class ColumnHeader extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
|
@ -72,16 +102,6 @@ class ColumnHeader extends PureComponent {
|
|||
this.props.onMove(1);
|
||||
};
|
||||
|
||||
handleBackClick = () => {
|
||||
const { history } = this.props;
|
||||
|
||||
if (history.location?.state?.fromMastodon) {
|
||||
history.goBack();
|
||||
} else {
|
||||
history.push('/');
|
||||
}
|
||||
};
|
||||
|
||||
handleTransitionEnd = () => {
|
||||
this.setState({ animating: false });
|
||||
};
|
||||
|
@ -95,7 +115,7 @@ class ColumnHeader extends PureComponent {
|
|||
};
|
||||
|
||||
render () {
|
||||
const { title, icon, iconComponent, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues, history } = this.props;
|
||||
const { title, icon, iconComponent, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues } = this.props;
|
||||
const { collapsed, animating } = this.state;
|
||||
|
||||
const wrapperClassName = classNames('column-header__wrapper', {
|
||||
|
@ -138,14 +158,7 @@ class ColumnHeader extends PureComponent {
|
|||
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' icon={AddIcon} /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
|
||||
}
|
||||
|
||||
if (!pinned && ((multiColumn && history.location?.state?.fromMastodon) || showBackButton)) {
|
||||
backButton = (
|
||||
<button onClick={this.handleBackClick} className='column-header__back-button'>
|
||||
<Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
|
||||
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
backButton = <BackButton pinned={pinned} show={showBackButton} />;
|
||||
|
||||
const collapsedContent = [
|
||||
extraContent,
|
||||
|
@ -203,22 +216,12 @@ class ColumnHeader extends PureComponent {
|
|||
</div>
|
||||
);
|
||||
|
||||
if (multiColumn || placeholder) {
|
||||
if (placeholder) {
|
||||
return component;
|
||||
} else {
|
||||
// The portal container and the component may be rendered to the DOM in
|
||||
// the same React render pass, so the container might not be available at
|
||||
// the time `render()` is called.
|
||||
const container = document.getElementById('tabs-bar__portal');
|
||||
if (container === null) {
|
||||
// The container wasn't available, force a re-render so that the
|
||||
// component can eventually be inserted in the container and not scroll
|
||||
// with the rest of the area.
|
||||
this.forceUpdate();
|
||||
return component;
|
||||
} else {
|
||||
return createPortal(component, container);
|
||||
}
|
||||
return (<ButtonInTabsBar>
|
||||
{component}
|
||||
</ButtonInTabsBar>);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { PropsWithChildren } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { Router as OriginalRouter } from 'react-router';
|
||||
import { Router as OriginalRouter, useHistory } from 'react-router';
|
||||
|
||||
import type {
|
||||
LocationDescriptor,
|
||||
|
@ -16,18 +16,23 @@ interface MastodonLocationState {
|
|||
fromMastodon?: boolean;
|
||||
mastodonModalKey?: string;
|
||||
}
|
||||
type HistoryPath = Path | LocationDescriptor<MastodonLocationState>;
|
||||
|
||||
const browserHistory = createBrowserHistory<
|
||||
MastodonLocationState | undefined
|
||||
>();
|
||||
type LocationState = MastodonLocationState | null | undefined;
|
||||
|
||||
type HistoryPath = Path | LocationDescriptor<LocationState>;
|
||||
|
||||
const browserHistory = createBrowserHistory<LocationState>();
|
||||
const originalPush = browserHistory.push.bind(browserHistory);
|
||||
const originalReplace = browserHistory.replace.bind(browserHistory);
|
||||
|
||||
export function useAppHistory() {
|
||||
return useHistory<LocationState>();
|
||||
}
|
||||
|
||||
function normalizePath(
|
||||
path: HistoryPath,
|
||||
state?: MastodonLocationState,
|
||||
): LocationDescriptorObject<MastodonLocationState> {
|
||||
state?: LocationState,
|
||||
): LocationDescriptorObject<LocationState> {
|
||||
const location = typeof path === 'string' ? { pathname: path } : { ...path };
|
||||
|
||||
if (location.state === undefined && state !== undefined) {
|
||||
|
|
|
@ -12,8 +12,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
|||
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
|
||||
import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/lock.svg';
|
||||
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
|
||||
import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg';
|
||||
import { ReactComponent as NotificationsActiveIcon } from '@material-symbols/svg-600/outlined/notifications_active.svg';
|
||||
import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications.svg';
|
||||
import { ReactComponent as NotificationsActiveIcon } from '@material-symbols/svg-600/outlined/notifications_active-fill.svg';
|
||||
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { Badge, AutomatedBadge, GroupBadge } from 'mastodon/components/badge';
|
||||
|
@ -264,7 +264,7 @@ class Header extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
if (account.getIn(['relationship', 'requested']) || account.getIn(['relationship', 'following'])) {
|
||||
bellBtn = <IconButton icon={account.getIn(['relationship', 'notifying']) ? 'bell' : 'bell-o'} iconComponent={account.getIn(['relationship', 'notifying']) ? NotificationsIcon : NotificationsActiveIcon} size={24} active={account.getIn(['relationship', 'notifying'])} title={intl.formatMessage(account.getIn(['relationship', 'notifying']) ? messages.disableNotifications : messages.enableNotifications, { name: account.get('username') })} onClick={this.props.onNotifyToggle} />;
|
||||
bellBtn = <IconButton icon={account.getIn(['relationship', 'notifying']) ? 'bell' : 'bell-o'} iconComponent={account.getIn(['relationship', 'notifying']) ? NotificationsActiveIcon : NotificationsIcon} active={account.getIn(['relationship', 'notifying'])} title={intl.formatMessage(account.getIn(['relationship', 'notifying']) ? messages.disableNotifications : messages.enableNotifications, { name: account.get('username') })} onClick={this.props.onNotifyToggle} />;
|
||||
}
|
||||
|
||||
if (me !== account.get('id')) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { connect } from 'react-redux';
|
|||
|
||||
import { lookupAccount, fetchAccount } from 'mastodon/actions/accounts';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import ColumnBackButton from 'mastodon/components/column_back_button';
|
||||
import { ColumnBackButton } from 'mastodon/components/column_back_button';
|
||||
import { LoadMore } from 'mastodon/components/load_more';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import ScrollContainer from 'mastodon/containers/scroll_container';
|
||||
|
@ -203,7 +203,7 @@ class AccountGallery extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<Column>
|
||||
<ColumnBackButton multiColumn={multiColumn} />
|
||||
<ColumnBackButton />
|
||||
|
||||
<ScrollContainer scrollKey='account_gallery'>
|
||||
<div className='scrollable scrollable--flex' onScroll={this.handleScroll}>
|
||||
|
|
|
@ -16,7 +16,7 @@ import { getAccountHidden } from 'mastodon/selectors';
|
|||
import { lookupAccount, fetchAccount } from '../../actions/accounts';
|
||||
import { fetchFeaturedTags } from '../../actions/featured_tags';
|
||||
import { expandAccountFeaturedTimeline, expandAccountTimeline, connectTimeline, disconnectTimeline } from '../../actions/timelines';
|
||||
import ColumnBackButton from '../../components/column_back_button';
|
||||
import { ColumnBackButton } from '../../components/column_back_button';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import StatusList from '../../components/status_list';
|
||||
import Column from '../ui/components/column';
|
||||
|
@ -184,7 +184,7 @@ class AccountTimeline extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<Column>
|
||||
<ColumnBackButton multiColumn={multiColumn} />
|
||||
<ColumnBackButton />
|
||||
|
||||
<StatusList
|
||||
prepend={<HeaderContainer accountId={this.props.accountId} hideTabs={forceEmptyState} tagged={this.props.params.tagged} />}
|
||||
|
|
|
@ -9,10 +9,10 @@ import { is } from 'immutable';
|
|||
|
||||
import { ReactComponent as DownloadIcon } from '@material-symbols/svg-600/outlined/download.svg';
|
||||
import { ReactComponent as PauseIcon } from '@material-symbols/svg-600/outlined/pause.svg';
|
||||
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow.svg';
|
||||
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow-fill.svg';
|
||||
import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
|
||||
import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off.svg';
|
||||
import { ReactComponent as VolumeUpIcon } from '@material-symbols/svg-600/outlined/volume_up.svg';
|
||||
import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off-fill.svg';
|
||||
import { ReactComponent as VolumeUpIcon } from '@material-symbols/svg-600/outlined/volume_up-fill.svg';
|
||||
import { throttle, debounce } from 'lodash';
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
|
|
|
@ -6,10 +6,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { ReactComponent as BlockIcon } from '@material-symbols/svg-600/outlined/block-fill.svg';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import { fetchBlocks, expandBlocks } from '../../actions/blocks';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import AccountContainer from '../../containers/account_container';
|
||||
|
@ -59,8 +59,7 @@ class Blocks extends ImmutablePureComponent {
|
|||
const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage="You haven't blocked any users yet." />;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} icon='ban' heading={intl.formatMessage(messages.heading)}>
|
||||
<ColumnBackButtonSlim />
|
||||
<Column bindToDocument={!multiColumn} icon='ban' iconComponent={BlockIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
|
||||
<ScrollableList
|
||||
scrollKey='blocks'
|
||||
onLoadMore={this.handleLoadMore}
|
||||
|
|
|
@ -8,10 +8,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { ReactComponent as BlockIcon } from '@material-symbols/svg-600/outlined/block-fill.svg';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import DomainContainer from '../../containers/domain_container';
|
||||
|
@ -60,9 +60,7 @@ class Blocks extends ImmutablePureComponent {
|
|||
const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no blocked domains yet.' />;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} icon='ban' heading={intl.formatMessage(messages.heading)}>
|
||||
<ColumnBackButtonSlim />
|
||||
|
||||
<Column bindToDocument={!multiColumn} icon='ban' iconComponent={BlockIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
|
||||
<ScrollableList
|
||||
scrollKey='domain_blocks'
|
||||
onLoadMore={this.handleLoadMore}
|
||||
|
|
|
@ -12,7 +12,6 @@ import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outli
|
|||
import { debounce } from 'lodash';
|
||||
|
||||
import { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import { me } from '../../initial_state';
|
||||
import Column from '../ui/components/column';
|
||||
|
@ -68,8 +67,7 @@ class FollowRequests extends ImmutablePureComponent {
|
|||
);
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} icon='user-plus' iconComponent={PersonAddIcon} heading={intl.formatMessage(messages.heading)}>
|
||||
<ColumnBackButtonSlim />
|
||||
<Column bindToDocument={!multiColumn} icon='user-plus' iconComponent={PersonAddIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
|
||||
<ScrollableList
|
||||
scrollKey='follow_requests'
|
||||
onLoadMore={this.handleLoadMore}
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
fetchFollowers,
|
||||
expandFollowers,
|
||||
} from '../../actions/accounts';
|
||||
import ColumnBackButton from '../../components/column_back_button';
|
||||
import { ColumnBackButton } from '../../components/column_back_button';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import AccountContainer from '../../containers/account_container';
|
||||
|
@ -147,7 +147,7 @@ class Followers extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<Column>
|
||||
<ColumnBackButton multiColumn={multiColumn} />
|
||||
<ColumnBackButton />
|
||||
|
||||
<ScrollableList
|
||||
scrollKey='followers'
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
fetchFollowing,
|
||||
expandFollowing,
|
||||
} from '../../actions/accounts';
|
||||
import ColumnBackButton from '../../components/column_back_button';
|
||||
import { ColumnBackButton } from '../../components/column_back_button';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import AccountContainer from '../../containers/account_container';
|
||||
|
@ -147,7 +147,7 @@ class Following extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<Column>
|
||||
<ColumnBackButton multiColumn={multiColumn} />
|
||||
<ColumnBackButton />
|
||||
|
||||
<ScrollableList
|
||||
scrollKey='following'
|
||||
|
|
|
@ -12,7 +12,6 @@ import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outli
|
|||
import { debounce } from 'lodash';
|
||||
|
||||
import { fetchMutes, expandMutes } from '../../actions/mutes';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import AccountContainer from '../../containers/account_container';
|
||||
|
@ -62,8 +61,7 @@ class Mutes extends ImmutablePureComponent {
|
|||
const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} icon='volume-off' iconComponent={VolumeOffIcon} heading={intl.formatMessage(messages.heading)}>
|
||||
<ColumnBackButtonSlim />
|
||||
<Column bindToDocument={!multiColumn} icon='volume-off' iconComponent={VolumeOffIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
|
||||
<ScrollableList
|
||||
scrollKey='mutes'
|
||||
onLoadMore={this.handleLoadMore}
|
||||
|
|
|
@ -9,7 +9,7 @@ import { connect } from 'react-redux';
|
|||
import { fetchSuggestions } from 'mastodon/actions/suggestions';
|
||||
import { markAsPartial } from 'mastodon/actions/timelines';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnBackButton from 'mastodon/components/column_back_button';
|
||||
import { ColumnBackButton } from 'mastodon/components/column_back_button';
|
||||
import { EmptyAccount } from 'mastodon/components/empty_account';
|
||||
import Account from 'mastodon/containers/account_container';
|
||||
|
||||
|
@ -25,7 +25,6 @@ class Follows extends PureComponent {
|
|||
dispatch: PropTypes.func.isRequired,
|
||||
suggestions: ImmutablePropTypes.list,
|
||||
isLoading: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
|
@ -39,7 +38,7 @@ class Follows extends PureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { onBack, isLoading, suggestions, multiColumn } = this.props;
|
||||
const { onBack, isLoading, suggestions } = this.props;
|
||||
|
||||
let loadedContent;
|
||||
|
||||
|
@ -53,7 +52,7 @@ class Follows extends PureComponent {
|
|||
|
||||
return (
|
||||
<Column>
|
||||
<ColumnBackButton multiColumn={multiColumn} onClick={onBack} />
|
||||
<ColumnBackButton onClick={onBack} />
|
||||
|
||||
<div className='scrollable privacy-policy'>
|
||||
<div className='column-title'>
|
||||
|
|
|
@ -47,7 +47,6 @@ class Onboarding extends ImmutablePureComponent {
|
|||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
account: ImmutablePropTypes.map,
|
||||
multiColumn: PropTypes.bool,
|
||||
...WithRouterPropTypes,
|
||||
};
|
||||
|
||||
|
@ -100,14 +99,14 @@ class Onboarding extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { account, multiColumn } = this.props;
|
||||
const { account } = this.props;
|
||||
const { step, shareClicked } = this.state;
|
||||
|
||||
switch(step) {
|
||||
case 'follows':
|
||||
return <Follows onBack={this.handleBackClick} multiColumn={multiColumn} />;
|
||||
return <Follows onBack={this.handleBackClick} />;
|
||||
case 'share':
|
||||
return <Share onBack={this.handleBackClick} multiColumn={multiColumn} />;
|
||||
return <Share onBack={this.handleBackClick} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -14,7 +14,7 @@ import { ReactComponent as ContentCopyIcon } from '@material-symbols/svg-600/out
|
|||
import SwipeableViews from 'react-swipeable-views';
|
||||
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnBackButton from 'mastodon/components/column_back_button';
|
||||
import { ColumnBackButton } from 'mastodon/components/column_back_button';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { me, domain } from 'mastodon/initial_state';
|
||||
|
||||
|
@ -146,18 +146,17 @@ class Share extends PureComponent {
|
|||
static propTypes = {
|
||||
onBack: PropTypes.func,
|
||||
account: ImmutablePropTypes.map,
|
||||
multiColumn: PropTypes.bool,
|
||||
intl: PropTypes.object,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { onBack, account, multiColumn, intl } = this.props;
|
||||
const { onBack, account, intl } = this.props;
|
||||
|
||||
const url = (new URL(`/@${account.get('username')}`, document.baseURI)).href;
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<ColumnBackButton multiColumn={multiColumn} onClick={onBack} />
|
||||
<ColumnBackButton onClick={onBack} />
|
||||
|
||||
<div className='scrollable privacy-policy'>
|
||||
<div className='column-title'>
|
||||
|
|
|
@ -13,7 +13,6 @@ import { ReactComponent as PushPinIcon } from '@material-symbols/svg-600/outline
|
|||
import { getStatusList } from 'mastodon/selectors';
|
||||
|
||||
import { fetchPinnedStatuses } from '../../actions/pin_statuses';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import StatusList from '../../components/status_list';
|
||||
import Column from '../ui/components/column';
|
||||
|
||||
|
@ -52,8 +51,7 @@ class PinnedStatuses extends ImmutablePureComponent {
|
|||
const { intl, statusIds, hasMore, multiColumn } = this.props;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} icon='thumb-tack' iconComponent={PushPinIcon} heading={intl.formatMessage(messages.heading)} ref={this.setRef}>
|
||||
<ColumnBackButtonSlim />
|
||||
<Column bindToDocument={!multiColumn} icon='thumb-tack' iconComponent={PushPinIcon} heading={intl.formatMessage(messages.heading)} ref={this.setRef} alwaysShowBackButton>
|
||||
<StatusList
|
||||
statusIds={statusIds}
|
||||
scrollKey='pinned_statuses'
|
||||
|
|
|
@ -10,9 +10,9 @@ import classNames from 'classnames';
|
|||
import Immutable from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import { ReactComponent as DescriptionIcon } from '@material-symbols/svg-600/outlined/description.svg';
|
||||
import { ReactComponent as DescriptionIcon } from '@material-symbols/svg-600/outlined/description-fill.svg';
|
||||
import { ReactComponent as OpenInNewIcon } from '@material-symbols/svg-600/outlined/open_in_new.svg';
|
||||
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow.svg';
|
||||
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow-fill.svg';
|
||||
|
||||
import { Blurhash } from 'mastodon/components/blurhash';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
|
@ -143,7 +143,7 @@ export default class Card extends PureComponent {
|
|||
|
||||
<strong className='status-card__title' title={card.get('title')} lang={language}>{card.get('title')}</strong>
|
||||
|
||||
{card.get('author_name').length > 0 ? <span className='status-card__author'><FormattedMessage id='link_preview.author' defaultMessage='By {name}' values={{ name: <strong>{card.get('author_name')}</strong> }} /></span> : <span className='status-card__description'>{card.get('description')}</span>}
|
||||
{card.get('author_name').length > 0 ? <span className='status-card__author'><FormattedMessage id='link_preview.author' defaultMessage='By {name}' values={{ name: <strong>{card.get('author_name')}</strong> }} /></span> : <span className='status-card__description' lang={language}>{card.get('description')}</span>}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
handleAccountClick = (e) => {
|
||||
if (e.button === 0 && !(e.ctrlKey || e.metaKey) && this.props.history) {
|
||||
e.preventDefault();
|
||||
this.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
|
||||
this.props.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { render, fireEvent, screen } from '@testing-library/react';
|
||||
import { render, fireEvent, screen } from 'mastodon/test_helpers';
|
||||
|
||||
import Column from '../column';
|
||||
|
||||
const fakeIcon = () => <span />;
|
||||
|
||||
describe('<Column />', () => {
|
||||
describe('<ColumnHeader /> click handler', () => {
|
||||
it('runs the scroll animation if the column contains scrollable content', () => {
|
||||
const scrollToMock = jest.fn();
|
||||
const { container } = render(
|
||||
<Column heading='notifications'>
|
||||
<Column heading='notifications' icon='notifications' iconComponent={fakeIcon}>
|
||||
<div className='scrollable' />
|
||||
</Column>,
|
||||
);
|
||||
|
@ -17,7 +19,7 @@ describe('<Column />', () => {
|
|||
});
|
||||
|
||||
it('does not try to scroll if there is no scrollable content', () => {
|
||||
render(<Column heading='notifications' />);
|
||||
render(<Column heading='notifications' icon='notifications' iconComponent={fakeIcon} />);
|
||||
fireEvent.click(screen.getByText('notifications'));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,15 +3,15 @@ import { PureComponent } from 'react';
|
|||
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import ColumnHeader from '../../../components/column_header';
|
||||
import { isMobile } from '../../../is_mobile';
|
||||
import { scrollTop } from '../../../scroll';
|
||||
|
||||
import ColumnHeader from './column_header';
|
||||
|
||||
export default class Column extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
heading: PropTypes.string,
|
||||
alwaysShowBackButton: PropTypes.bool,
|
||||
icon: PropTypes.string,
|
||||
iconComponent: PropTypes.func,
|
||||
children: PropTypes.node,
|
||||
|
@ -51,13 +51,14 @@ export default class Column extends PureComponent {
|
|||
};
|
||||
|
||||
render () {
|
||||
const { heading, icon, iconComponent, children, active, hideHeadingOnMobile } = this.props;
|
||||
const { heading, icon, iconComponent, children, active, hideHeadingOnMobile, alwaysShowBackButton } = this.props;
|
||||
|
||||
const showHeading = heading && (!hideHeadingOnMobile || (hideHeadingOnMobile && !isMobile(window.innerWidth)));
|
||||
|
||||
const columnHeaderId = showHeading && heading.replace(/ /g, '-');
|
||||
|
||||
const header = showHeading && (
|
||||
<ColumnHeader icon={icon} iconComponent={iconComponent} active={active} type={heading} onClick={this.handleHeaderClick} columnHeaderId={columnHeaderId} />
|
||||
<ColumnHeader icon={icon} iconComponent={iconComponent} active={active} title={heading} onClick={this.handleHeaderClick} columnHeaderId={columnHeaderId} showBackButton={alwaysShowBackButton} />
|
||||
);
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
|
||||
export default class ColumnHeader extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
icon: PropTypes.string,
|
||||
iconComponent: PropTypes.func,
|
||||
type: PropTypes.string,
|
||||
active: PropTypes.bool,
|
||||
onClick: PropTypes.func,
|
||||
columnHeaderId: PropTypes.string,
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
this.props.onClick();
|
||||
};
|
||||
|
||||
render () {
|
||||
const { icon, iconComponent, type, active, columnHeaderId } = this.props;
|
||||
let iconElement = '';
|
||||
|
||||
if (icon) {
|
||||
iconElement = <Icon id={icon} icon={iconComponent} className='column-header__icon' />;
|
||||
}
|
||||
|
||||
return (
|
||||
<h1 className={classNames('column-header', { active })} id={columnHeaderId || null}>
|
||||
<button onClick={this.handleClick}>
|
||||
{iconElement}
|
||||
{type}
|
||||
</button>
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { Children, cloneElement } from 'react';
|
||||
import { Children, cloneElement, useCallback } from 'react';
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
@ -21,6 +21,7 @@ import {
|
|||
ListTimeline,
|
||||
Directory,
|
||||
} from '../util/async-components';
|
||||
import { useColumnsContext } from '../util/columns_context';
|
||||
|
||||
import BundleColumnError from './bundle_column_error';
|
||||
import { ColumnLoading } from './column_loading';
|
||||
|
@ -43,6 +44,17 @@ const componentMap = {
|
|||
'DIRECTORY': Directory,
|
||||
};
|
||||
|
||||
const TabsBarPortal = () => {
|
||||
const {setTabsBarElement} = useColumnsContext();
|
||||
|
||||
const setRef = useCallback((element) => {
|
||||
if(element)
|
||||
setTabsBarElement(element);
|
||||
}, [setTabsBarElement]);
|
||||
|
||||
return <div id='tabs-bar__portal' ref={setRef} />;
|
||||
};
|
||||
|
||||
export default class ColumnsArea extends ImmutablePureComponent {
|
||||
static propTypes = {
|
||||
columns: ImmutablePropTypes.list.isRequired,
|
||||
|
@ -146,7 +158,7 @@ export default class ColumnsArea extends ImmutablePureComponent {
|
|||
</div>
|
||||
|
||||
<div className='columns-area__panels__main'>
|
||||
<div className='tabs-bar__wrapper'><div id='tabs-bar__portal' /></div>
|
||||
<div className='tabs-bar__wrapper'><TabsBarPortal /></div>
|
||||
<div className='columns-area columns-area--mobile'>{children}</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -64,8 +64,8 @@ import {
|
|||
About,
|
||||
PrivacyPolicy,
|
||||
} from './util/async-components';
|
||||
import { ColumnsContextProvider } from './util/columns_context';
|
||||
import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';
|
||||
|
||||
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
||||
// Without this it ends up in ~8 very commonly used bundles.
|
||||
import '../../components/status';
|
||||
|
@ -179,68 +179,70 @@ class SwitchingColumnsArea extends PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}>
|
||||
<WrappedSwitch>
|
||||
{redirect}
|
||||
<ColumnsContextProvider multiColumn={!singleColumn}>
|
||||
<ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}>
|
||||
<WrappedSwitch>
|
||||
{redirect}
|
||||
|
||||
{singleColumn ? <Redirect from='/deck' to='/home' exact /> : null}
|
||||
{singleColumn && pathName.startsWith('/deck/') ? <Redirect from={pathName} to={pathName.slice(5)} /> : null}
|
||||
{/* Redirect old bookmarks (without /deck) with home-like routes to the advanced interface */}
|
||||
{!singleColumn && pathName === '/getting-started' ? <Redirect from='/getting-started' to='/deck/getting-started' exact /> : null}
|
||||
{!singleColumn && pathName === '/home' ? <Redirect from='/home' to='/deck/getting-started' exact /> : null}
|
||||
{singleColumn ? <Redirect from='/deck' to='/home' exact /> : null}
|
||||
{singleColumn && pathName.startsWith('/deck/') ? <Redirect from={pathName} to={pathName.slice(5)} /> : null}
|
||||
{/* Redirect old bookmarks (without /deck) with home-like routes to the advanced interface */}
|
||||
{!singleColumn && pathName === '/getting-started' ? <Redirect from='/getting-started' to='/deck/getting-started' exact /> : null}
|
||||
{!singleColumn && pathName === '/home' ? <Redirect from='/home' to='/deck/getting-started' exact /> : null}
|
||||
|
||||
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
|
||||
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
|
||||
<WrappedRoute path='/about' component={About} content={children} />
|
||||
<WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} />
|
||||
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
|
||||
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
|
||||
<WrappedRoute path='/about' component={About} content={children} />
|
||||
<WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} />
|
||||
|
||||
<WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} />
|
||||
<Redirect from='/timelines/public' to='/public' exact />
|
||||
<Redirect from='/timelines/public/local' to='/public/local' exact />
|
||||
<WrappedRoute path='/public' exact component={Firehose} componentParams={{ feedType: 'public' }} content={children} />
|
||||
<WrappedRoute path='/public/local' exact component={Firehose} componentParams={{ feedType: 'community' }} content={children} />
|
||||
<WrappedRoute path='/public/remote' exact component={Firehose} componentParams={{ feedType: 'public:remote' }} content={children} />
|
||||
<WrappedRoute path={['/conversations', '/timelines/direct']} component={DirectTimeline} content={children} />
|
||||
<WrappedRoute path='/tags/:id' component={HashtagTimeline} content={children} />
|
||||
<WrappedRoute path='/lists/:id' component={ListTimeline} content={children} />
|
||||
<WrappedRoute path='/notifications' component={Notifications} content={children} />
|
||||
<WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} />
|
||||
<WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} />
|
||||
<Redirect from='/timelines/public' to='/public' exact />
|
||||
<Redirect from='/timelines/public/local' to='/public/local' exact />
|
||||
<WrappedRoute path='/public' exact component={Firehose} componentParams={{ feedType: 'public' }} content={children} />
|
||||
<WrappedRoute path='/public/local' exact component={Firehose} componentParams={{ feedType: 'community' }} content={children} />
|
||||
<WrappedRoute path='/public/remote' exact component={Firehose} componentParams={{ feedType: 'public:remote' }} content={children} />
|
||||
<WrappedRoute path={['/conversations', '/timelines/direct']} component={DirectTimeline} content={children} />
|
||||
<WrappedRoute path='/tags/:id' component={HashtagTimeline} content={children} />
|
||||
<WrappedRoute path='/lists/:id' component={ListTimeline} content={children} />
|
||||
<WrappedRoute path='/notifications' component={Notifications} content={children} />
|
||||
<WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} />
|
||||
|
||||
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
|
||||
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
|
||||
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
|
||||
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
|
||||
|
||||
<WrappedRoute path='/start' exact component={Onboarding} content={children} />
|
||||
<WrappedRoute path='/directory' component={Directory} content={children} />
|
||||
<WrappedRoute path={['/explore', '/search']} component={Explore} content={children} />
|
||||
<WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} />
|
||||
<WrappedRoute path='/start' exact component={Onboarding} content={children} />
|
||||
<WrappedRoute path='/directory' component={Directory} content={children} />
|
||||
<WrappedRoute path={['/explore', '/search']} component={Explore} content={children} />
|
||||
<WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} />
|
||||
|
||||
<WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />
|
||||
<WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} />
|
||||
<WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
|
||||
<WrappedRoute path={['/accounts/:id/followers', '/users/:acct/followers', '/@:acct/followers']} component={Followers} content={children} />
|
||||
<WrappedRoute path={['/accounts/:id/following', '/users/:acct/following', '/@:acct/following']} component={Following} content={children} />
|
||||
<WrappedRoute path={['/@:acct/media', '/accounts/:id/media']} component={AccountGallery} content={children} />
|
||||
<WrappedRoute path='/@:acct/:statusId' exact component={Status} content={children} />
|
||||
<WrappedRoute path='/@:acct/:statusId/reblogs' component={Reblogs} content={children} />
|
||||
<WrappedRoute path='/@:acct/:statusId/favourites' component={Favourites} content={children} />
|
||||
<WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />
|
||||
<WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} />
|
||||
<WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
|
||||
<WrappedRoute path={['/accounts/:id/followers', '/users/:acct/followers', '/@:acct/followers']} component={Followers} content={children} />
|
||||
<WrappedRoute path={['/accounts/:id/following', '/users/:acct/following', '/@:acct/following']} component={Following} content={children} />
|
||||
<WrappedRoute path={['/@:acct/media', '/accounts/:id/media']} component={AccountGallery} content={children} />
|
||||
<WrappedRoute path='/@:acct/:statusId' exact component={Status} content={children} />
|
||||
<WrappedRoute path='/@:acct/:statusId/reblogs' component={Reblogs} content={children} />
|
||||
<WrappedRoute path='/@:acct/:statusId/favourites' component={Favourites} content={children} />
|
||||
|
||||
{/* Legacy routes, cannot be easily factored with other routes because they share a param name */}
|
||||
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} />
|
||||
<WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} />
|
||||
<WrappedRoute path='/statuses/:statusId/reblogs' component={Reblogs} content={children} />
|
||||
<WrappedRoute path='/statuses/:statusId/favourites' component={Favourites} content={children} />
|
||||
{/* Legacy routes, cannot be easily factored with other routes because they share a param name */}
|
||||
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} />
|
||||
<WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} />
|
||||
<WrappedRoute path='/statuses/:statusId/reblogs' component={Reblogs} content={children} />
|
||||
<WrappedRoute path='/statuses/:statusId/favourites' component={Favourites} content={children} />
|
||||
|
||||
<WrappedRoute path='/follow_requests' component={FollowRequests} content={children} />
|
||||
<WrappedRoute path='/blocks' component={Blocks} content={children} />
|
||||
<WrappedRoute path='/domain_blocks' component={DomainBlocks} content={children} />
|
||||
<WrappedRoute path='/followed_tags' component={FollowedTags} content={children} />
|
||||
<WrappedRoute path='/mutes' component={Mutes} content={children} />
|
||||
<WrappedRoute path='/lists' component={Lists} content={children} />
|
||||
<WrappedRoute path='/follow_requests' component={FollowRequests} content={children} />
|
||||
<WrappedRoute path='/blocks' component={Blocks} content={children} />
|
||||
<WrappedRoute path='/domain_blocks' component={DomainBlocks} content={children} />
|
||||
<WrappedRoute path='/followed_tags' component={FollowedTags} content={children} />
|
||||
<WrappedRoute path='/mutes' component={Mutes} content={children} />
|
||||
<WrappedRoute path='/lists' component={Lists} content={children} />
|
||||
|
||||
<Route component={BundleColumnError} />
|
||||
</WrappedSwitch>
|
||||
</ColumnsAreaContainer>
|
||||
<Route component={BundleColumnError} />
|
||||
</WrappedSwitch>
|
||||
</ColumnsAreaContainer>
|
||||
</ColumnsContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import type { ReactElement } from 'react';
|
||||
import { createContext, useContext, useMemo, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
export const ColumnsContext = createContext<{
|
||||
tabsBarElement: HTMLElement | null;
|
||||
setTabsBarElement: (element: HTMLElement) => void;
|
||||
multiColumn: boolean;
|
||||
}>({
|
||||
tabsBarElement: null,
|
||||
multiColumn: false,
|
||||
setTabsBarElement: () => undefined, // no-op
|
||||
});
|
||||
|
||||
export function useColumnsContext() {
|
||||
return useContext(ColumnsContext);
|
||||
}
|
||||
|
||||
export const ButtonInTabsBar: React.FC<{
|
||||
children: ReactElement | string | undefined;
|
||||
}> = ({ children }) => {
|
||||
const { multiColumn, tabsBarElement } = useColumnsContext();
|
||||
|
||||
if (multiColumn) {
|
||||
return children;
|
||||
} else if (!tabsBarElement) {
|
||||
return children;
|
||||
} else {
|
||||
return createPortal(children, tabsBarElement);
|
||||
}
|
||||
};
|
||||
|
||||
type ContextValue = React.ContextType<typeof ColumnsContext>;
|
||||
|
||||
export const ColumnsContextProvider: React.FC<
|
||||
React.PropsWithChildren<{ multiColumn: boolean }>
|
||||
> = ({ multiColumn, children }) => {
|
||||
const [tabsBarElement, setTabsBarElement] =
|
||||
useState<ContextValue['tabsBarElement']>(null);
|
||||
|
||||
const contextValue = useMemo<ContextValue>(
|
||||
() => ({ multiColumn, tabsBarElement, setTabsBarElement }),
|
||||
[multiColumn, tabsBarElement],
|
||||
);
|
||||
|
||||
return (
|
||||
<ColumnsContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</ColumnsContext.Provider>
|
||||
);
|
||||
};
|
|
@ -10,11 +10,11 @@ import { is } from 'immutable';
|
|||
import { ReactComponent as FullscreenIcon } from '@material-symbols/svg-600/outlined/fullscreen.svg';
|
||||
import { ReactComponent as FullscreenExitIcon } from '@material-symbols/svg-600/outlined/fullscreen_exit.svg';
|
||||
import { ReactComponent as PauseIcon } from '@material-symbols/svg-600/outlined/pause.svg';
|
||||
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow.svg';
|
||||
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow-fill.svg';
|
||||
import { ReactComponent as RectangleIcon } from '@material-symbols/svg-600/outlined/rectangle.svg';
|
||||
import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
|
||||
import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off.svg';
|
||||
import { ReactComponent as VolumeUpIcon } from '@material-symbols/svg-600/outlined/volume_up.svg';
|
||||
import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off-fill.svg';
|
||||
import { ReactComponent as VolumeUpIcon } from '@material-symbols/svg-600/outlined/volume_up-fill.svg';
|
||||
import { throttle } from 'lodash';
|
||||
|
||||
import { Blurhash } from 'mastodon/components/blurhash';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"about.blocks": "Valvotut palvelimet",
|
||||
"about.blocks": "Moderoidut palvelimet",
|
||||
"about.contact": "Ota yhteyttä:",
|
||||
"about.disclaimer": "Mastodon on vapaa avoimen lähdekoodin ohjelmisto ja Mastodon gGmbH:n tavaramerkki.",
|
||||
"about.domain_blocks.no_reason_available": "Syytä ei ole ilmoitettu",
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
"account.block_short": "Bloquear",
|
||||
"account.blocked": "Bloqueada",
|
||||
"account.browse_more_on_origin_server": "Busca máis no perfil orixinal",
|
||||
"account.cancel_follow_request": "Retirar solicitude de seguimento",
|
||||
"account.cancel_follow_request": "Cancelar a solicitude de seguimento",
|
||||
"account.direct": "Mencionar de xeito privado a @{name}",
|
||||
"account.disable_notifications": "Deixar de notificarme cando @{name} publica",
|
||||
"account.domain_blocked": "Dominio agochado",
|
||||
|
|
|
@ -202,7 +202,7 @@
|
|||
"dismissable_banner.community_timeline": "אלו הם החצרוצים הציבוריים האחרונים מהמשתמשים על שרת {domain}.",
|
||||
"dismissable_banner.dismiss": "בטל",
|
||||
"dismissable_banner.explore_links": "אלו הקישורים האחרונים ששותפו על ידי משתמשים ששרת זה רואה ברשת המבוזרת כרגע.",
|
||||
"dismissable_banner.explore_statuses": "ההודעות האלו, משרת זה ואחרים ברשת המבוזרת, צוברים חשיפה היום. הודעות חדשות יותר עם יותר הדהודים וחיבובים מדורגים יותר לגובה.",
|
||||
"dismissable_banner.explore_statuses": "ההודעות האלו, משרת זה ואחרים ברשת המבוזרת, צוברים חשיפה היום. הודעות חדשות יותר עם יותר הדהודים וחיבובים מדורגים גבוה יותר.",
|
||||
"dismissable_banner.explore_tags": "התגיות האלו, משרת זה ואחרים ברשת המבוזרת, צוברות חשיפה כעת.",
|
||||
"dismissable_banner.public_timeline": "אלו ההודעות האחרונות שהתקבלו מהמשתמשים שנעקבים על ידי משתמשים מ־{domain}.",
|
||||
"embed.instructions": "ניתן להטמיע את ההודעה הזו באתרך ע\"י העתקת הקוד שלהלן.",
|
||||
|
@ -315,7 +315,7 @@
|
|||
"home.pending_critical_update.title": "יצא עדכון אבטחה חשוב!",
|
||||
"home.show_announcements": "הצג הכרזות",
|
||||
"interaction_modal.description.favourite": "עם חשבון מסטודון, ניתן לחבב את ההודעה כדי לומר למחבר/ת שהערכת את תוכנו או כדי לשמור אותו לקריאה בעתיד.",
|
||||
"interaction_modal.description.follow": "עם חשבון מסטודון, ניתן לעקוב אחרי {name} כדי לקבל את הםוסטים שלו/ה בפיד הבית.",
|
||||
"interaction_modal.description.follow": "עם חשבון מסטודון, ניתן לעקוב אחרי {name} כדי לקבל את הפוסטים שלו/ה בפיד הבית.",
|
||||
"interaction_modal.description.reblog": "עם חשבון מסטודון, ניתן להדהד את החצרוץ ולשתף עם עוקבים.",
|
||||
"interaction_modal.description.reply": "עם חשבון מסטודון, ניתן לענות לחצרוץ.",
|
||||
"interaction_modal.login.action": "קח אותי לדף הבית",
|
||||
|
@ -493,7 +493,7 @@
|
|||
"onboarding.steps.setup_profile.title": "התאמה אישית של הפרופיל",
|
||||
"onboarding.steps.share_profile.body": "ספרו לחברים איך למצוא אתכם במסטודון!",
|
||||
"onboarding.steps.share_profile.title": "לשתף פרופיל",
|
||||
"onboarding.tips.2fa": "<strong>הידעת?</strong> ניתן לאבטח את החשבון ע\"י הקמת אימות בשני צעדים במסך מאפייני החשבון. השיטה תעבוד עם כל יישומון תואם TOTP על המגשיר שלך, אין צורך לתת לנו את מספר הטלפון!",
|
||||
"onboarding.tips.2fa": "<strong>הידעת?</strong> ניתן לאבטח את החשבון ע\"י הקמת אימות דו-שלבי במסך מאפייני החשבון. השיטה תעבוד עם כל יישומון תואם TOTP על המכשיר שלך, ללא צורך במספר טלפון!",
|
||||
"onboarding.tips.accounts_from_other_servers": "<strong>הידעת?</strong> כיוון שמסטודון פועל ברשת מבוזרת, חלק מהפרופילים שתתקלו בהם פועלים משרתים אחרים משרת הבית שלכם. ניתן להיות איתם בקשר בצורה זהה לכל חשבון אחר! שם השרת שלהם הוא החלק השני של שם המשתמש שלהם!",
|
||||
"onboarding.tips.migration": "<strong>הידעת?</strong> אם תחליטו כי {domain} איננו שרת שמתאים לכם בעתיד, ניתן לעבור לשרת אחר מבלי לאבד עוקבים. תוכלו אפילו להקים שרת משלכן!",
|
||||
"onboarding.tips.verification": "<strong>הידעת?</strong> ניתן לאשרר את החשבון ע\"י קישור הפרופיל אל האתר שלכם ומהאתר חזרה לפרופיל. לא נדרשים תשלומים ומסמכים!",
|
||||
|
@ -575,7 +575,7 @@
|
|||
"report.thanks.title": "לא מעוניין/ת לראות את זה?",
|
||||
"report.thanks.title_actionable": "תודה על הדיווח, נבדוק את העניין.",
|
||||
"report.unfollow": "הפסיקו לעקוב אחרי @{name}",
|
||||
"report.unfollow_explanation": "אתם עוקבים אחרי החשבון הזה. כדי להפסיק לראות את הפרסומים שלו בפיד הבית שלכם, הפסיקו לעקוב אחריהם.",
|
||||
"report.unfollow_explanation": "אתם עוקבים אחרי החשבון הזה. כדי להפסיק לראות את הפרסומים שלו בפיד הבית שלכם, הפסיקו לעקוב אחריו.",
|
||||
"report_notification.attached_statuses": "{count, plural, one {הודעה מצורפת} two {הודעותיים מצורפות} many {{count} הודעות מצורפות} other {{count} הודעות מצורפות}}",
|
||||
"report_notification.categories.legal": "חוקי",
|
||||
"report_notification.categories.other": "שונות",
|
||||
|
|
|
@ -590,7 +590,7 @@
|
|||
"search.quick_action.open_url": "마스토돈에서 URL 열기",
|
||||
"search.quick_action.status_search": "{x}에 맞는 게시물",
|
||||
"search.search_or_paste": "검색하거나 URL 붙여넣기",
|
||||
"search_popout.full_text_search_disabled_message": "{domain}에서는 사용할 수 없습니다.",
|
||||
"search_popout.full_text_search_disabled_message": "{domain}에서는 이용할 수 없습니다.",
|
||||
"search_popout.language_code": "ISO 언어코드",
|
||||
"search_popout.options": "검색 옵션",
|
||||
"search_popout.quick_actions": "빠른 작업",
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
"admin.impact_report.instance_follows": "Obserwujący, których straciliby ich użytkownicy",
|
||||
"admin.impact_report.title": "Podsumowanie wpływu",
|
||||
"alert.rate_limited.message": "Spróbuj ponownie po {retry_time, time, medium}.",
|
||||
"alert.rate_limited.title": "Ograniczony czasowo",
|
||||
"alert.rate_limited.title": "Ograniczenie liczby zapytań",
|
||||
"alert.unexpected.message": "Wystąpił nieoczekiwany błąd.",
|
||||
"alert.unexpected.title": "Ups!",
|
||||
"announcement.announcement": "Ogłoszenie",
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { Component } from 'react';
|
||||
|
||||
import { IntlProvider } from 'react-intl';
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
function render(
|
||||
ui: React.ReactElement,
|
||||
{ locale = 'en', signedIn = true, ...renderOptions } = {},
|
||||
) {
|
||||
const Wrapper = (props: { children: React.ReactElement }) => {
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<IntlProvider locale={locale}>
|
||||
<FakeIdentityWrapper signedIn={signedIn}>
|
||||
{props.children}
|
||||
</FakeIdentityWrapper>
|
||||
</IntlProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
return rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
|
||||
}
|
||||
|
||||
// re-export everything
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
export * from '@testing-library/react';
|
||||
|
||||
// override render method
|
||||
export { render };
|
|
@ -3137,20 +3137,6 @@ $ui-header-height: 55px;
|
|||
margin-inline-end: 5px;
|
||||
}
|
||||
|
||||
.column-back-button--slim {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.column-back-button--slim-button {
|
||||
cursor: pointer;
|
||||
flex: 0 0 auto;
|
||||
font-size: 16px;
|
||||
padding: 15px;
|
||||
position: absolute;
|
||||
inset-inline-end: 0;
|
||||
top: -50px;
|
||||
}
|
||||
|
||||
.react-toggle {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
@ -7434,7 +7420,12 @@ noscript {
|
|||
border: 1px solid lighten($ui-base-color, 12%);
|
||||
border-radius: 4px;
|
||||
box-sizing: content-box;
|
||||
padding: 2px;
|
||||
padding: 5px;
|
||||
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7517,6 +7508,11 @@ noscript {
|
|||
color: lighten($ui-highlight-color, 8%);
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.verified {
|
||||
border: 1px solid rgba($valid-value-color, 0.5);
|
||||
margin-top: -1px;
|
||||
|
@ -7537,6 +7533,16 @@ noscript {
|
|||
color: $valid-value-color;
|
||||
}
|
||||
|
||||
dd {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: $valid-value-color;
|
||||
}
|
||||
|
|
|
@ -75,7 +75,12 @@ class AttachmentBatch
|
|||
end
|
||||
when :fog
|
||||
logger.debug { "Deleting #{attachment.path(style)}" }
|
||||
attachment.directory.files.new(key: attachment.path(style)).destroy
|
||||
|
||||
begin
|
||||
attachment.send(:directory).files.new(key: attachment.path(style)).destroy
|
||||
rescue Fog::Storage::OpenStack::NotFound
|
||||
# Ignore failure to delete a file that has already been deleted
|
||||
end
|
||||
when :azure
|
||||
logger.debug { "Deleting #{attachment.path(style)}" }
|
||||
attachment.destroy
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ContentSecurityPolicy
|
||||
def base_host
|
||||
Rails.configuration.x.web_domain
|
||||
end
|
||||
|
||||
def assets_host
|
||||
url_from_configured_asset_host || url_from_base_host
|
||||
end
|
||||
|
||||
def media_host
|
||||
cdn_host_value || assets_host
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def url_from_configured_asset_host
|
||||
Rails.configuration.action_controller.asset_host
|
||||
end
|
||||
|
||||
def cdn_host_value
|
||||
s3_alias_host || s3_cloudfront_host || azure_alias_host || s3_hostname_host
|
||||
end
|
||||
|
||||
def url_from_base_host
|
||||
host_to_url(base_host)
|
||||
end
|
||||
|
||||
def host_to_url(host_string)
|
||||
uri_from_configuration_and_string(host_string) if host_string.present?
|
||||
end
|
||||
|
||||
def s3_alias_host
|
||||
host_to_url ENV.fetch('S3_ALIAS_HOST', nil)
|
||||
end
|
||||
|
||||
def s3_cloudfront_host
|
||||
host_to_url ENV.fetch('S3_CLOUDFRONT_HOST', nil)
|
||||
end
|
||||
|
||||
def azure_alias_host
|
||||
host_to_url ENV.fetch('AZURE_ALIAS_HOST', nil)
|
||||
end
|
||||
|
||||
def s3_hostname_host
|
||||
host_to_url ENV.fetch('S3_HOSTNAME', nil)
|
||||
end
|
||||
|
||||
def uri_from_configuration_and_string(host_string)
|
||||
Addressable::URI.parse("#{host_protocol}://#{host_string}").tap do |uri|
|
||||
uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/')
|
||||
end.to_s
|
||||
end
|
||||
|
||||
def host_protocol
|
||||
Rails.configuration.x.use_https ? 'https' : 'http'
|
||||
end
|
||||
end
|
|
@ -8,13 +8,15 @@ class UserMailer < Devise::Mailer
|
|||
helper :instance
|
||||
helper :statuses
|
||||
helper :formatting
|
||||
helper :routing
|
||||
|
||||
helper RoutingHelper
|
||||
before_action :set_instance
|
||||
|
||||
default to: -> { @resource.email }
|
||||
|
||||
def confirmation_instructions(user, token, *, **)
|
||||
@resource = user
|
||||
@token = token
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
|
@ -28,185 +30,177 @@ class UserMailer < Devise::Mailer
|
|||
def reset_password_instructions(user, token, *, **)
|
||||
@resource = user
|
||||
@token = token
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('devise.mailer.reset_password_instructions.subject')
|
||||
mail subject: default_devise_subject
|
||||
end
|
||||
end
|
||||
|
||||
def password_change(user, *, **)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('devise.mailer.password_change.subject')
|
||||
mail subject: default_devise_subject
|
||||
end
|
||||
end
|
||||
|
||||
def email_changed(user, *, **)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('devise.mailer.email_changed.subject')
|
||||
mail subject: default_devise_subject
|
||||
end
|
||||
end
|
||||
|
||||
def two_factor_enabled(user, *, **)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_enabled.subject')
|
||||
mail subject: default_devise_subject
|
||||
end
|
||||
end
|
||||
|
||||
def two_factor_disabled(user, *, **)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_disabled.subject')
|
||||
mail subject: default_devise_subject
|
||||
end
|
||||
end
|
||||
|
||||
def two_factor_recovery_codes_changed(user, *, **)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_recovery_codes_changed.subject')
|
||||
mail subject: default_devise_subject
|
||||
end
|
||||
end
|
||||
|
||||
def webauthn_enabled(user, *, **)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_enabled.subject')
|
||||
mail subject: default_devise_subject
|
||||
end
|
||||
end
|
||||
|
||||
def webauthn_disabled(user, *, **)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_disabled.subject')
|
||||
mail subject: default_devise_subject
|
||||
end
|
||||
end
|
||||
|
||||
def webauthn_credential_added(user, webauthn_credential)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
@webauthn_credential = webauthn_credential
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_credential.added.subject')
|
||||
mail subject: I18n.t('devise.mailer.webauthn_credential.added.subject')
|
||||
end
|
||||
end
|
||||
|
||||
def webauthn_credential_deleted(user, webauthn_credential)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
@webauthn_credential = webauthn_credential
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_credential.deleted.subject')
|
||||
mail subject: I18n.t('devise.mailer.webauthn_credential.deleted.subject')
|
||||
end
|
||||
end
|
||||
|
||||
def welcome(user)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('user_mailer.welcome.subject')
|
||||
mail subject: default_i18n_subject
|
||||
end
|
||||
end
|
||||
|
||||
def backup_ready(user, backup)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
@backup = backup
|
||||
|
||||
return unless @resource.active_for_authentication?
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('user_mailer.backup_ready.subject')
|
||||
mail subject: default_i18n_subject
|
||||
end
|
||||
end
|
||||
|
||||
def warning(user, warning)
|
||||
@resource = user
|
||||
@warning = warning
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
@statuses = @warning.statuses.includes(:account, :preloadable_poll, :media_attachments, active_mentions: [:account])
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t("user_mailer.warning.subject.#{@warning.action}", acct: "@#{user.account.local_username_and_domain}")
|
||||
mail subject: I18n.t("user_mailer.warning.subject.#{@warning.action}", acct: "@#{user.account.local_username_and_domain}")
|
||||
end
|
||||
end
|
||||
|
||||
def appeal_approved(user, appeal)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
@appeal = appeal
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('user_mailer.appeal_approved.subject', date: l(@appeal.created_at))
|
||||
mail subject: default_i18n_subject(date: l(@appeal.created_at))
|
||||
end
|
||||
end
|
||||
|
||||
def appeal_rejected(user, appeal)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
@appeal = appeal
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('user_mailer.appeal_rejected.subject', date: l(@appeal.created_at))
|
||||
mail subject: default_i18n_subject(date: l(@appeal.created_at))
|
||||
end
|
||||
end
|
||||
|
||||
def suspicious_sign_in(user, remote_ip, user_agent, timestamp)
|
||||
@resource = user
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
@remote_ip = remote_ip
|
||||
@user_agent = user_agent
|
||||
@detection = Browser.new(user_agent)
|
||||
@timestamp = timestamp.to_time.utc
|
||||
|
||||
I18n.with_locale(locale) do
|
||||
mail to: @resource.email, subject: I18n.t('user_mailer.suspicious_sign_in.subject')
|
||||
mail subject: default_i18n_subject
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_devise_subject
|
||||
I18n.t(:subject, scope: ['devise.mailer', action_name])
|
||||
end
|
||||
|
||||
def set_instance
|
||||
@instance = Rails.configuration.x.local_domain
|
||||
end
|
||||
|
||||
def locale
|
||||
@resource.locale.presence || I18n.default_locale
|
||||
end
|
||||
|
|
|
@ -35,7 +35,7 @@ class Tag < ApplicationRecord
|
|||
HASHTAG_LAST_SEQUENCE = '([[:word:]_]*[[:alpha:]][[:word:]_]*)'
|
||||
HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASHTAG_LAST_SEQUENCE}"
|
||||
|
||||
HASHTAG_RE = %r{(?<![=/)[:word]])#(#{HASHTAG_NAME_PAT})}i
|
||||
HASHTAG_RE = %r{(?<![=/)\w])#(#{HASHTAG_NAME_PAT})}i
|
||||
HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i
|
||||
HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]#{HASHTAG_SEPARATORS}]/
|
||||
|
||||
|
|
|
@ -488,7 +488,7 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
def validate_email_dns?
|
||||
email_changed? && !external? && !(Rails.env.test? || Rails.env.development?)
|
||||
email_changed? && !external? && !Rails.env.local? # rubocop:disable Rails/UnknownEnv
|
||||
end
|
||||
|
||||
def validate_role_elevation
|
||||
|
|
|
@ -10,7 +10,9 @@ class REST::FeaturedTagSerializer < ActiveModel::Serializer
|
|||
end
|
||||
|
||||
def url
|
||||
short_account_tag_url(object.account, object.tag)
|
||||
# The path is hardcoded because we have to deal with both local and
|
||||
# remote users, which are different routes
|
||||
account_with_domain_url(object.account, "tagged/#{object.tag.to_param}")
|
||||
end
|
||||
|
||||
def name
|
||||
|
|
|
@ -37,6 +37,8 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService
|
|||
end
|
||||
|
||||
def process_items(items)
|
||||
return if items.nil?
|
||||
|
||||
process_note_items(items) if @options[:note]
|
||||
process_hashtag_items(items) if @options[:hashtag]
|
||||
end
|
||||
|
|
|
@ -71,7 +71,7 @@ class FollowService < BaseService
|
|||
if @target_account.local?
|
||||
LocalNotificationWorker.perform_async(@target_account.id, follow_request.id, follow_request.class.name, 'follow_request')
|
||||
elsif @target_account.activitypub?
|
||||
ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), @source_account.id, @target_account.inbox_url)
|
||||
ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), @source_account.id, @target_account.inbox_url, { 'bypass_availability' => true })
|
||||
end
|
||||
|
||||
follow_request
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
inherit_from: ../../.rubocop.yml
|
||||
|
||||
# Disable for the `Rubocop` lints in haml-lint
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: false
|
|
@ -1,5 +1,5 @@
|
|||
- content_for :page_title do
|
||||
= "#{display_name(@account)} (#{acct(@account)})"
|
||||
#{display_name(@account)} (#{acct(@account)})
|
||||
|
||||
- content_for :header_tags do
|
||||
- if @account.user_prefers_noindex?
|
||||
|
|
|
@ -30,6 +30,6 @@
|
|||
\-
|
||||
%br/
|
||||
%samp.ellipsized-ip= relevant_account_ip(account, params[:ip])
|
||||
- if !account.suspended? && account.user_pending? && account.user&.invite_request&.text&.present?
|
||||
- if !account.suspended? && account.user_pending? && account.user&.invite_request&.text.present?
|
||||
.batch-table__row__content__quote
|
||||
%p= account.user&.invite_request&.text
|
||||
|
|
|
@ -22,9 +22,10 @@
|
|||
|
||||
.fields-group
|
||||
- %i(username by_domain display_name email ip).each do |key|
|
||||
- unless key == :by_domain && params[:origin] != 'remote'
|
||||
.input.string.optional
|
||||
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.accounts.#{key}")
|
||||
- next if key == :by_domain && params[:origin] != 'remote'
|
||||
|
||||
.input.string.optional
|
||||
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.accounts.#{key}")
|
||||
|
||||
.actions
|
||||
%button.button= t('admin.accounts.search')
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
|
||||
%hr.spacer/
|
||||
|
||||
- if @account.user&.invite_request&.text&.present?
|
||||
- if @account.user&.invite_request&.text.present?
|
||||
.speech-bubble
|
||||
.speech-bubble__bubble
|
||||
= @account.user&.invite_request&.text
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
= custom_emoji_tag(custom_emoji)
|
||||
|
||||
.batch-table__row__content__text
|
||||
%samp= ":#{custom_emoji.shortcode}:"
|
||||
%samp :#{custom_emoji.shortcode}:
|
||||
|
||||
- if custom_emoji.local?
|
||||
%span.information-badge= custom_emoji.category&.name || t('admin.custom_emojis.uncategorized')
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
= t('.title', domain: Addressable::IDNA.to_unicode(@domain_block.domain))
|
||||
|
||||
= simple_form_for @domain_block, url: admin_domain_blocks_path, method: :post do |f|
|
||||
|
||||
%p.hint= t('.preamble_html', domain: Addressable::IDNA.to_unicode(@domain_block.domain))
|
||||
%ul.hint
|
||||
%li= t('.stop_communication')
|
||||
|
|
|
@ -5,16 +5,16 @@
|
|||
- if relay.accepted?
|
||||
%span.positive-hint
|
||||
= fa_icon('check')
|
||||
= ' '
|
||||
|
||||
= t 'admin.relays.enabled'
|
||||
- elsif relay.pending?
|
||||
= fa_icon('hourglass')
|
||||
= ' '
|
||||
|
||||
= t 'admin.relays.pending'
|
||||
- else
|
||||
%span.negative-hint
|
||||
= fa_icon('times')
|
||||
= ' '
|
||||
|
||||
= t 'admin.relays.disabled'
|
||||
%td
|
||||
- if relay.accepted?
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.announcements-list__item
|
||||
= link_to edit_admin_rule_path(rule), class: 'announcements-list__item__title' do
|
||||
= "#{rule_counter + 1}."
|
||||
#{rule_counter + 1}.
|
||||
= truncate(rule.text)
|
||||
|
||||
.announcements-list__item__action-bar
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
%td= update.version
|
||||
%td= t("admin.software_updates.types.#{update.type}")
|
||||
- if update.urgent?
|
||||
%td.critical= t("admin.software_updates.critical_update")
|
||||
%td.critical= t('admin.software_updates.critical_update')
|
||||
- else
|
||||
%td
|
||||
%td= table_link_to 'link', t('admin.software_updates.release_notes'), update.release_notes
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- content_for :page_title do
|
||||
= t('admin.statuses.title')
|
||||
\-
|
||||
= "@#{@account.pretty_acct}"
|
||||
@#{@account.pretty_acct}
|
||||
|
||||
.filters
|
||||
.filter-subset
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
%span= t('admin.trends.tags.not_trendable')
|
||||
= fa_icon 'lock fw'
|
||||
|
||||
|
||||
= link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.listable? ? 'positive' : 'negative'] do
|
||||
- if @tag.listable?
|
||||
%span= t('admin.trends.tags.listable')
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
%br/
|
||||
|
||||
= link_to tag_path(tag), target: '_blank' do
|
||||
= link_to tag_path(tag), target: '_blank', rel: 'noopener noreferrer' do
|
||||
= t('admin.trends.tags.used_by_over_week', count: tag.history.reduce(0) { |sum, day| sum + day.accounts })
|
||||
|
||||
- if tag.trendable? && (rank = Trends.tags.rank(tag.id))
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
- content_for :page_title do
|
||||
= t('auth.resend_confirmation')
|
||||
|
||||
= simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
|
||||
= render 'shared/error_messages', object: resource
|
||||
- if resource.errors.of_kind?(:email, :already_confirmed)
|
||||
.simple_form
|
||||
= render 'auth/shared/progress', stage: resource.approved? ? 'completed' : 'confirmed'
|
||||
|
||||
.fields-group
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, readonly: current_user.present?, hint: current_user.present? && t('auth.confirmations.wrong_email_hint')
|
||||
- if resource.approved?
|
||||
%h1.title= t('auth.confirmations.welcome_title', name: resource.account.username)
|
||||
%p.lead= t('auth.confirmations.registration_complete', domain: site_hostname)
|
||||
- if resource.created_by_application && redirect_to_app?
|
||||
- app = resource.created_by_application
|
||||
%p.lead= t('auth.confirmations.redirect_to_app_html', app_name: app.name, clicking_this_link: link_to(t('auth.confirmations.clicking_this_link'), app.confirmation_redirect_uri))
|
||||
- else
|
||||
%p.lead= t('auth.confirmations.proceed_to_login_html', login_link: link_to_login(t('auth.confirmations.login_link')))
|
||||
- else
|
||||
%h1.title= t('auth.confirmations.awaiting_review_title')
|
||||
%p.lead= t('auth.confirmations.awaiting_review', domain: site_hostname)
|
||||
- else
|
||||
= simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
|
||||
= render 'shared/error_messages', object: resource
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.resend_confirmation'), type: :submit
|
||||
.fields-group
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, readonly: current_user.present?, hint: current_user.present? && t('auth.confirmations.wrong_email_hint')
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.resend_confirmation'), type: :submit
|
||||
|
||||
.form-footer= render 'auth/shared/links'
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
%td
|
||||
%span{ title: session.user_agent }<
|
||||
= fa_icon "#{session_device_icon(session)} fw", 'aria-label': session_device_icon(session)
|
||||
= ' '
|
||||
|
||||
= t 'sessions.description', browser: t("sessions.browsers.#{session.browser}", default: session.browser.to_s), platform: t("sessions.platforms.#{session.platform}", default: session.platform.to_s)
|
||||
%td
|
||||
%samp= session.ip
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
= f.simple_fields_for :invite_request, resource.invite_request || resource.build_invite_request do |invite_request_fields|
|
||||
= invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text, label: false, hint: false
|
||||
|
||||
|
||||
= hidden_field_tag :accept, params[:accept]
|
||||
= f.input :invite_code, as: :hidden
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
- progress_index = { rules: 0, details: 1, confirm: 2 }[stage.to_sym]
|
||||
- progress_index = { rules: 0, details: 1, confirm: 2, confirmed: 3, completed: 4 }[stage.to_sym]
|
||||
|
||||
%ol.progress-tracker
|
||||
%li{ class: progress_index.positive? ? 'completed' : 'active' }
|
||||
|
@ -20,6 +20,8 @@
|
|||
.label= t('auth.progress.confirm')
|
||||
- if approved_registrations?
|
||||
%li.separator{ class: progress_index > 2 ? 'completed' : nil }
|
||||
%li
|
||||
%li{ class: [progress_index > 3 && 'completed', progress_index == 3 && 'active'] }
|
||||
.circle
|
||||
- if progress_index > 3
|
||||
= check_icon
|
||||
.label= t('auth.progress.review')
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
%p.hint
|
||||
%span.positive-hint
|
||||
= fa_icon 'check'
|
||||
= ' '
|
||||
|
||||
= t 'disputes.strikes.appeal_approved'
|
||||
- elsif @appeal.persisted? && @appeal.rejected?
|
||||
%p.hint
|
||||
%span.negative-hint
|
||||
= fa_icon 'times'
|
||||
= ' '
|
||||
|
||||
= t 'disputes.strikes.appeal_rejected'
|
||||
|
||||
.report-header
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
!!!
|
||||
%html{ lang: I18n.locale }
|
||||
%head
|
||||
%meta{ content: 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type' }/
|
||||
%meta{ 'content' => 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type' }/
|
||||
%meta{ charset: 'utf-8' }/
|
||||
%title= safe_join([yield(:page_title), Setting.default_settings['site_title']], ' - ')
|
||||
%meta{ content: 'width=device-width,initial-scale=1', name: 'viewport' }/
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
= image_tag full_asset_url(status.account.avatar.url), alt: ''
|
||||
%td{ align: 'left' }
|
||||
%bdi= display_name(status.account)
|
||||
= "@#{status.account.pretty_acct}"
|
||||
@#{status.account.pretty_acct}
|
||||
|
||||
- if status.spoiler_text?
|
||||
.auto-dir
|
||||
|
|
|
@ -24,14 +24,14 @@
|
|||
%th= t('admin.accounts.followers')
|
||||
%td= number_with_delimiter @export.total_followers
|
||||
%td
|
||||
%tr
|
||||
%th= t('exports.blocks')
|
||||
%td= number_with_delimiter @export.total_blocks
|
||||
%td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv)
|
||||
%tr
|
||||
%th= t('exports.mutes')
|
||||
%td= number_with_delimiter @export.total_mutes
|
||||
%td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv)
|
||||
%tr
|
||||
%th= t('exports.blocks')
|
||||
%td= number_with_delimiter @export.total_blocks
|
||||
%td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv)
|
||||
%tr
|
||||
%th= t('exports.domain_blocks')
|
||||
%td= number_with_delimiter @export.total_domain_blocks
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
%p.hint
|
||||
%span.positive-hint
|
||||
= fa_icon 'check'
|
||||
= ' '
|
||||
|
||||
= t 'two_factor_authentication.enabled'
|
||||
|
||||
.table-wrapper
|
||||
|
|
|
@ -62,18 +62,18 @@
|
|||
- else
|
||||
= fa_icon('reply-all')
|
||||
%span.detailed-status__reblogs>= friendly_number_to_human status.replies_count
|
||||
= ' '
|
||||
|
||||
·
|
||||
- if status.public_visibility? || status.unlisted_visibility?
|
||||
%span.detailed-status__link
|
||||
= fa_icon('retweet')
|
||||
%span.detailed-status__reblogs>= friendly_number_to_human status.reblogs_count
|
||||
= ' '
|
||||
|
||||
·
|
||||
%span.detailed-status__link
|
||||
= fa_icon('star')
|
||||
%span.detailed-status__favorites>= friendly_number_to_human status.favourites_count
|
||||
= ' '
|
||||
|
||||
|
||||
- if user_signed_in?
|
||||
·
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
- percent = total_votes_count.positive? ? 100 * option.votes_count / total_votes_count : 0
|
||||
%label.poll__option><
|
||||
%span.poll__number><
|
||||
= "#{percent.round}%"
|
||||
#{percent.round}%
|
||||
%span.poll__option__text
|
||||
= prerender_custom_emojis(h(option.title), status.emojis)
|
||||
- if own_votes.include?(index)
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
%span.display-name
|
||||
%bdi
|
||||
%strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: prefers_autoplay?)
|
||||
= ' '
|
||||
|
||||
%span.display-name__account
|
||||
= acct(status.account)
|
||||
= fa_icon('lock') if status.account.locked?
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
= button_tag t('generic.save_changes'), class: 'button', form: 'edit_policy'
|
||||
|
||||
= simple_form_for @policy, url: statuses_cleanup_path, method: :put, html: { id: 'edit_policy' } do |f|
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :enabled, as: :boolean, wrapper: :with_label, label: t('statuses_cleanup.enabled'), hint: t('statuses_cleanup.enabled_hint')
|
||||
|
|
|
@ -41,10 +41,10 @@
|
|||
%tr
|
||||
%td.column-cell.text-center
|
||||
%p
|
||||
%strong= "#{t('sessions.ip')}:"
|
||||
%strong #{t('sessions.ip')}:
|
||||
= @remote_ip
|
||||
%br/
|
||||
%strong= "#{t('sessions.browser')}:"
|
||||
%strong #{t('sessions.browser')}:
|
||||
%span{ title: @user_agent }= t 'sessions.description', browser: t("sessions.browsers.#{@detection.id}", default: @detection.id.to_s), platform: t("sessions.platforms.#{@detection.platform.id}", default: @detection.platform.id.to_s)
|
||||
%br/
|
||||
= l(@timestamp.in_time_zone(@resource.time_zone.presence), format: :with_time_zone)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
= image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''
|
||||
|
||||
%h1= t 'devise.mailer.webauthn_credential.added.title'
|
||||
%p.lead= "#{t('devise.mailer.webauthn_credential.added.explanation')}:"
|
||||
%p.lead #{t('devise.mailer.webauthn_credential.added.explanation')}:
|
||||
%p.lead= @webauthn_credential.nickname
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
= image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''
|
||||
|
||||
%h1= t 'devise.mailer.webauthn_credential.deleted.title'
|
||||
%p.lead= "#{t('devise.mailer.webauthn_credential.deleted.explanation')}:"
|
||||
%p.lead #{t('devise.mailer.webauthn_credential.deleted.explanation')}:
|
||||
%p.lead= @webauthn_credential.nickname
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
%table.input{ align: 'center', cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
%tr
|
||||
%td= "@#{@resource.account.username}@#{@instance}"
|
||||
%td @#{@resource.account.username}@#{@instance}
|
||||
.col-3
|
||||
%table.column{ cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
|
|
|
@ -23,9 +23,10 @@ class ActivityPub::DeliveryWorker
|
|||
HEADERS = { 'Content-Type' => 'application/activity+json' }.freeze
|
||||
|
||||
def perform(json, source_account_id, inbox_url, options = {})
|
||||
return unless DeliveryFailureTracker.available?(inbox_url)
|
||||
|
||||
@options = options.with_indifferent_access
|
||||
|
||||
return unless @options[:bypass_availability] || DeliveryFailureTracker.available?(inbox_url)
|
||||
|
||||
@json = json
|
||||
@source_account = Account.find(source_account_id)
|
||||
@inbox_url = inbox_url
|
||||
|
|
|
@ -71,15 +71,20 @@ module Mastodon
|
|||
# https://github.com/mastodon/mastodon/pull/24241#discussion_r1162890242
|
||||
config.active_support.cache_format_version = 6.1
|
||||
|
||||
config.add_autoload_paths_to_load_path = false
|
||||
# Please, add to the `ignore` list any other `lib` subdirectories that do
|
||||
# not contain `.rb` files, or that should not be reloaded or eager loaded.
|
||||
# Common ones are `templates`, `generators`, or `middleware`, for example.
|
||||
# config.autoload_lib(ignore: %w(assets tasks templates generators))
|
||||
# TODO: We should enable this eventually, but for now there are many things
|
||||
# in the wrong path from the perspective of zeitwerk.
|
||||
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
# Application configuration should go into files in config/initializers
|
||||
# -- all .rb files in that directory are automatically loaded.
|
||||
|
||||
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
||||
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
||||
# config.time_zone = 'Central Time (US & Canada)'
|
||||
# Configuration for the application, engines, and railties goes here.
|
||||
#
|
||||
# These settings can be overridden in specific environments using the files
|
||||
# in config/environments, which are processed later.
|
||||
#
|
||||
# config.time_zone = "Central Time (US & Canada)"
|
||||
# config.eager_load_paths << Rails.root.join("extras")
|
||||
|
||||
# All translations from config/locales/*.rb,yml are auto loaded.
|
||||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
||||
|
@ -201,7 +206,7 @@ module Mastodon
|
|||
# We use our own middleware for this
|
||||
config.public_file_server.enabled = false
|
||||
|
||||
config.middleware.use PublicFileServerMiddleware if Rails.env.development? || Rails.env.test? || ENV['RAILS_SERVE_STATIC_FILES'] == 'true'
|
||||
config.middleware.use PublicFileServerMiddleware if Rails.env.local? || ENV['RAILS_SERVE_STATIC_FILES'] == 'true' # rubocop:disable Rails/UnknownEnv
|
||||
config.middleware.use Rack::Attack
|
||||
config.middleware.use Mastodon::RackMiddleware
|
||||
|
||||
|
|
|
@ -68,6 +68,9 @@ Rails.application.configure do
|
|||
# Highlight code that triggered database queries in logs.
|
||||
config.active_record.verbose_query_logs = true
|
||||
|
||||
# Highlight code that enqueued background job in logs.
|
||||
config.active_job.verbose_enqueue_logs = true
|
||||
|
||||
# Debug mode disables concatenation and preprocessing of assets.
|
||||
config.assets.debug = true
|
||||
|
||||
|
@ -98,6 +101,9 @@ Rails.application.configure do
|
|||
# We provide a default secret for the development environment here.
|
||||
# This value should not be used in production environments!
|
||||
config.x.otp_secret = ENV.fetch('OTP_SECRET', '1fc2b87989afa6351912abeebe31ffc5c476ead9bf8b3d74cbc4a302c7b69a45b40b1bbef3506ddad73e942e15ed5ca4b402bf9a66423626051104f4b5f05109')
|
||||
|
||||
# Raise error when a before_action's only/except options reference missing actions
|
||||
config.action_controller.raise_on_missing_callback_actions = true
|
||||
end
|
||||
|
||||
Redis.raise_deprecations = true
|
||||
|
|
|
@ -6,7 +6,7 @@ Rails.application.configure do
|
|||
# Settings specified here will take precedence over those in config/application.rb.
|
||||
|
||||
# Code is not reloaded between requests.
|
||||
config.cache_classes = true
|
||||
config.enable_reloading = false
|
||||
|
||||
# Eager load code on boot. This eager loads most of Rails and
|
||||
# your application in memory, allowing both threaded web servers
|
||||
|
@ -19,8 +19,8 @@ Rails.application.configure do
|
|||
config.action_controller.perform_caching = true
|
||||
config.action_controller.asset_host = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?
|
||||
|
||||
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
|
||||
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
|
||||
# Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
|
||||
# key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
|
||||
# config.require_master_key = true
|
||||
|
||||
# Compress CSS using a preprocessor.
|
||||
|
@ -48,10 +48,9 @@ Rails.application.configure do
|
|||
}
|
||||
}
|
||||
|
||||
# Include generic and useful information about system operation, but avoid logging too much
|
||||
# information to avoid inadvertent exposure of personally identifiable information (PII).
|
||||
# Use the lowest log level to ensure availability of diagnostic information
|
||||
# when problems arise.
|
||||
# Info include generic and useful information about system operation, but avoids logging too much
|
||||
# information to avoid inadvertent exposure of personally identifiable information (PII). If you
|
||||
# want to log everything, set the level to "debug".
|
||||
config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info').to_sym
|
||||
|
||||
# Prepend all log lines with the following tags.
|
||||
|
@ -72,10 +71,13 @@ Rails.application.configure do
|
|||
|
||||
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
||||
# English when a translation cannot be found).
|
||||
# This setting would typically be `true` to use the `I18n.default_locale`.
|
||||
# Some locales are missing translation entries and would have errors:
|
||||
# https://github.com/mastodon/mastodon/pull/24727
|
||||
config.i18n.fallbacks = [:en]
|
||||
|
||||
# Send deprecation notices to registered listeners.
|
||||
config.active_support.deprecation = :notify
|
||||
# Don't log any deprecations.
|
||||
config.active_support.report_deprecations = false
|
||||
|
||||
# Use default logging formatter so that PID and timestamp are not suppressed.
|
||||
config.log_formatter = ::Logger::Formatter.new
|
||||
|
@ -93,10 +95,10 @@ Rails.application.configure do
|
|||
# require "syslog/logger"
|
||||
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name")
|
||||
|
||||
ActiveSupport::Logger.new(STDOUT).tap do |logger|
|
||||
logger.formatter = config.log_formatter
|
||||
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
||||
end
|
||||
# Log to STDOUT by default
|
||||
config.logger = ActiveSupport::Logger.new(STDOUT)
|
||||
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
|
||||
.then { |logger| ActiveSupport::TaggedLogging.new(logger) }
|
||||
|
||||
# Do not dump schema after migrations.
|
||||
config.active_record.dump_schema_after_migration = false
|
||||
|
@ -156,4 +158,12 @@ Rails.application.configure do
|
|||
}
|
||||
|
||||
config.x.otp_secret = ENV.fetch('OTP_SECRET')
|
||||
|
||||
# Enable DNS rebinding protection and other `Host` header attacks.
|
||||
# config.hosts = [
|
||||
# "example.com", # Allow requests from example.com
|
||||
# /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
|
||||
# ]
|
||||
# Skip DNS rebinding protection for the default health check endpoint.
|
||||
# config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
|
||||
end
|
||||
|
|
|
@ -10,12 +10,13 @@ require 'active_support/core_ext/integer/time'
|
|||
Rails.application.configure do
|
||||
# Settings specified here will take precedence over those in config/application.rb.
|
||||
|
||||
# Turn false under Spring and add config.action_view.cache_template_loading = true.
|
||||
config.cache_classes = true
|
||||
# While tests run files are not watched, reloading is not necessary.
|
||||
config.enable_reloading = false
|
||||
|
||||
# Eager loading loads your whole application. When running a single test locally,
|
||||
# this probably isn't necessary. It's a good idea to do in a continuous integration
|
||||
# system, or in some way before deploying your code.
|
||||
# Eager loading loads your entire application. When running a single test locally,
|
||||
# this is usually not necessary, and can slow down your test suite. However, it's
|
||||
# recommended that you enable it in continuous integration systems to ensure eager
|
||||
# loading is working properly before deploying your code.
|
||||
config.eager_load = ENV['CI'].present?
|
||||
|
||||
config.assets_digest = false
|
||||
|
@ -26,7 +27,7 @@ Rails.application.configure do
|
|||
config.cache_store = :memory_store
|
||||
|
||||
# Raise exceptions instead of rendering exception templates.
|
||||
config.action_dispatch.show_exceptions = false
|
||||
config.action_dispatch.show_exceptions = :rescuable
|
||||
|
||||
# Disable request forgery protection in test environment.
|
||||
config.action_controller.allow_forgery_protection = false
|
||||
|
@ -73,11 +74,14 @@ Rails.application.configure do
|
|||
|
||||
# Annotate rendered view with file names.
|
||||
# config.action_view.annotate_rendered_view_with_filenames = true
|
||||
|
||||
# Raise error when a before_action's only/except options reference missing actions
|
||||
config.action_controller.raise_on_missing_callback_actions = true
|
||||
end
|
||||
|
||||
Paperclip::Attachment.default_options[:path] = Rails.root.join('spec', 'test_files', ':class', ':id_partition', ':style.:extension')
|
||||
|
||||
# set fake_data for pam, don't do real calls, just use fake data
|
||||
# Enable fake_data for PAM
|
||||
if ENV['PAM_ENABLED'] == 'true'
|
||||
Rpam2.fake_data =
|
||||
{
|
||||
|
|
|
@ -64,6 +64,7 @@ ignore_unused:
|
|||
- 'statuses.attached.*'
|
||||
- 'move_handler.carry_{mutes,blocks}_over_text'
|
||||
- 'admin_mailer.*.subject'
|
||||
- 'user_mailer.*.subject'
|
||||
- 'notification_mailer.*'
|
||||
- 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html'
|
||||
- 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html'
|
||||
|
|
|
@ -1,27 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Define an application-wide content security policy
|
||||
# For further information see the following documentation
|
||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
def host_to_url(str)
|
||||
return if str.blank?
|
||||
# Define an application-wide content security policy.
|
||||
# See the Securing Rails Applications Guide for more information:
|
||||
# https://guides.rubyonrails.org/security.html#content-security-policy-header
|
||||
|
||||
uri = Addressable::URI.parse("http#{Rails.configuration.x.use_https ? 's' : ''}://#{str}")
|
||||
uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/')
|
||||
uri.to_s
|
||||
end
|
||||
require_relative '../../app/lib/content_security_policy'
|
||||
|
||||
base_host = Rails.configuration.x.web_domain
|
||||
|
||||
assets_host = Rails.configuration.action_controller.asset_host
|
||||
assets_host ||= host_to_url(base_host)
|
||||
|
||||
media_host = host_to_url(ENV['S3_ALIAS_HOST'])
|
||||
media_host ||= host_to_url(ENV['S3_CLOUDFRONT_HOST'])
|
||||
media_host ||= host_to_url(ENV['AZURE_ALIAS_HOST'])
|
||||
media_host ||= host_to_url(ENV['S3_HOSTNAME']) if ENV['S3_ENABLED'] == 'true'
|
||||
media_host ||= assets_host
|
||||
policy = ContentSecurityPolicy.new
|
||||
assets_host = policy.assets_host
|
||||
media_host = policy.media_host
|
||||
|
||||
def sso_host
|
||||
return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true'
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Avoid CORS issues when API is called from the frontend app.
|
||||
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
|
||||
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin Ajax requests.
|
||||
|
||||
# Read more: https://github.com/cyu/rack-cors
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Configure parameters to be filtered from the log file. Use this to limit dissemination of
|
||||
# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported
|
||||
# notations and behaviors.
|
||||
# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file.
|
||||
# Use this to limit dissemination of sensitive information.
|
||||
# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors.
|
||||
Rails.application.config.filter_parameters += [
|
||||
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
|
||||
]
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
# are locale specific, and you may define rules for as many different
|
||||
# locales as you wish. All of these examples are active by default:
|
||||
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
||||
# inflect.plural /^(ox)$/i, '\1en'
|
||||
# inflect.singular /^(ox)en/i, '\1'
|
||||
# inflect.irregular 'person', 'people'
|
||||
# inflect.plural /^(ox)$/i, "\\1en"
|
||||
# inflect.singular /^(ox)en/i, "\\1"
|
||||
# inflect.irregular "person", "people"
|
||||
# inflect.uncountable %w( fish sheep )
|
||||
# end
|
||||
|
||||
|
@ -32,3 +32,8 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|||
|
||||
inflect.singular 'data', 'data'
|
||||
end
|
||||
|
||||
# These inflection rules are supported but not enabled by default:
|
||||
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
||||
# inflect.acronym "RESTful"
|
||||
# end
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Be sure to restart your server when you modify this file.
|
||||
#
|
||||
# This file eases your Rails 7.1 framework defaults upgrade.
|
||||
#
|
||||
# Uncomment each configuration one by one to switch to the new default.
|
||||
# Once your application is ready to run with all new defaults, you can remove
|
||||
# this file and set the `config.load_defaults` to `7.1`.
|
||||
#
|
||||
# Read the Guide for Upgrading Ruby on Rails for more info on each option.
|
||||
# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
|
||||
|
||||
# No longer add autoloaded paths into `$LOAD_PATH`. This means that you won't be able
|
||||
# to manually require files that are managed by the autoloader, which you shouldn't do anyway.
|
||||
# This will reduce the size of the load path, making `require` faster if you don't use bootsnap, or reduce the size
|
||||
# of the bootsnap cache if you use it.
|
||||
Rails.application.config.add_autoload_paths_to_load_path = false
|
||||
|
||||
# Remove the default X-Download-Options headers since it is used only by Internet Explorer.
|
||||
# If you need to support Internet Explorer, add back `"X-Download-Options" => "noopen"`.
|
||||
# Rails.application.config.action_dispatch.default_headers = {
|
||||
# "X-Frame-Options" => "SAMEORIGIN",
|
||||
# "X-XSS-Protection" => "0",
|
||||
# "X-Content-Type-Options" => "nosniff",
|
||||
# "X-Permitted-Cross-Domain-Policies" => "none",
|
||||
# "Referrer-Policy" => "strict-origin-when-cross-origin"
|
||||
# }
|
||||
|
||||
# Do not treat an `ActionController::Parameters` instance
|
||||
# as equal to an equivalent `Hash` by default.
|
||||
# Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false
|
||||
|
||||
# Active Record Encryption now uses SHA-256 as its hash digest algorithm. Important: If you have
|
||||
# data encrypted with previous Rails versions, there are two scenarios to consider:
|
||||
#
|
||||
# 1. If you have +config.active_support.key_generator_hash_digest_class+ configured as SHA1 (the default
|
||||
# before Rails 7.0), you need to configure SHA-1 for Active Record Encryption too:
|
||||
# Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA1
|
||||
# 2. If you have +config.active_support.key_generator_hash_digest_class+ configured as SHA256 (the new default
|
||||
# in 7.0), then you need to configure SHA-256 for Active Record Encryption:
|
||||
# Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA256
|
||||
#
|
||||
# If you don't currently have data encrypted with Active Record encryption, you can disable this setting to
|
||||
# configure the default behavior starting 7.1+:
|
||||
# Rails.application.config.active_record.encryption.support_sha1_for_non_deterministic_encryption = false
|
||||
|
||||
# No longer run after_commit callbacks on the first of multiple Active Record
|
||||
# instances to save changes to the same database row within a transaction.
|
||||
# Instead, run these callbacks on the instance most likely to have internal
|
||||
# state which matches what was committed to the database, typically the last
|
||||
# instance to save.
|
||||
# Rails.application.config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction = false
|
||||
|
||||
# Configures SQLite with a strict strings mode, which disables double-quoted string literals.
|
||||
#
|
||||
# SQLite has some quirks around double-quoted string literals.
|
||||
# It first tries to consider double-quoted strings as identifier names, but if they don't exist
|
||||
# it then considers them as string literals. Because of this, typos can silently go unnoticed.
|
||||
# For example, it is possible to create an index for a non existing column.
|
||||
# See https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted for more details.
|
||||
# Rails.application.config.active_record.sqlite3_adapter_strict_strings_by_default = true
|
||||
|
||||
# Disable deprecated singular associations names
|
||||
# Rails.application.config.active_record.allow_deprecated_singular_associations_name = false
|
||||
|
||||
# Enable the Active Job `BigDecimal` argument serializer, which guarantees
|
||||
# roundtripping. Without this serializer, some queue adapters may serialize
|
||||
# `BigDecimal` arguments as simple (non-roundtrippable) strings.
|
||||
#
|
||||
# When deploying an application with multiple replicas, old (pre-Rails 7.1)
|
||||
# replicas will not be able to deserialize `BigDecimal` arguments from this
|
||||
# serializer. Therefore, this setting should only be enabled after all replicas
|
||||
# have been successfully upgraded to Rails 7.1.
|
||||
# Rails.application.config.active_job.use_big_decimal_serializer = true
|
||||
|
||||
# Specify if an `ArgumentError` should be raised if `Rails.cache` `fetch` or
|
||||
# `write` are given an invalid `expires_at` or `expires_in` time.
|
||||
# Options are `true`, and `false`. If `false`, the exception will be reported
|
||||
# as `handled` and logged instead.
|
||||
# Rails.application.config.active_support.raise_on_invalid_cache_expiration_time = true
|
||||
|
||||
# Specify whether Query Logs will format tags using the SQLCommenter format
|
||||
# (https://open-telemetry.github.io/opentelemetry-sqlcommenter/), or using the legacy format.
|
||||
# Options are `:legacy` and `:sqlcommenter`.
|
||||
# Rails.application.config.active_record.query_log_tags_format = :sqlcommenter
|
||||
|
||||
# Specify the default serializer used by `MessageEncryptor` and `MessageVerifier`
|
||||
# instances.
|
||||
#
|
||||
# The legacy default is `:marshal`, which is a potential vector for
|
||||
# deserialization attacks in cases where a message signing secret has been
|
||||
# leaked.
|
||||
#
|
||||
# In Rails 7.1, the new default is `:json_allow_marshal` which serializes and
|
||||
# deserializes with `ActiveSupport::JSON`, but can fall back to deserializing
|
||||
# with `Marshal` so that legacy messages can still be read.
|
||||
#
|
||||
# In Rails 7.2, the default will become `:json` which serializes and
|
||||
# deserializes with `ActiveSupport::JSON` only.
|
||||
#
|
||||
# Alternatively, you can choose `:message_pack` or `:message_pack_allow_marshal`,
|
||||
# which serialize with `ActiveSupport::MessagePack`. `ActiveSupport::MessagePack`
|
||||
# can roundtrip some Ruby types that are not supported by JSON, and may provide
|
||||
# improved performance, but it requires the `msgpack` gem.
|
||||
#
|
||||
# For more information, see
|
||||
# https://guides.rubyonrails.org/v7.1/configuring.html#config-active-support-message-serializer
|
||||
#
|
||||
# If you are performing a rolling deploy of a Rails 7.1 upgrade, wherein servers
|
||||
# that have not yet been upgraded must be able to read messages from upgraded
|
||||
# servers, first deploy without changing the serializer, then set the serializer
|
||||
# in a subsequent deploy.
|
||||
# Rails.application.config.active_support.message_serializer = :json_allow_marshal
|
||||
|
||||
# Enable a performance optimization that serializes message data and metadata
|
||||
# together. This changes the message format, so messages serialized this way
|
||||
# cannot be read by older versions of Rails. However, messages that use the old
|
||||
# format can still be read, regardless of whether this optimization is enabled.
|
||||
#
|
||||
# To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have
|
||||
# not yet been upgraded must be able to read messages from upgraded servers,
|
||||
# leave this optimization off on the first deploy, then enable it on a
|
||||
# subsequent deploy.
|
||||
# Rails.application.config.active_support.use_message_serializer_for_metadata = true
|
||||
|
||||
# Set the maximum size for Rails log files.
|
||||
#
|
||||
# `config.load_defaults 7.1` does not set this value for environments other than
|
||||
# development and test.
|
||||
#
|
||||
# if Rails.env.local?
|
||||
# Rails.application.config.log_file_size = 100 * 1024 * 1024
|
||||
# end
|
||||
|
||||
# Enable raising on assignment to attr_readonly attributes. The previous
|
||||
# behavior would allow assignment but silently not persist changes to the
|
||||
# database.
|
||||
# Rails.application.config.active_record.raise_on_assign_to_attr_readonly = true
|
||||
|
||||
# Enable validating only parent-related columns for presence when the parent is mandatory.
|
||||
# The previous behavior was to validate the presence of the parent record, which performed an extra query
|
||||
# to get the parent every time the child record was updated, even when parent has not changed.
|
||||
# Rails.application.config.active_record.belongs_to_required_validates_foreign_key = false
|
||||
|
||||
# Enable precompilation of `config.filter_parameters`. Precompilation can
|
||||
# improve filtering performance, depending on the quantity and types of filters.
|
||||
# Rails.application.config.precompile_filter_parameters = true
|
||||
|
||||
# Enable before_committed! callbacks on all enrolled records in a transaction.
|
||||
# The previous behavior was to only run the callbacks on the first copy of a record
|
||||
# if there were multiple copies of the same record enrolled in the transaction.
|
||||
# Rails.application.config.active_record.before_committed_on_all_records = true
|
||||
|
||||
# Disable automatic column serialization into YAML.
|
||||
# To keep the historic behavior, you can set it to `YAML`, however it is
|
||||
# recommended to explicitly define the serialization method for each column
|
||||
# rather than to rely on a global default.
|
||||
# Rails.application.config.active_record.default_column_serializer = nil
|
||||
|
||||
# Enable a performance optimization that serializes Active Record models
|
||||
# in a faster and more compact way.
|
||||
#
|
||||
# To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have
|
||||
# not yet been upgraded must be able to read caches from upgraded servers,
|
||||
# leave this optimization off on the first deploy, then enable it on a
|
||||
# subsequent deploy.
|
||||
# Rails.application.config.active_record.marshalling_format_version = 7.1
|
||||
|
||||
# Run `after_commit` and `after_*_commit` callbacks in the order they are defined in a model.
|
||||
# This matches the behaviour of all other callbacks.
|
||||
# In previous versions of Rails, they ran in the inverse order.
|
||||
# Rails.application.config.active_record.run_after_transaction_callbacks_in_order_defined = true
|
||||
|
||||
# Whether a `transaction` block is committed or rolled back when exited via `return`, `break` or `throw`.
|
||||
#
|
||||
# Rails.application.config.active_record.commit_transaction_on_non_local_return = true
|
||||
|
||||
# Controls when to generate a value for <tt>has_secure_token</tt> declarations.
|
||||
#
|
||||
# Rails.application.config.active_record.generate_secure_token_on = :initialize
|
||||
|
||||
# ** Please read carefully, this must be configured in config/application.rb **
|
||||
# Change the format of the cache entry.
|
||||
# Changing this default means that all new cache entries added to the cache
|
||||
# will have a different format that is not supported by Rails 7.0
|
||||
# applications.
|
||||
# Only change this value after your application is fully deployed to Rails 7.1
|
||||
# and you have no plans to rollback.
|
||||
# When you're ready to change format, add this to `config/application.rb` (NOT
|
||||
# this file):
|
||||
# config.active_support.cache_format_version = 7.1
|
||||
|
||||
# Configure Action View to use HTML5 standards-compliant sanitizers when they are supported on your
|
||||
# platform.
|
||||
#
|
||||
# `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action View to use HTML5-compliant
|
||||
# sanitizers if they are supported, else fall back to HTML4 sanitizers.
|
||||
#
|
||||
# In previous versions of Rails, Action View always used `Rails::HTML4::Sanitizer` as its vendor.
|
||||
#
|
||||
# Rails.application.config.action_view.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor
|
||||
|
||||
# Configure Action Text to use an HTML5 standards-compliant sanitizer when it is supported on your
|
||||
# platform.
|
||||
#
|
||||
# `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action Text to use HTML5-compliant
|
||||
# sanitizers if they are supported, else fall back to HTML4 sanitizers.
|
||||
#
|
||||
# In previous versions of Rails, Action Text always used `Rails::HTML4::Sanitizer` as its vendor.
|
||||
#
|
||||
# Rails.application.config.action_text.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor
|
||||
|
||||
# Configure the log level used by the DebugExceptions middleware when logging
|
||||
# uncaught exceptions during requests
|
||||
# Rails.application.config.action_dispatch.debug_exception_log_level = :error
|
||||
|
||||
# Configure the test helpers in Action View, Action Dispatch, and rails-dom-testing to use HTML5
|
||||
# parsers.
|
||||
#
|
||||
# Nokogiri::HTML5 isn't supported on JRuby, so JRuby applications must set this to :html4.
|
||||
#
|
||||
# In previous versions of Rails, these test helpers always used an HTML4 parser.
|
||||
#
|
||||
# Rails.application.config.dom_testing_default_html_version = :html5
|
|
@ -1,12 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Define an application-wide HTTP permissions policy. For further
|
||||
# information see https://developers.google.com/web/updates/2018/06/feature-policy
|
||||
#
|
||||
# Rails.application.config.permissions_policy do |f|
|
||||
# f.camera :none
|
||||
# f.gyroscope :none
|
||||
# f.microphone :none
|
||||
# f.usb :none
|
||||
# f.fullscreen :self
|
||||
# f.payment :self, "https://secure.example.com"
|
||||
# information see: https://developers.google.com/web/updates/2018/06/feature-policy
|
||||
|
||||
# Rails.application.config.permissions_policy do |policy|
|
||||
# policy.camera :none
|
||||
# policy.gyroscope :none
|
||||
# policy.microphone :none
|
||||
# policy.usb :none
|
||||
# policy.fullscreen :self
|
||||
# policy.payment :self, "https://secure.example.com"
|
||||
# end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
StrongMigrations.start_after = 2017_09_24_022025
|
||||
StrongMigrations.target_version = 10
|
||||
StrongMigrations.target_version = 12
|
||||
|
|
|
@ -9,7 +9,7 @@ he:
|
|||
agreement: הסכם שירות
|
||||
email: כתובת דוא"ל
|
||||
locale: הגדרות אזוריות
|
||||
password: סיסמא
|
||||
password: סיסמה
|
||||
user/account:
|
||||
username: שם משתמש/ת
|
||||
user/invite_request:
|
||||
|
|
|
@ -1174,6 +1174,7 @@ cy:
|
|||
functional: Mae eich cyfrif nawr yn weithredol.
|
||||
pending: Mae'ch cais yn aros i gael ei adolygu gan ein staff. Gall hyn gymryd cryn amser. Byddwch yn derbyn e-bost os caiff eich cais ei gymeradwyo.
|
||||
redirecting_to: Mae eich cyfrif yn anweithredol oherwydd ei fod ar hyn o bryd yn ailgyfeirio i %{acct}.
|
||||
self_destruct: Gab fod parth %{domain} yn cau, dim ond mynediad cyfyngedig fyddwch yn ei gael i'ch cyfrif.
|
||||
view_strikes: Gweld rybuddion y gorffennol yn erbyn eich cyfrif
|
||||
too_fast: Cafodd y ffurflen ei chyflwyno'n rhy gyflym, ceisiwch eto.
|
||||
use_security_key: Defnyddiwch allwedd diogelwch
|
||||
|
@ -1675,6 +1676,9 @@ cy:
|
|||
over_daily_limit: Rydych wedi mynd dros y terfyn o %{limit} postiad a drefnwyd ar gyfer heddiw
|
||||
over_total_limit: Rydych wedi mynd dros y terfyn o %{limit} postiad a drefnwyd
|
||||
too_soon: Rhaid i'r dyddiad a drefnwyd fod yn y dyfodol
|
||||
self_destruct:
|
||||
lead_html: Yn anffodus mae <strong>%{domain}</strong> yn cau'n barhaol. Os oedd gennych gyfrif yno, ni fydd modd i chi barhau i'w ddefnyddio, ond mae dal modd gofyn i gael copi wrth gefn o'ch data.
|
||||
title: Mae'r gweinydd hwn yn cau
|
||||
sessions:
|
||||
activity: Gweithgaredd ddiwethaf
|
||||
browser: Porwr
|
||||
|
|
|
@ -1041,6 +1041,14 @@ da:
|
|||
hint_html: Bare en ting mere! Vi er nødt til at bekræfte, at du er et menneske (dette er for at vi kan holde spam ude!). Løs CAPTCHA'en nedenfor og klik på "Fortsæt".
|
||||
title: Sikkerhedstjek
|
||||
confirmations:
|
||||
awaiting_review: E-mailadressen er bekræftet! %{domain}-personalet gennemgår nu registreringen. En e-mail fremsendes, såfremt din konto godkendes!
|
||||
awaiting_review_title: Registreringen er ved at blive gennemgået
|
||||
clicking_this_link: klikke på dette link
|
||||
login_link: log ind
|
||||
proceed_to_login_html: Der kan nu fortsættes til %{login_link}.
|
||||
redirect_to_app_html: En omdirigering til <strong>%{app_name}</strong>-appen burde være sket. Er det ikke tilfældet, prøv da %{clicking_this_link} eller returnér manuelt til appen.
|
||||
registration_complete: Registreringen på %{domain} er nu fuldført!
|
||||
welcome_title: Velkommen %{name}!
|
||||
wrong_email_hint: Er denne e-mailadresse ikke korrekt, kan den ændres i kontoindstillinger.
|
||||
delete_account: Slet konto
|
||||
delete_account_html: Ønsker du at slette din konto, kan du <a href="%{path}">gøre dette hér</a>. Du vil blive bedt om bekræftelse.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ de:
|
|||
hint_html: Fast geschafft! Wir müssen uns vergewissern, dass du ein Mensch bist (damit wir Spam verhindern können!). Bitte löse das CAPTCHA und klicke auf „Weiter“.
|
||||
title: Sicherheitsüberprüfung
|
||||
confirmations:
|
||||
awaiting_review: Deine E-Mail-Adresse wurde bestätigt und das Team von %{domain} überprüft nun deine Registrierung. Sobald es dein Konto genehmigt, wirst du eine E-Mail erhalten.
|
||||
awaiting_review_title: Deine Registrierung wird überprüft
|
||||
clicking_this_link: Klick auf diesen Link
|
||||
login_link: anmelden
|
||||
proceed_to_login_html: Du kannst dich nun %{login_link}.
|
||||
redirect_to_app_html: Du hättest zur <strong>%{app_name}</strong>-App weitergeleitet werden sollen. Wenn das nicht geschehen ist, versuche es mit einem %{clicking_this_link} oder kehre manuell zur App zurück.
|
||||
registration_complete: Deine Registrierung auf %{domain} ist nun abgeschlossen!
|
||||
welcome_title: Willkommen, %{name}!
|
||||
wrong_email_hint: Sollte diese E-Mail-Adresse nicht korrekt sein, kannst du sie in den Kontoeinstellungen ändern.
|
||||
delete_account: Konto löschen
|
||||
delete_account_html: Falls du dein Konto endgültig löschen möchtest, kannst du das <a href="%{path}">hier vornehmen</a>. Du musst dies zusätzlich bestätigen.
|
||||
|
|
|
@ -8,10 +8,10 @@ he:
|
|||
failure:
|
||||
already_authenticated: חשבון זה כבר מחובר.
|
||||
inactive: חשבון זה טרם הופעל.
|
||||
invalid: "%{authentication_keys} או סיסמא לא נכונים."
|
||||
invalid: "%{authentication_keys} או סיסמה לא נכונים."
|
||||
last_attempt: יש לך עוד ניסיון אחד לפני נעילת החשבון.
|
||||
locked: חשבון זה נעול.
|
||||
not_found_in_database: "%{authentication_keys} או סיסמא לא נכונים."
|
||||
not_found_in_database: "%{authentication_keys} או סיסמה לא נכונים."
|
||||
pending: חשבונך נמצא עדיין בבדיקה.
|
||||
timeout: פג תוקף השהיה בחשבון. נא להכנס מחדש על מנת להמשיך.
|
||||
unauthenticated: יש להרשם או להכנס לחשבון על מנת להמשיך.
|
||||
|
@ -27,24 +27,24 @@ he:
|
|||
title: אימות כתובת דוא״ל
|
||||
email_changed:
|
||||
explanation: 'כתובת הדוא"ל של חשבונך שונתה ל:'
|
||||
extra: אם לא שינית את כתובת הדוא"ל שלך, יכול להיות שמישהו השתלט על חשבונך. נא לשנות את הסיסמא מיידית או ליצור קשר עם מנהלי השרת אם ננעלת מחוץ לחשבון.
|
||||
extra: אם לא שינית את כתובת הדוא"ל שלך, יכול להיות שמישהו השתלט על חשבונך. נא לשנות את הסיסמה שלך מיידית או ליצור קשר עם מנהלי השרת אם ננעלת מחוץ לחשבונך.
|
||||
subject: 'מסטודון: כתובת הדוא"ל שונתה'
|
||||
title: כתובת דוא״ל חדשה
|
||||
password_change:
|
||||
explanation: הסיסמא לחשבונך שונתה.
|
||||
extra: אם לא שינית את סיסמתך, יכול להיות שמישהו השתלט על חשבונך. נא לשנות את הסיסמא מיידית או ליצור קשר עם מנהלי השרת אם ננעלת מחוץ לחשבון.
|
||||
subject: 'מסטודון: הסיסמא שונתה'
|
||||
title: הסיסמא שונתה
|
||||
explanation: הסיסמה לחשבונך שונתה.
|
||||
extra: אם לא שינית את סיסמתך, יכול להיות שמישהו השתלט על חשבונך. נא לשנות את הסיסמה שלך מיידית או ליצור קשר עם מנהלי השרת אם ננעלת מחוץ לחשבונך.
|
||||
subject: 'מסטודון: הסיסמה שונתה'
|
||||
title: הסיסמה שונתה
|
||||
reconfirmation_instructions:
|
||||
explanation: נא לאמת את הכתובת הדוא"ל החדשה על מנת לשנותה.
|
||||
extra: אם שינוי זה לא בוצע על ידך, נא להתעלם מדוא"ל זה. כתובת הדוא"ל של חשבון המסטודון שלך לא תשונה אלא אם תלחץ הקישורית לעיל.
|
||||
subject: 'מסטודון: נא לאשר כתובת דוא"ל עבור %{instance}'
|
||||
title: אימות כתובת דוא״ל
|
||||
reset_password_instructions:
|
||||
action: שינוי סיסמא
|
||||
explanation: ביקשת סיסמא חדשה לחשבון.
|
||||
extra: אם לא ביקשת את זה, נא להתעלם מדוא"ל זה. סיסמתך לא תשתנה עוד שתלחץ הקישורית לעיל ותיוצר סיסמא חדשה.
|
||||
subject: 'מסטודון: הוראות לאיפוס סיסמא'
|
||||
action: שינוי סיסמה
|
||||
explanation: ביקשת סיסמה חדשה לחשבון שלך.
|
||||
extra: אם לא ביקשת זאת, נא להתעלם מדוא"ל זה. סיסמתך לא תשתנה עוד שתלחץ הקישורית לעיל ותיוצר סיסמה חדשה.
|
||||
subject: 'מסטודון: הוראות לאיפוס סיסמה'
|
||||
title: איפוס סיסמה
|
||||
two_factor_disabled:
|
||||
explanation: האימות הדו-גורמי לחשבונך בוטל. ניתן עתה להכנס לחשבון עם כתובת דוא"ל וסיסמא בלבד.
|
||||
|
@ -81,7 +81,7 @@ he:
|
|||
failure: 'לא ניתן לאמת את חשבונך מ־%{kind} מהסיבה: "%{reason}".'
|
||||
success: נכשל אימות מחשבון %{kind}.
|
||||
passwords:
|
||||
no_token: לא ניתן לגשת לעמוד זה, אלא מדוא"ל איפוס סיסמא. אם לא הגעת מדוא"ל איפוס סיסמא, יש לוודא שכתובת הקישורית הוקלדה בשלמותה.
|
||||
no_token: לא ניתן לגשת לעמוד זה, אלא מדוא"ל איפוס סיסמה. אם הגעת מדוא"ל איפוס סיסמה, יש לוודא שכתובת הקישורית הוקלדה בשלמותה.
|
||||
send_instructions: בדקות הקרובות יתקבל דוא"ל עם הוראות לאיפוס סיסמתך. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.
|
||||
send_paranoid_instructions: אם כתובת הדוא"ל שלך קיימת במסד הנתונים, יתקבל בדקות הקרובות דוא"ל עם הוראות לאחזור סיסמא. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.
|
||||
updated: סיסמתך שונתה בהצלחה. הינך כעת במצב מחובר.
|
||||
|
|
|
@ -88,7 +88,7 @@ sr-Latn:
|
|||
updated_not_active: Vaša lozinka nije uspešno promenjena.
|
||||
registrations:
|
||||
destroyed: Ćao! Vaš nalog je uspešno obrisan. Nadamo se da ćete se uskoro vratiti.
|
||||
signed_up: Dobrodošli! Uspešno ste se registrovali.
|
||||
signed_up: Dobro došli! Uspešno ste se registrovali.
|
||||
signed_up_but_inactive: Uspešno ste se registrovali. Nažalost ne možete se prijaviti zato što Vaš nalog još nije aktiviran.
|
||||
signed_up_but_locked: Uspešno ste se registrovali. Nažalost ne možete se prijaviti zato što je Vaš nalog zaključan.
|
||||
signed_up_but_pending: Na vaš imejl poslata je poruka sa vezom za potvrdu. Nakon što kliknete na vezu, pregledaćemo vašu prijavu. Bićete obavešteni ako bude odobreno.
|
||||
|
|
|
@ -88,7 +88,7 @@ sr:
|
|||
updated_not_active: Ваша лозинка није успешно промењена.
|
||||
registrations:
|
||||
destroyed: Ћао! Ваш налог је успешно обрисан. Надамо се да ћете се ускоро вратити.
|
||||
signed_up: Добродошли! Успешно сте се регистровали.
|
||||
signed_up: Добро дошли! Успешно сте се регистровали.
|
||||
signed_up_but_inactive: Успешно сте се регистровали. Нажалост не можете се пријавити зато што Ваш налог још није активиран.
|
||||
signed_up_but_locked: Успешно сте се регистровали. Нажалост не можете се пријавити зато што је Ваш налог закључан.
|
||||
signed_up_but_pending: На ваш имејл послата је порука са везом за потврду. Након што кликнете на везу, прегледаћемо вашу пријаву. Бићете обавештени ако буде одобрено.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ en:
|
|||
hint_html: Just one more thing! We need to confirm you're a human (this is so we can keep the spam out!). Solve the CAPTCHA below and click "Continue".
|
||||
title: Security check
|
||||
confirmations:
|
||||
awaiting_review: Your e-mail address is confirmed! The %{domain} staff is now reviewing your registration. You will receive an e-mail if they approve your account!
|
||||
awaiting_review_title: Your registration is being reviewed
|
||||
clicking_this_link: clicking this link
|
||||
login_link: log in
|
||||
proceed_to_login_html: You can now proceed to %{login_link}.
|
||||
redirect_to_app_html: You should have been redirected to the <strong>%{app_name}</strong> app. If that did not happen, try %{clicking_this_link} or manually return to the app.
|
||||
registration_complete: Your registration on %{domain} is now complete!
|
||||
welcome_title: Welcome, %{name}!
|
||||
wrong_email_hint: If that e-mail address is not correct, you can change it in account settings.
|
||||
delete_account: Delete account
|
||||
delete_account_html: If you wish to delete your account, you can <a href="%{path}">proceed here</a>. You will be asked for confirmation.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ es-AR:
|
|||
hint_html: ¡Sólo una cosa más! Necesitamos confirmar que sos humano (¡esto es para que podamos mantener el spam fuera!). Resuelvé la CAPTCHA abajo y hacé clic en "Continuar".
|
||||
title: Comprobación de seguridad
|
||||
confirmations:
|
||||
awaiting_review: "¡Tu dirección de correo electrónico fue confirmada! El equipo de %{domain} está revisando tu registro. ¡Recibirás un correo electrónico si aprueban tu cuenta!"
|
||||
awaiting_review_title: Tu registro está siendo revisado
|
||||
clicking_this_link: haciendo clic en este enlace
|
||||
login_link: iniciar sesión
|
||||
proceed_to_login_html: Ahora podés %{login_link}.
|
||||
redirect_to_app_html: Deberías haber sido redirigido a la aplicación <strong>%{app_name}</strong>. Si eso no sucedió, probá %{clicking_this_link} o volvé a la aplicación manualmente.
|
||||
registration_complete: "¡Tu registro en %{domain} fue completado!"
|
||||
welcome_title: "¡Te damos la bienvenida, %{name}!"
|
||||
wrong_email_hint: Si esa dirección de correo electrónico no es correcta, podés cambiarla en la configuración de la cuenta.
|
||||
delete_account: Eliminar cuenta
|
||||
delete_account_html: Si querés eliminar tu cuenta, podés <a href="%{path}">seguir por acá</a>. Se te va a pedir una confirmación.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ es-MX:
|
|||
hint_html: ¡Una última cosita! Necesitamos confirmar que eres humano (¡así podemos evitar el spam!). Resuelve este CAPTCHA de debajo y pulsa en "Continuar".
|
||||
title: Comprobación de seguridad
|
||||
confirmations:
|
||||
awaiting_review: "¡Tu dirección de correo electrónico ha sido confirmada! El personal de %{domain} está revisando tu registro. ¡Recibirás un correo electrónico si aprueban tu cuenta!"
|
||||
awaiting_review_title: Su registro está siendo revisado
|
||||
clicking_this_link: presionando este enlace
|
||||
login_link: iniciar sesión
|
||||
proceed_to_login_html: Ahora puedes proceder a %{login_link}.
|
||||
redirect_to_app_html: Deberías haber sido redirigido a la aplicación <strong>%{app_name}</strong>. Si eso no sucedió, prueba %{clicking_this_link} o vuelve a la aplicación manualmente.
|
||||
registration_complete: "¡Tu registro en %{domain} ha sido completado!"
|
||||
welcome_title: "¡Bienvenido, %{name}!"
|
||||
wrong_email_hint: Si esa dirección de correo electrónico no es correcta, puedes cambiarla en la configuración de la cuenta.
|
||||
delete_account: Borrar cuenta
|
||||
delete_account_html: Si desea eliminar su cuenta, puede <a href="%{path}">proceder aquí</a>. Será pedido de una confirmación.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ es:
|
|||
hint_html: ¡Una última cosita! Necesitamos confirmar que eres humano (¡así podemos evitar el spam!). Resuelve este CAPTCHA de debajo y pulsa en "Continuar".
|
||||
title: Comprobación de seguridad
|
||||
confirmations:
|
||||
awaiting_review: "¡Tu dirección de correo electrónico ha sido confirmada! El personal de %{domain} está revisando tu registro. ¡Recibirás un correo electrónico cuando aprueben tu cuenta!"
|
||||
awaiting_review_title: Estamos revisando tu registro
|
||||
clicking_this_link: haciendo clic en este enlace
|
||||
login_link: iniciar sesión
|
||||
proceed_to_login_html: Ahora puedes proceder a %{login_link}.
|
||||
redirect_to_app_html: Serás redirigido a la aplicación <strong>%{app_name}</strong>. Si esto no sucede, prueba %{clicking_this_link} o regresa manualmente a la aplicación.
|
||||
registration_complete: "¡Has completado tu registro en %{domain}!"
|
||||
welcome_title: "¡Bienvenido, %{name}!"
|
||||
wrong_email_hint: Si esa dirección de correo electrónico no es correcta, puedes cambiarla en la configuración de la cuenta.
|
||||
delete_account: Borrar cuenta
|
||||
delete_account_html: Si desea eliminar su cuenta, puede <a href="%{path}">proceder aquí</a>. Será pedido de una confirmación.
|
||||
|
@ -1100,7 +1108,7 @@ es:
|
|||
account_status: Estado de la cuenta
|
||||
confirming: Esperando confirmación de correo electrónico.
|
||||
functional: Tu cuenta está completamente operativa.
|
||||
pending: Su solicitud está pendiente de revisión por nuestros administradores. Eso puede tardar algún tiempo. Usted recibirá un correo electrónico si el solicitud sea aprobada.
|
||||
pending: Tu solicitud está pendiente de revisión por nuestro personal. Eso puede tardar un tiempo. Recibirás un correo electrónico cuando tu solicitud sea aprobada.
|
||||
redirecting_to: Tu cuenta se encuentra inactiva porque está siendo redirigida a %{acct}.
|
||||
self_destruct: Como %{domain} está en proceso de cierre, solo tendrás acceso limitado a tu cuenta.
|
||||
view_strikes: Ver amonestaciones pasadas contra tu cuenta
|
||||
|
@ -1786,7 +1794,7 @@ es:
|
|||
title: Un nuevo inicio de sesión
|
||||
warning:
|
||||
appeal: Enviar una apelación
|
||||
appeal_description: Si crees que esto es un error, puedes enviar una apelación al equipo de %{instance}.
|
||||
appeal_description: Si crees que esto es un error, puedes enviar una apelación al personal de %{instance}.
|
||||
categories:
|
||||
spam: Spam
|
||||
violation: El contenido viola las siguientes directrices de la comunidad
|
||||
|
|
|
@ -534,7 +534,7 @@ fi:
|
|||
total_reported: Niitä koskevat raportit
|
||||
total_storage: Medialiitteet
|
||||
totals_time_period_hint_html: Alla näkyvät yhteenlasketut tiedot sisältävät koko ajan.
|
||||
unknown_instance: Tällä palvelimella ei ole tällä hetkellä tähän verkkotunnukseen liittyviä tietueita.
|
||||
unknown_instance: Tällä palvelimella ei tällä hetkellä ole tähän verkkotunnukseen liittyviä tietueita.
|
||||
invites:
|
||||
deactivate_all: Poista kaikki käytöstä
|
||||
filter:
|
||||
|
@ -1041,6 +1041,14 @@ fi:
|
|||
hint_html: Vielä yksi juttu! Meidän on vahvistettava, että olet ihminen (tämän avulla pidämme roskapostin poissa!). Ratkaise alla oleva CAPTCHA-vahvistus ja paina "Jatka".
|
||||
title: Turvatarkastus
|
||||
confirmations:
|
||||
awaiting_review: Sähköpostiosoitteesi on vahvistettu! Seuraavaksi palvelimen %{domain} ylläpito tarkistaa rekisteröitymisesi ja saat lopuksi ilmoituksen sähköpostitse, jos tilisi hyväksytään!
|
||||
awaiting_review_title: Rekisteröitymisesi on tarkistettavana
|
||||
clicking_this_link: tästä linkistä
|
||||
login_link: kirjautumalla sisään
|
||||
proceed_to_login_html: Voit nyt jatkaa %{login_link}.
|
||||
redirect_to_app_html: Sinun olisi pitänyt ohjautua sovellukseen <strong>%{app_name}</strong>. Jos näin ei tapahtunut, yritä avata se %{clicking_this_link} tai palaa sovellukseen manuaalisesti.
|
||||
registration_complete: Rekisteröitymisesi palvelimelle %{domain} on suoritettu!
|
||||
welcome_title: Tervetuloa, %{name}!
|
||||
wrong_email_hint: Jos sähköpostiosoite ei ole oikein, voit muuttaa sen tilin asetuksista.
|
||||
delete_account: Poista tili
|
||||
delete_account_html: Jos haluat poistaa tilisi, voit <a href="%{path}">edetä tästä</a>. Sinua pyydetään vahvistamaan poisto.
|
||||
|
@ -1100,7 +1108,7 @@ fi:
|
|||
account_status: Tilin tila
|
||||
confirming: Odotetaan sähköpostivahvistuksen valmistumista.
|
||||
functional: Tilisi on täysin toiminnassa.
|
||||
pending: Hakemuksesi odottaa henkilökuntamme tarkastusta. Tämä voi kestää jonkin aikaa. Saat sähköpostiviestin, jos hakemuksesi hyväksytään.
|
||||
pending: Hakemuksesi odottaa palvelimen ylläpidon tarkastusta. Tämä voi kestää jonkin aikaa. Saat sähköpostiviestin, jos hakemuksesi hyväksytään.
|
||||
redirecting_to: Tilisi ei ole aktiivinen, koska se ohjaa tällä hetkellä tilille %{acct}.
|
||||
self_destruct: Koska %{domain} sulkeutuu, voit käyttää tiliäsi vain rajoitetusti.
|
||||
view_strikes: Näytä tiliäsi koskevia aiempia varoituksia
|
||||
|
@ -1163,7 +1171,7 @@ fi:
|
|||
approve_appeal: Hyväksy valitus
|
||||
associated_report: Liittyvä raportti
|
||||
created_at: Päivätty
|
||||
description_html: Nämä ovat tiliäsi koskevia toimia ja varoituksia, jotka instanssin %{instance} henkilökunta on lähettänyt sinulle.
|
||||
description_html: Nämä ovat tiliäsi koskevia toimia ja varoituksia, jotka instanssin %{instance} ylläpito on lähettänyt sinulle.
|
||||
recipient: Osoitettu
|
||||
reject_appeal: Hylkää valitus
|
||||
status: 'Julkaisu #%{id}'
|
||||
|
@ -1786,7 +1794,7 @@ fi:
|
|||
title: Uusi kirjautuminen
|
||||
warning:
|
||||
appeal: Lähetä valitus
|
||||
appeal_description: Jos uskot, että tämä on virhe, voit hakea muutosta instanssin %{instance} henkilökunnalta.
|
||||
appeal_description: Jos uskot, että tämä on virhe, voit hakea muutosta instanssin %{instance} ylläpidolta.
|
||||
categories:
|
||||
spam: Roskaposti
|
||||
violation: Sisältö rikkoo seuraavia yhteisön sääntöjä
|
||||
|
|
|
@ -1041,6 +1041,14 @@ fo:
|
|||
hint_html: Bara eitt afturat! Tað er neyðugt hjá okkum at vátta, at tú ert eitt menniskja (fyri at sleppa undan ruskposti!). Loys CAPTCHA niðanfyri og trýst á "Halt fram".
|
||||
title: Trygdarkanning
|
||||
confirmations:
|
||||
awaiting_review: Teldupostadressan hjá góðkend! Nú kanna %{domain} ábyrgdarfólk skrásetingina hjá tær. Góðkenna tey kontu tína, so senda tey tær eitt teldubræv!
|
||||
awaiting_review_title: Skrásetingin hjá tær verður viðgjørd
|
||||
clicking_this_link: við at klikkja á hetta leinki
|
||||
login_link: rita inn
|
||||
proceed_to_login_html: Nú kanst tú fara víðari til %{login_link}.
|
||||
redirect_to_app_html: Tú skuldi verið send/ur víðari til <strong>%{app_name}</strong> appina. Hendi tað ikki, so kanst tú royna %{clicking_this_link} ella fara manuelt aftur til appina.
|
||||
registration_complete: Skráseting tín á %{domain} er nú avgreidd!
|
||||
welcome_title: Vælkomin, %{name}!
|
||||
wrong_email_hint: Um hesin teldupoststaðurin ikki er rættur, so kanst tú broyta hann í kontustillingunum.
|
||||
delete_account: Strika kontu
|
||||
delete_account_html: Ynskir tú at strika kontuna, so kanst tú <a href="%{path}">halda fram her</a>. Tú verður spurd/ur um váttan.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ fr-QC:
|
|||
hint_html: Juste une autre chose! Nous avons besoin de confirmer que vous êtes un humain (pour que nous puissions empêcher les spams!). Résolvez le CAPTCHA ci-dessous et cliquez sur "Continuer".
|
||||
title: Vérification de sécurité
|
||||
confirmations:
|
||||
awaiting_review: Votre adresse e-mail est confirmée ! L’équipe de %{domain} vérifie désormais votre inscription. Vous recevrez un e-mail si votre compte est approuvé !
|
||||
awaiting_review_title: Votre inscription est en cours de validation
|
||||
clicking_this_link: cliquer sur ce lien
|
||||
login_link: vous connecter
|
||||
proceed_to_login_html: Vous pouvez désormais %{login_link}.
|
||||
redirect_to_app_html: Vous auriez dû être redirigé vers l’application <strong>%{app_name}</strong>. Si cela ne s’est pas produit, essayez de %{clicking_this_link} ou de revenir manuellement à l’application.
|
||||
registration_complete: Votre inscription sur %{domain} est désormais terminée !
|
||||
welcome_title: Bienvenue, %{name} !
|
||||
wrong_email_hint: Si cette adresse de courriel est incorrecte, vous pouvez la modifier dans vos paramètres de compte.
|
||||
delete_account: Supprimer le compte
|
||||
delete_account_html: Si vous désirez supprimer votre compte, vous pouvez <a href="%{path}">cliquer ici</a>. Il vous sera demandé de confirmer cette action.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ fr:
|
|||
hint_html: Encore une chose ! Nous avons besoin de confirmer que vous êtes un humain (c'est pour que nous puissions empêcher les spams !). Résolvez le CAPTCHA ci-dessous et cliquez sur "Continuer".
|
||||
title: Vérification de sécurité
|
||||
confirmations:
|
||||
awaiting_review: Votre adresse e-mail est confirmée ! L’équipe de %{domain} vérifie désormais votre inscription. Vous recevrez un e-mail si votre compte est approuvé !
|
||||
awaiting_review_title: Votre inscription est en cours de validation
|
||||
clicking_this_link: cliquer sur ce lien
|
||||
login_link: vous connecter
|
||||
proceed_to_login_html: Vous pouvez désormais %{login_link}.
|
||||
redirect_to_app_html: Vous auriez dû être redirigé vers l’application <strong>%{app_name}</strong>. Si cela ne s’est pas produit, essayez de %{clicking_this_link} ou de revenir manuellement à l’application.
|
||||
registration_complete: Votre inscription sur %{domain} est désormais terminée !
|
||||
welcome_title: Bienvenue, %{name} !
|
||||
wrong_email_hint: Si cette adresse de courriel est incorrecte, vous pouvez la modifier dans vos paramètres de compte.
|
||||
delete_account: Supprimer le compte
|
||||
delete_account_html: Si vous désirez supprimer votre compte, vous pouvez <a href="%{path}">cliquer ici</a>. Il vous sera demandé de confirmer cette action.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ fy:
|
|||
hint_html: Noch ien ding! Jo moatte befêstigje dat jo in minske binne (dit is om de spam bûten de doar te hâlden!). Los de ûndersteande CAPTCHA op en klik op ‘Trochgean’.
|
||||
title: Befeiligingskontrôle
|
||||
confirmations:
|
||||
awaiting_review: Jo e-mailadres is befêstige! De %{domain}-meiwurkers binne no dwaande mei it besjen fan jo registraasje. Jo ûntfange in e-mailberjocht as de jo account goedkarre!
|
||||
awaiting_review_title: Jo registraasje wurdt beoardield
|
||||
clicking_this_link: klik op dizze keppeling
|
||||
login_link: oanmelde
|
||||
proceed_to_login_html: Jo kinne no fierder gean nei %{login_link}.
|
||||
redirect_to_app_html: Jo soene omlaad wêze moatte nei de <strong>%{app_name}</strong> app. As dat net bard is, probearje dan %{clicking_this_link} of kear hânmjittich werom nei de app.
|
||||
registration_complete: Jo registraasje op %{domain} is no foltôge!
|
||||
welcome_title: Wolkom, %{name}!
|
||||
wrong_email_hint: As it e-mailadres net korrekt is, kinne jo dat wizigje yn de accountynstellingen.
|
||||
delete_account: Account fuortsmite
|
||||
delete_account_html: Wannear’t jo jo account graach fuortsmite wolle, kinne jo dat <a href="%{path}">hjir dwaan</a>. Wy freegje jo dêr om in befêstiging.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ gl:
|
|||
hint_html: Unha cousa máis! Temos que confirmar que es un ser humano (para poder evitar contas de spam!). Resolve o CAPTCHA de aquí embaixo e preme en "Continuar".
|
||||
title: Comprobación de seguridade
|
||||
confirmations:
|
||||
awaiting_review: O teu correo está verificado! A administración de %{domain} está revisando a túa solicitude. Recibirás outro correo se aproban a túa conta!
|
||||
awaiting_review_title: Estamos revisando a solicitude de rexistro
|
||||
clicking_this_link: premendo nesta ligazón
|
||||
login_link: acceder
|
||||
proceed_to_login_html: Xa podes %{login_link}.
|
||||
redirect_to_app_html: Ímoste redirixir á app <strong>%{app_name}</strong>. Se iso non acontece, proba %{clicking_this_link} ou volve ti manualmente á app.
|
||||
registration_complete: Completouse a creación da conta en %{domain}!
|
||||
welcome_title: Benvida, %{name}!
|
||||
wrong_email_hint: Se o enderezo de email non é correcto, podes cambialo nos axustes da conta.
|
||||
delete_account: Eliminar conta
|
||||
delete_account_html: Se queres eliminar a túa conta, podes <a href="%{path}">facelo aquí</a>. Deberás confirmar a acción.
|
||||
|
|
|
@ -1077,6 +1077,14 @@ he:
|
|||
hint_html: עוד דבר אחד, עלינו לאשרר שאת(ה) אנושיים (לצורך סינון ספאם). נא לפתור את הקאפצ'ה להלן וללחוץ "המשך".
|
||||
title: בדיקות אבטחה
|
||||
confirmations:
|
||||
awaiting_review: כתובת הדואל שלך אושרה! צוות %{domain} עכשיו יבדוק את הרשמתך. תשלח אליך הודעת דואל אם הצוות יאשר את החשבון!
|
||||
awaiting_review_title: הרשמתך עוברת בדיקה
|
||||
clicking_this_link: לחיצה על קישור זה
|
||||
login_link: כניסה
|
||||
proceed_to_login_html: ניתן להמשיך עכשיו אל %{login_link}.
|
||||
redirect_to_app_html: כאן אמורה היתה להיות הפניה אוטמטית ליישומון <strong>%{app_name}</strong>. אם זה לא קרה, ניתן לנסות שוב על ידי %{clicking_this_link} או חזרה ידנית אל היישומון.
|
||||
registration_complete: הרשמתך לשרת %{domain} הושלמה כעת!
|
||||
welcome_title: ברוך/ה הבא/ה, %{name}!
|
||||
wrong_email_hint: אם כתובת הדואל הזו איננה נכונה, ניתן לשנות אותה בעמוד ההגדרות.
|
||||
delete_account: מחיקת חשבון
|
||||
delete_account_html: אם ברצונך למחוק את החשבון, ניתן <a href="%{path}">להמשיך כאן</a>. תתבקש/י לספק אישור נוסף.
|
||||
|
@ -1126,7 +1134,7 @@ he:
|
|||
new_confirmation_instructions_sent: אתם עומדים לקבל הודעת דואל חדשה עם קיש/ור אימות בדקות הקרובות!
|
||||
title: בדוק/בדקי את תיבת הדואר הנכנס שלך
|
||||
sign_in:
|
||||
preamble_html: הכנס.י עם שם וסיסמא מאתר <strong>%{domain}</strong>. אם חשבונך מתארח בשרת אחר, לא ניתן להתחבר איתו פה.
|
||||
preamble_html: הכנס.י עם שם וסיסמה מאתר <strong>%{domain}</strong>. אם חשבונך מתארח בשרת אחר, לא ניתן להתחבר איתו פה.
|
||||
title: התחבר אל %{domain}
|
||||
sign_up:
|
||||
manual_review: פתיחת חשבון אצל %{domain} עוברת בדיקה ידנית על ידי הצוות שלנו. כדי לסייע בתהליך הרישום שלכןם, כתבו לנו על עצמכןם ולמה אתןם רוצותים חשבון בשרת %{domain}.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ hu:
|
|||
hint_html: Még egy dolog! Meg kell győződnünk róla, hogy tényleg valós személy vagy (így távol tarthatjuk a spam-et). Oldd meg az alábbi CAPTCHA-t és kattints a "Folytatás"-ra.
|
||||
title: Biztonsági ellenőrzés
|
||||
confirmations:
|
||||
awaiting_review: Az email címed megerősítésre került. %{domain} stábja jelenleg áttekinti a regisztrációdat. Ha jóváhagyásra került a fiókod, egy emailt küldenek majd!
|
||||
awaiting_review_title: A regisztrációd áttekintés alatt áll
|
||||
clicking_this_link: kattintás erre a hivatkozásra
|
||||
login_link: bejelentkezés
|
||||
proceed_to_login_html: 'Most továbbléphetsz: %{login_link}.'
|
||||
redirect_to_app_html: Át kellett volna irányítsunk a <strong>%{app_name}</strong> alkalmazáshoz. Ha ez nem történt meg, próbálkozz a %{clicking_this_link} lehetőséggel vagy térj vissza manuálisan az alkalmazáshoz.
|
||||
registration_complete: A regisztrációd %{domain} domainen befejeződött!
|
||||
welcome_title: Üdvözlet, %{name}!
|
||||
wrong_email_hint: Ha az emailcím nem helyes, a fiókbeállításokban megváltoztathatod.
|
||||
delete_account: Felhasználói fiók törlése
|
||||
delete_account_html: Felhasználói fiókod törléséhez <a href="%{path}">kattints ide</a>. A rendszer újbóli megerősítést fog kérni.
|
||||
|
|
|
@ -1045,6 +1045,14 @@ is:
|
|||
Leystu Turing skynprófið og smelltu á "Áfram".
|
||||
title: Öryggisathugun
|
||||
confirmations:
|
||||
awaiting_review: Tölvupóstfangið þitt er staðfest. Umsjónarfólk %{domain} er núna að yfirfara skráninguna þína. Þú munt fá tölvupóst ef þau samþykkja skráninguna þína!
|
||||
awaiting_review_title: Verið er að yfirfara skráninguna þína
|
||||
clicking_this_link: smella á þennan tengil
|
||||
login_link: skrá þig inn
|
||||
proceed_to_login_html: Þú getur núna farið í að %{login_link}.
|
||||
redirect_to_app_html: Þér ætti að hafa verið endurbeint í <strong>%{app_name}</strong> forritið. Ef það gerðist ekki, skaltu prófa að %{clicking_this_link} eða fara aftur í forritið.
|
||||
registration_complete: Skráning þín á %{domain} er núna tilbúin!
|
||||
welcome_title: Velkomin/n %{name}!
|
||||
wrong_email_hint: Ef það tölvupóstfang er ekki rétt geturðu breytt því í stillingum notandaaðgangsins.
|
||||
delete_account: Eyða notandaaðgangi
|
||||
delete_account_html: Ef þú vilt eyða notandaaðgangnum þínum, þá geturðu <a href="%{path}">farið í það hér</a>. Þú verður beðin/n um staðfestingu.
|
||||
|
|
|
@ -1043,6 +1043,14 @@ it:
|
|||
hint_html: Solamente un'altra cosa! Dobbiamo confermare che tu sia un essere umano (così possiamo tenere fuori lo spam!). Risolvi il CAPTCHA sottostante e fai clic su "Continua".
|
||||
title: Controllo di sicurezza
|
||||
confirmations:
|
||||
awaiting_review: Il tuo indirizzo e-mail è confermato! Lo staff di %{domain} sta esaminando la tua registrazione. Riceverai una e-mail se il tuo account sarà approvato!
|
||||
awaiting_review_title: La tua registrazione è in corso di revisione
|
||||
clicking_this_link: cliccando su questo link
|
||||
login_link: accedi
|
||||
proceed_to_login_html: Ora puoi procedere con il %{login_link}.
|
||||
redirect_to_app_html: Avresti dovuto essere reindirizzato all'app <strong>%{app_name}</strong>. Se ciò non fosse avvenuto, prova %{clicking_this_link} o torna manualmente all'app.
|
||||
registration_complete: La tua registrazione su %{domain} è ora completata!
|
||||
welcome_title: Benvenutə, %{name}!
|
||||
wrong_email_hint: Se l'indirizzo e-mail non è corretto, puoi modificarlo nelle impostazioni dell'account.
|
||||
delete_account: Elimina account
|
||||
delete_account_html: Se desideri cancellare il tuo account, puoi <a href="%{path}">farlo qui</a>. Ti sarà chiesta conferma.
|
||||
|
|
|
@ -1023,6 +1023,14 @@ ja:
|
|||
hint_html: もう一つだけ!あなたが人間であることを確認する必要があります(スパムを防ぐためです!)。 以下のCAPTCHAを解き、「続ける」をクリックします。
|
||||
title: セキュリティチェック
|
||||
confirmations:
|
||||
awaiting_review: メールアドレスは確認済みです。%{domain} のモデレーターによりアカウント登録の審査が完了すると、メールでお知らせします。
|
||||
awaiting_review_title: 登録の審査待ちです
|
||||
clicking_this_link: こちらのリンク
|
||||
login_link: こちらのリンク
|
||||
proceed_to_login_html: "%{login_link}から早速ログインしてみましょう。"
|
||||
redirect_to_app_html: "<strong>%{app_name}</strong>に戻ります。自動で移動しない場合は%{clicking_this_link}を押すか、手動でアプリを切り替えてください。"
|
||||
registration_complete: "%{domain} へのアカウント登録が完了しました。"
|
||||
welcome_title: Mastodonへようこそ、%{name}さん
|
||||
wrong_email_hint: メールアドレスが正しくない場合は、アカウント設定で変更できます。
|
||||
delete_account: アカウントの削除
|
||||
delete_account_html: アカウントを削除したい場合、<a href="%{path}">こちら</a>から手続きが行えます。削除する前に、確認画面があります。
|
||||
|
|
|
@ -1025,6 +1025,14 @@ ko:
|
|||
hint_html: 하나만 더! 당신이 사람인지 확인이 필요합니다 (스팸 계정을 거르기 위해서 필요한 과정입니다). 아래에 있는 CAPTCHA를 풀고 "계속"을 누르세요
|
||||
title: 보안 체크
|
||||
confirmations:
|
||||
awaiting_review: 이메일 주소가 확인되었습니다! 이제 %{domain} 스태프가 가입을 검토할 것입니다. 계정이 승인되면 이메일을 받게 됩니다!
|
||||
awaiting_review_title: 가입 신청을 검토 중입니다
|
||||
clicking_this_link: 이 링크를 클릭
|
||||
login_link: 로그인
|
||||
proceed_to_login_html: 이제 %{login_link} 할 수 있습니다.
|
||||
redirect_to_app_html: 곧 <strong>%{app_name}</strong>으로 리디렉션 됩니다. 안 된다면, %{clicking_this_link}하거나 직접 앱으로 돌아가세요.
|
||||
registration_complete: 지금 막 %{domain} 가입이 완료되었습니다!
|
||||
welcome_title: "%{name} 님 반갑습니다!"
|
||||
wrong_email_hint: 만약 이메일 주소가 올바르지 않다면, 계정 설정에서 수정할 수 있습니다.
|
||||
delete_account: 계정 삭제
|
||||
delete_account_html: 계정을 삭제하고 싶은 경우, <a href="%{path}">여기서</a> 삭제할 수 있습니다. 삭제 전 확인 화면이 표시됩니다.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ nl:
|
|||
hint_html: Nog maar één ding! Je moet bevestigen dat je een mens bent (dit is om de spam buiten de deur te houden!). Los de onderstaande CAPTCHA op en klik op "Doorgaan".
|
||||
title: Veiligheidscontrole
|
||||
confirmations:
|
||||
awaiting_review: Je e-mailadres is bevestigd! De medewerkers van %{domain} zijn nu bezig met het beoordelen van jouw registratie. Je ontvangt een e-mailbericht wanneer ze jouw account goedkeuren!
|
||||
awaiting_review_title: Je registratie wordt beoordeeld
|
||||
clicking_this_link: op deze link te klikken
|
||||
login_link: inloggen
|
||||
proceed_to_login_html: Je kunt nu verder gaan naar %{login_link}.
|
||||
redirect_to_app_html: Je zou omgeleid moeten zijn naar de <strong>%{app_name}</strong> app. Als dat niet is gebeurd, probeer dan %{clicking_this_link} of keer handmatig terug naar de app.
|
||||
registration_complete: Je registratie op %{domain} is nu voltooid!
|
||||
welcome_title: Welkom %{name}!
|
||||
wrong_email_hint: Als dat e-mailadres niet correct is, kun je het wijzigen in je accountinstellingen.
|
||||
delete_account: Account verwijderen
|
||||
delete_account_html: Wanneer je jouw account graag wilt verwijderen, kun je dat <a href="%{path}">hier doen</a>. We vragen jou daar om een bevestiging.
|
||||
|
@ -1573,8 +1581,8 @@ nl:
|
|||
over_total_limit: Je hebt de limiet van %{limit} in te plannen berichten overschreden
|
||||
too_soon: De datum voor het ingeplande bericht moet in de toekomst liggen
|
||||
self_destruct:
|
||||
lead_html: Helaas gaat <strong>%{domain}</strong> permanent afsluiten. Als u daar een account had, kunt u deze niet meer gebruiken, maar u kunt nog steeds een back-up van uw gegevens opvragen.
|
||||
title: Deze server gaat afsluiten
|
||||
lead_html: Helaas gaat <strong>%{domain}</strong> permanent sluiten. Als je daar een account had, kun je deze niet meer gebruiken, maar je kunt nog steeds een back-up van je gegevens opvragen.
|
||||
title: Deze server gaat sluiten
|
||||
sessions:
|
||||
activity: Laatst actief
|
||||
browser: Webbrowser
|
||||
|
|
|
@ -1077,6 +1077,14 @@ pl:
|
|||
hint_html: Jeszcze jedno! Potrzebujemy potwierdzić twoje człowieczeństwo, żeby ograniczyć spam. Rozwiąż poniższą CAPTCHA-ę i naciśnij "Kontynuuj".
|
||||
title: Kontrola bezpieczeństwa
|
||||
confirmations:
|
||||
awaiting_review: Twój adres e-mail został potwierdzony! Administracja %{domain} sprawdza Twoją rejestrację. Otrzymasz e-mail w momencie, gdy zaakceptują Twoje konto!
|
||||
awaiting_review_title: Twoja rejestracja jest obecnie sprawdzana
|
||||
clicking_this_link: kliknąć ten link
|
||||
login_link: zaloguj się
|
||||
proceed_to_login_html: Teraz możesz przejść do %{login_link}.
|
||||
redirect_to_app_html: Powinieneś zostać przekierowany do aplikacji <strong>%{app_name}</strong>. Jeśli tak się nie stało, spróbuj %{clicking_this_link} lub ręcznie wróć do aplikacji.
|
||||
registration_complete: Twoja rejestracja na %{domain} została zakończona!
|
||||
welcome_title: Witaj, %{name}!
|
||||
wrong_email_hint: Jeśli ten adres e-mail nie jest poprawny, możesz go zmienić w ustawieniach konta.
|
||||
delete_account: Usunięcie konta
|
||||
delete_account_html: Jeżeli chcesz usunąć konto, <a href="%{path}">przejdź tutaj</a>. Otrzymasz prośbę o potwierdzenie.
|
||||
|
|
|
@ -1040,6 +1040,8 @@ pt-BR:
|
|||
hint_html: Só mais uma coisa! Precisamos confirmar que você é um humano (isso é para que possamos evitar o spam!). Resolva o CAPTCHA abaixo e clique em "Continuar".
|
||||
title: Verificação de segurança
|
||||
confirmations:
|
||||
registration_complete: Seu cadastro no %{domain} foi concluído!
|
||||
welcome_title: Boas vindas, %{name}!
|
||||
wrong_email_hint: Se esse endereço de e-mail não estiver correto, você pode alterá-lo nas configurações da conta.
|
||||
delete_account: Excluir conta
|
||||
delete_account_html: Se você deseja excluir sua conta, você pode <a href="%{path}">fazer isso aqui</a>. Uma confirmação será solicitada.
|
||||
|
|
|
@ -1041,6 +1041,14 @@ pt-PT:
|
|||
hint_html: Só mais uma coisa! Precisamos confirmar que você é um humano (isto para que possamos evitar spam!). Resolva o CAPTCHA abaixo e clique em "Continuar".
|
||||
title: Verificação de segurança
|
||||
confirmations:
|
||||
awaiting_review: O seu endereço de correio eletrónico foi confirmado! A equipa %{domain} está agora a rever a sua inscrição. Receberá uma mensagem de correio eletrónico se aprovarem a sua conta!
|
||||
awaiting_review_title: A sua inscrição está a ser revista
|
||||
clicking_this_link: clicar nesta hiperligação
|
||||
login_link: iniciar sessão
|
||||
proceed_to_login_html: Pode agora prosseguir para %{login_link}.
|
||||
redirect_to_app_html: Devia ter sido reencaminhado para a aplicação <strong>%{app_name}</strong>. Se isso não aconteceu, tente %{clicking_this_link} ou volte manualmente para a aplicação.
|
||||
registration_complete: O seu registo sem %{domain} está agora concluído!
|
||||
welcome_title: Bem-vindo(a), %{name}!
|
||||
wrong_email_hint: Se esse endereço de e-mail não estiver correto, você pode alterá-lo nas configurações da conta.
|
||||
delete_account: Eliminar conta
|
||||
delete_account_html: Se deseja eliminar a sua conta, pode <a href="%{path}">continuar aqui</a>. Uma confirmação será solicitada.
|
||||
|
|
|
@ -556,6 +556,7 @@ ru:
|
|||
total_reported: Жалобы на них
|
||||
total_storage: Медиафайлы
|
||||
totals_time_period_hint_html: Итоги, показанные ниже, включают данные за всё время.
|
||||
unknown_instance: На данный момент нет записей об этом домене на этом сервере.
|
||||
invites:
|
||||
deactivate_all: Отключить все
|
||||
filter:
|
||||
|
@ -1076,6 +1077,12 @@ ru:
|
|||
hint_html: Еще одна вещь! Нам нужно подтвердить, что вы человек (так что мы можем держать спам!). Решите капчу ниже и нажмите кнопку «Продолжить».
|
||||
title: Проверка безопасности
|
||||
confirmations:
|
||||
awaiting_review: Ваш адрес электронной почты подтвержден! Сотрудники %{domain} проверяют вашу регистрацию. Вы получите письмо, если они подтвердят вашу учетную запись!
|
||||
awaiting_review_title: Ваша регистрация проверяется
|
||||
login_link: войти
|
||||
proceed_to_login_html: Теперь вы можете перейти к %{login_link}.
|
||||
registration_complete: Ваша регистрация на %{domain} завершена!
|
||||
welcome_title: Добро пожаловать, %{name}!
|
||||
wrong_email_hint: Если этот адрес электронной почты неверен, вы можете изменить его в настройках аккаунта.
|
||||
delete_account: Удалить учётную запись
|
||||
delete_account_html: Удалить свою учётную запись <a href="%{path}">можно в два счёта здесь</a>, но прежде у вас будет спрошено подтверждение.
|
||||
|
@ -1137,6 +1144,7 @@ ru:
|
|||
functional: Ваша учётная запись в полном порядке.
|
||||
pending: Ваша заявка ожидает одобрения администраторами, это может занять немного времени. Вы получите письмо, как только заявку одобрят.
|
||||
redirecting_to: Ваша учётная запись деактивированна, потому что вы настроили перенаправление на %{acct}.
|
||||
self_destruct: Поскольку %{domain} закрывается, вы получите ограниченный доступ к вашей учетной записи.
|
||||
view_strikes: Просмотр предыдущих замечаний в адрес вашей учетной записи
|
||||
too_fast: Форма отправлена слишком быстро, попробуйте еще раз.
|
||||
use_security_key: Использовать ключ безопасности
|
||||
|
@ -1622,6 +1630,8 @@ ru:
|
|||
over_daily_limit: Вы превысили лимит в %{limit} запланированных постов на указанный день
|
||||
over_total_limit: Вы превысили лимит на %{limit} запланированных постов
|
||||
too_soon: Запланированная дата должна быть в будущем
|
||||
self_destruct:
|
||||
title: Этот сервер закрывается
|
||||
sessions:
|
||||
activity: Последняя активность
|
||||
browser: Браузер
|
||||
|
|
|
@ -180,9 +180,9 @@ he:
|
|||
bot: זהו חשבון מסוג בוט
|
||||
chosen_languages: סינון שפות
|
||||
confirm_new_password: אישור סיסמא חדשה
|
||||
confirm_password: אישור סיסמא
|
||||
confirm_password: אישור סיסמה
|
||||
context: סינון לפי הקשר
|
||||
current_password: סיסמא נוכחית
|
||||
current_password: סיסמה נוכחית
|
||||
data: מידע
|
||||
display_name: שם להצגה
|
||||
email: כתובת דוא"ל
|
||||
|
@ -194,10 +194,10 @@ he:
|
|||
irreversible: הסרה במקום הסתרה
|
||||
locale: שפה
|
||||
max_uses: מספר מרבי של שימושים
|
||||
new_password: סיסמא חדשה
|
||||
new_password: סיסמה חדשה
|
||||
note: אודות
|
||||
otp_attempt: קוד אימות דו-שלבי
|
||||
password: סיסמא
|
||||
password: סיסמה
|
||||
phrase: מילת מפתח או ביטוי
|
||||
setting_advanced_layout: אפשר ממשק ווב מתקדם
|
||||
setting_aggregate_reblogs: קבץ הדהודים זהים
|
||||
|
|
|
@ -125,6 +125,8 @@ sk:
|
|||
removed_header_msg: Úspešne odstránený obrázok hlavičky %{username}
|
||||
resend_confirmation:
|
||||
already_confirmed: Tento užívateľ je už potvrdený
|
||||
send: Odošli potvrdzovací odkaz znovu
|
||||
success: Potvrdzovací email úspešne odoslaný!
|
||||
reset: Resetuj
|
||||
reset_password: Obnov heslo
|
||||
resubscribe: Znovu odoberaj
|
||||
|
@ -1040,6 +1042,7 @@ sk:
|
|||
confirm_remove_selected_followers: Si si istý/á, že chceš odstrániť vybraných sledovateľov?
|
||||
confirm_remove_selected_follows: Si si istý/á, že chceš odstrániť vybraných sledovaných?
|
||||
dormant: Spiace
|
||||
follow_failure: Nemožno nasledovať niektoré z vybraných účtov.
|
||||
follow_selected_followers: Následuj označených sledovatelov
|
||||
followers: Následovatelia
|
||||
following: Následovaní
|
||||
|
|
|
@ -401,9 +401,11 @@ sl:
|
|||
cancel: Prekliči
|
||||
confirm: Suspendiraj
|
||||
permanent_action: Z razveljavitvijo suzpenza ne boste obnovili nobenih podatkov ali razmerij.
|
||||
preamble_html: Suspendirali boste <strong>%{domain}</strong> in njene poddomene.
|
||||
remove_all_data: S tem boste odstranili celotno vsebino, medijske vsebine ter podatke iz profila za rčune te domene na vašem strežniku.
|
||||
stop_communication: Vaš strežnik bo prenehal komunicirati s temi strežniki.
|
||||
title: Potrdi domenski blok za %{domain}
|
||||
undo_relationships: To bo prekinilo vse odnose sledenja med računi na teh strežnikih in na vašem strežniku.
|
||||
created_msg: Domenski blok se sedaj obdeluje
|
||||
destroyed_msg: Domenski blok je bil razveljavljen
|
||||
domain: Domena
|
||||
|
@ -554,6 +556,7 @@ sl:
|
|||
total_reported: Prijave o njih
|
||||
total_storage: Predstavnostne priloge
|
||||
totals_time_period_hint_html: Spodaj prikazani seštevki vključujejo podatke za celotno obdobje.
|
||||
unknown_instance: Trenutno ne obstaja zapis te domene na tem strežniku.
|
||||
invites:
|
||||
deactivate_all: Onemogoči vse
|
||||
filter:
|
||||
|
@ -767,6 +770,9 @@ sl:
|
|||
branding:
|
||||
preamble: Blagovna znamka vašega strežnika ga loči od drugih strežnikov v omrežju. Podatki se lahko prikžejo prek številnih okolij, kot so spletni vmesnik Mastodona, domorodni programi, predogledi povezav na drugih spletiščih, aplikacije za sporočanje itn. Zatorej je najbolje, da te podatke ohranite jasne, kratke in pomenljive.
|
||||
title: Blagovne znamke
|
||||
captcha_enabled:
|
||||
desc_html: To se zanaša na zunanje skripte hCaptcha in lahko predstavlja tveganje za varnost in zasebnost. Poleg tega <strong>to lahko nekaterim ljudem (posebno invalidom) občutno oteži dostopnost registracijskega postopka</strong>. Zato svetujemo, da razmislite o drugih ukrepih, kot je na primer registracija na podlagi odobritve ali povabila.
|
||||
title: Od novih uporabnikov zahtevaj reševanje CAPTCHA za potrditev računov
|
||||
content_retention:
|
||||
preamble: Nazdor nad hrambo vsebine uporabnikov v Mastodonu.
|
||||
title: Hramba vsebin
|
||||
|
@ -795,13 +801,17 @@ sl:
|
|||
none: Nihče se ne more prijaviti
|
||||
open: Vsakdo se lahko prijavi
|
||||
security:
|
||||
authorized_fetch: Od drugih strežnikov v federaciji zahtevaj overitev pristnosti
|
||||
authorized_fetch_hint: Zahtevanje overitve pristnosti od drugih strežnikov v federaciji omogoči strožje uveljavljanje uporabniških in strežniških blokad. Vendar je cena za to počasnejše delovanje, zmanjšanje dosega vaših odgovorov in morebitne težave z združljivostjo z nekaterimi storitvami v federaciji. Poleg tega to odločenim akterjem ne bo preprečilo pridobivanja vaših javnih objav in računov.
|
||||
authorized_fetch_overridden_hint: Trenutno ne morete spremeniti te nastavitve, ker jo preglasi okoljska spremenljivka.
|
||||
federation_authentication: Izvršba overitve pristnosti v federaciji
|
||||
title: Nastavitve strežnika
|
||||
site_uploads:
|
||||
delete: Izbriši naloženo datoteko
|
||||
destroyed_msg: Prenos na strežnik uspešno izbrisan!
|
||||
software_updates:
|
||||
critical_update: Kritično — čim prej posodobite
|
||||
description: Vašo namestitev Mastodona je priporočeno vedno imeti posodobljeno in tako koristiti najnovejše popravke ter zmožnosti. Poleg tega je včasih nujno čim prej posodobiti Mastodon in se s tem izogniti varnostnim težavam. Zato Mastodon vsakih 30 minut preverja razpoložljivost posodobitev in vas o njih obvešča glede na vaše nastavitve obveščanja po e-pošti.
|
||||
documentation_link: Več o tem
|
||||
release_notes: Opombe ob izdaji
|
||||
title: Razpoložljive posodobitve
|
||||
|
@ -851,10 +861,20 @@ sl:
|
|||
system_checks:
|
||||
database_schema_check:
|
||||
message_html: Na čakanju so migracije zbirke podatkov. Prosimo, izvedite jih, da zagotovite, da se program vede pričakovano
|
||||
elasticsearch_health_red:
|
||||
message_html: Z gručo Elasticsearch ni vse v redu (rdeče stanje), zmožnosti iskanja niso na voljo
|
||||
elasticsearch_health_yellow:
|
||||
message_html: Z gručo Elasticsearch ni vse v redu (rumeno stanje), priporočeno je ugotoviti razlog
|
||||
elasticsearch_index_mismatch:
|
||||
message_html: Preslikave kazala Elasticsearch so zastarele. Poženite <code>tootctl search deploy --only=%{value}</code>
|
||||
elasticsearch_preset:
|
||||
action: Glejte dokumentacijo
|
||||
message_html: Vaša gruča Elasticsearch vsebuje več kot eno vozlišče, vendar Mastodon ni nastavljen, da bi jih uporabljal.
|
||||
elasticsearch_preset_single_node:
|
||||
action: Glejte dokumentacijo
|
||||
message_html: Vaša gruča Elasticsearch vsebuje samo eno vozlišče, <code>ES_PRESET</code> bi moralo biti nastavljeno na <code>single_node_cluster</code>.
|
||||
elasticsearch_reset_chewy:
|
||||
message_html: Sistemsko kazalo Elasticsearch je zastarelo zaradi spremembe nastavitve. Za posodobitev poženite <code>tootctl search deploy --reset-chewy</code>.
|
||||
elasticsearch_running_check:
|
||||
message_html: Povezava z Elasticsearch ni uspela. Preverite, da deluje, ali onemogočite iskanje po vsem besedilu
|
||||
elasticsearch_version_check:
|
||||
|
@ -867,6 +887,7 @@ sl:
|
|||
message_html: Noben proces Sidekiq ne poteka za %{value} vrst. Preglejte svojo prilagoditev Sidekiq
|
||||
software_version_critical_check:
|
||||
action: Glejte razpoložljive posodobitve
|
||||
message_html: Na voljo je kritična posodobitev Mastodona. Posodobite čim prej.
|
||||
software_version_patch_check:
|
||||
action: Glejte razpoložljive posodobitve
|
||||
message_html: Na voljo je posodobitev Mastodona s popravki hroščev.
|
||||
|
@ -991,6 +1012,9 @@ sl:
|
|||
body: "%{target} se pritožuje na moderatorsko odločitev %{action_taken_by} z dne %{date}, ki je bila %{type}. Zapisal/a je:"
|
||||
next_steps: Pritožbi lahko ugodite in s tem razveljavite moderatorsko odločitev ali pa jo prezrete.
|
||||
subject: "%{username} se je pritožil na moderatorsko odločitev na %{instance}"
|
||||
new_critical_software_updates:
|
||||
body: Izdane so bile nove kritične različice Mastodona. Priporočena je čimprejšnja posodobitev.
|
||||
subject: Za %{instance} so na voljo kritične posodobitve Mastodona!
|
||||
new_pending_account:
|
||||
body: Podrobnosti o novem računu so navedene spodaj. To aplikacijo lahko odobrite ali zavrnete.
|
||||
subject: Nov račun za pregled na %{instance} (%{username})
|
||||
|
@ -998,6 +1022,9 @@ sl:
|
|||
body: "%{reporter} je prijavil %{target}"
|
||||
body_remote: Nekdo iz %{domain} je prijavil %{target}
|
||||
subject: Nove prijave za %{instance} (#%{id})
|
||||
new_software_updates:
|
||||
body: Izdane so bile nove različice Mastodona. Priporočena je posodobitev.
|
||||
subject: Za %{instance} so na voljo nove različice Mastodona.
|
||||
new_trends:
|
||||
body: 'Naslednji elementi potrebujejo pregled, preden jih je možno javno prikazati:'
|
||||
new_trending_links:
|
||||
|
@ -1046,8 +1073,18 @@ sl:
|
|||
auth:
|
||||
apply_for_account: Zaprosite za račun
|
||||
captcha_confirmation:
|
||||
help_html: Če imate težave pri reševanju CAPTCHA, lahko prek %{email} stopite v stik z nami in pomagali vam bomo.
|
||||
hint_html: Samo še nekaj. Moramo se prepričati, da ste človek (to nam pomaga pri preprečevanju neželenih vsebin). Rešite spodnji CAPTCHA in kliknite »Nadaljuj«.
|
||||
title: Varnostno preverjanje
|
||||
confirmations:
|
||||
awaiting_review: Vaš e-poštni naslov je potrjen. Skrbniki %{domain} bodo pregledali vašo prijavo. Če odobrijo vaš račun, boste o tem prejeli e-pošto.
|
||||
awaiting_review_title: Vaša prijava se pregleduje
|
||||
clicking_this_link: s klikom na to povezavo
|
||||
login_link: prijavo
|
||||
proceed_to_login_html: Sedaj lahko nadaljujete na %{login_link}.
|
||||
redirect_to_app_html: Morali bi biti preusmerjeni na aplikacijo <strong>%{app_name}</strong>. Če se to ni zgodilo, poskusite %{clicking_this_link} ali pa se ročno vrnite na aplikacijo.
|
||||
registration_complete: Vaša prijava na %{domain} je sedaj zaključena.
|
||||
welcome_title: Pozdravljeni, %{name}!
|
||||
wrong_email_hint: Če ta e-poštni naslov ni pravilen, ga lahko spremenite v nastavitvah računa.
|
||||
delete_account: Izbriši račun
|
||||
delete_account_html: Če želite izbrisati svoj račun, lahko nadaljujete <a href="%{path}">tukaj</a>. Prosili vas bomo za potrditev.
|
||||
|
@ -1083,7 +1120,9 @@ sl:
|
|||
rules:
|
||||
accept: Sprejmi
|
||||
back: Nazaj
|
||||
invited_by: "%{domain} se lahko pridružite zahvaljujoč povabilu, ki ste ga prejeli od:"
|
||||
preamble: Slednje določajo in njihovo spoštovanje zagotavljajo moderatorji %{domain}.
|
||||
preamble_invited: Preden nadaljujete, si preberite osnovna pravila, ki so jih postavili moderatorji na %{domain}.
|
||||
title: Nekaj osnovnih pravil.
|
||||
title_invited: Ste povabljeni.
|
||||
security: Varnost
|
||||
|
@ -1107,6 +1146,7 @@ sl:
|
|||
functional: Vaš račun je polno opravilen.
|
||||
pending: Naše osebje preverja vašo prijavo. To lahko traja nekaj časa. Če bo vaša prijava odobrena, boste prejeli e-pošto.
|
||||
redirecting_to: Vaš račun ni dejaven, ker trenutno preusmerja na račun %{acct}.
|
||||
self_destruct: Ker se %{domain} zapira, boste imeli omejen dostop da svojega računa.
|
||||
view_strikes: Pokaži pretekle ukrepe proti mojemu računu
|
||||
too_fast: Obrazec oddan prehitro, poskusite znova.
|
||||
use_security_key: Uporabi varnostni ključ
|
||||
|
@ -1188,6 +1228,7 @@ sl:
|
|||
invalid_domain: ni veljavno ime domene
|
||||
edit_profile:
|
||||
basic_information: Osnovni podatki
|
||||
hint_html: "<strong>Prilagodite, kaj ljudje vidijo na vašem javnem profilu in poleg vaših objav.</strong> Drugi vam bodo raje sledili nazaj in z vami klepetali, če boste imeli izpolnjen profil in nastavljeno profilno sliko."
|
||||
other: Drugo
|
||||
errors:
|
||||
'400': Zahteva, ki ste jo oddali, je neveljavna ali nepravilno oblikovana.
|
||||
|
@ -1322,6 +1363,20 @@ sl:
|
|||
merge_long: Ohrani obstoječe zapise in dodaj nove
|
||||
overwrite: Prepiši
|
||||
overwrite_long: Zamenjaj trenutne zapise z novimi
|
||||
overwrite_preambles:
|
||||
blocking_html: Svoj <strong>seznam blokiranih računov boste nadomestili</strong> z največ <strong>%{total_items} računi</strong> iz <strong>%{filename}</strong>.
|
||||
bookmarks_html: Svoje <strong>zaznamke boste nadomestili</strong> z največ <strong>%{total_items} objavami</strong> iz <strong>%{filename}</strong>.
|
||||
domain_blocking_html: Svoj <strong>seznam blokiranih domen boste nadomestili</strong> z največ <strong>%{total_items} domenami</strong> iz <strong>%{filename}</strong>.
|
||||
following_html: "<strong>Začeli boste slediti</strong> največ <strong>%{total_items} računom</strong> iz <strong>%{filename}</strong> in <strong>prenehali slediti vsem ostalim</strong>."
|
||||
lists_html: Svoje <strong>sezname boste nadomestili</strong> z vsebino datoteke <strong>%{filename}</strong>. Največ <strong>%{total_items} računov</strong> bo dodanih na nove sezname.
|
||||
muting_html: Svoj <strong>seznam utišanih računov boste nadomestili</strong> z največ <strong>%{total_items} računi</strong> iz <strong>%{filename}</strong>.
|
||||
preambles:
|
||||
blocking_html: "<strong>Blokirali boste</strong> največ <strong>%{total_items} računov</strong> iz <strong>%{filename}</strong>."
|
||||
bookmarks_html: "<strong>Med zaznamke</strong> boste dodali boste največ <strong>%{total_items} objav</strong> iz <strong>%{filename}</strong>."
|
||||
domain_blocking_html: "<strong>Blokirali boste</strong> največ <strong>%{total_items} domen</strong> iz <strong>%{filename}</strong>."
|
||||
following_html: "<strong>Začeli boste slediti</strong> največ <strong>%{total_items} računom</strong> iz <strong>%{filename}</strong>."
|
||||
lists_html: Dodali boste največ <strong>%{total_items} računov</strong> iz <strong>%{filename}</strong> na svoje <strong>sezname</strong>. Po potrebi bodo ustvarjeni novi seznami.
|
||||
muting_html: "<strong>Utišali boste</strong> največ <strong>%{total_items} računov</strong> iz <strong>%{filename}</strong>."
|
||||
preface: Podatke, ki ste jih izvozili iz drugega strežnika, lahko uvozite. Na primer seznam oseb, ki jih spremljate ali blokirate.
|
||||
recent_imports: Nedavni uvozi
|
||||
states:
|
||||
|
@ -1393,6 +1448,7 @@ sl:
|
|||
unsubscribe:
|
||||
action: Da, odjavi me
|
||||
complete: Odjavljeni
|
||||
confirmation_html: Ali se res želite odjaviti od prejemanja %{type} za Mastodon na %{domain} na svojo e-pošto %{email}? Kadarkoli se lahko znova prijavite iz svojih <a href="%{settings_path}">nastavitev e-poštnih obvestil</a>.
|
||||
emails:
|
||||
notification_emails:
|
||||
favourite: e-sporočil z obvestili o priljubljenosti
|
||||
|
@ -1400,6 +1456,7 @@ sl:
|
|||
follow_request: e-sporočil o zahtevah za sledenje
|
||||
mention: e-sporočil z obvestili o omembah
|
||||
reblog: e-sporočil z obvestili o izpostavljanju
|
||||
resubscribe_html: Če ste se odjavili po pomoti, se lahko znova prijavite iz svojih <a href="%{settings_path}">nastavitev e-poštnih obvestil</a>.
|
||||
success_html: Nič več ne boste prejemali %{type} za Mastodon na %{domain} na svoj e-naslov %{email}.
|
||||
title: Odjavi od naročnine
|
||||
media_attachments:
|
||||
|
@ -1526,9 +1583,13 @@ sl:
|
|||
posting_defaults: Privzete nastavitev objavljanja
|
||||
public_timelines: Javne časovnice
|
||||
privacy:
|
||||
hint_html: "<strong>Prilagodite, kako lahko drugi najdejo vaš profil in vaše objave.</strong> V Mastodonu obstaja več zmožnosti, ki vam pomagajo doseči širše občinstvo, če so omogočene. Vzemite si čas in preverite, ali te nastavitve ustrezajo vašemu namenu uporabe."
|
||||
privacy: Zasebnost
|
||||
privacy_hint_html: Nadzorujte, koliko informacij želite razkriti drugim. Ljudje lahko zanimive profile in aplikacije odkrijejo z brskanjem po seznamih sledenih in ko vidijo katere programe drugi uporabljajo za objavljanje. Morda pa bi to želeli skriti in varovati zasebnost.
|
||||
reach: Dosegljivost
|
||||
reach_hint_html: Nadzorujte, ali želite, da vas drugi ljudje najdejo in vam pričnejo slediti. Ali želite, da se vaše objave prikažejo na strani Razišči? Ali želite, da vas drugi ljudje vidijo med predlogi za sledenje? Ali želite nove sledilce odobriti samodejno, ali vsakega posebej odobriti ročno?
|
||||
search: Iskanje
|
||||
search_hint_html: Nadzorujte, kako želite, da vas najdejo. Ali želite, da vas ljudje najdejo po javnih objavah? Ali želite, da ljudje, ki niso na Mastodonu, lahko najdejo vaš profil med iskanjem po spletu? Vedite, da javnih objav in podatkov ni mogoče povsem izvzeti iz podatkovnih zbirk vseh spletnih iskalnikov.
|
||||
title: Zasebnost in dosegljivost
|
||||
privacy_policy:
|
||||
title: Pravilnik o zasebnosti
|
||||
|
@ -1571,6 +1632,9 @@ sl:
|
|||
over_daily_limit: Za ta dan ste presegli omejitev %{limit} načrtovanih objav
|
||||
over_total_limit: Presegli ste omejitev %{limit} načrtovanih objav
|
||||
too_soon: Načrtovani datum mora biti v prihodnosti
|
||||
self_destruct:
|
||||
lead_html: Na žalost se <strong>%{domain}</strong> za vedno zapira. Če ste tu imeli svoj račun, ga v prihodnje ne boste mogli več uporabljati. Zahtevate lahko kopijo svojih podatkov.
|
||||
title: Ta strežnik se zapira
|
||||
sessions:
|
||||
activity: Zadnja dejavnost
|
||||
browser: Brskalnik
|
||||
|
@ -1752,6 +1816,10 @@ sl:
|
|||
month: "%b %Y"
|
||||
time: "%H:%M"
|
||||
with_time_zone: "%d. %b. %Y %H:%M %Z"
|
||||
translation:
|
||||
errors:
|
||||
quota_exceeded: Kvota uporabe prevajalne storitve za ta strežnik je bila presežena.
|
||||
too_many_requests: V zadnjem času je prevajalna storitev prejela preveč zahtevkov.
|
||||
two_factor_authentication:
|
||||
add: Dodaj
|
||||
disable: Onemogoči
|
||||
|
@ -1837,7 +1905,9 @@ sl:
|
|||
seamless_external_login: Prijavljeni ste prek zunanje storitve, tako da nastavitve gesla in e-pošte niso na voljo.
|
||||
signed_in_as: 'Vpisani kot:'
|
||||
verification:
|
||||
extra_instructions_html: <strong>Nasvet:</strong> Povezava na vaši spletni strani je lahko nevidna. Pomembni del je atribut <code>rel="me"</code>, ki preprečuje lažno predstavljanje na spletnih straneh z uporabniško ustvarjeno vsebino. Namesto oznake <code>a</code> lahko uporabite tudi oznako <code>link</code> znotraj glave (<code>head</code>) spletne strani, vendar mora biti HTML dosegljiv brez izvajanja skript JavaScript.
|
||||
here_is_how: Kako to poteka
|
||||
hint_html: "<strong>Vsakdo lahko potrdi svojo istovetnost na Mastodonu.</strong> To temelji na odprtih spletnih standardih in je sedaj in za vedno brezplačno. Potrebujete le osebno spletno stran, po kateri vas ljudje prepoznajo. Ko na svoj profil dodate povezavo na to osebno spletno stran, bo Mastodon preveril, ali na njej obstaja povezava nazaj na profil. Če ta obstaja, bo to vidno na profiu."
|
||||
instructions_html: Spodnjo kodo kopirajte in prilepite v HTML svojega spletnega mesta. Nato dodajte naslov svoje spletne strani v eno od dodatnih polj v svojem profilu v zavihku »Uredi profil« in shranite spremembe.
|
||||
verification: Potrditev
|
||||
verified_links: Vaše preverjene povezave
|
||||
|
|
|
@ -1035,6 +1035,14 @@ sq:
|
|||
hint_html: Edhe një gjë tjetër! Na duhet të ripohoni se jeni qenie njerëzore (që të mbajmë larg mesazhe të padëshiruar!). Zgjidhni CAPTCHA-n më poshtë dhe klikoni mbi “Vazhdo”.
|
||||
title: Kontroll sigurie
|
||||
confirmations:
|
||||
awaiting_review: Adresa juaj email u ripohua! Ekipi i %{domain} stani po bën regjistrimin tuaj. Nëse e miratojnë llogarinë tuaj, do të merrni një email!
|
||||
awaiting_review_title: Regjistrimi juaj po merret në shqyrtim
|
||||
clicking_this_link: duke klikuar këtë lidhje
|
||||
login_link: hyni
|
||||
proceed_to_login_html: Tani mund të vazhdoni të %{login_link}.
|
||||
redirect_to_app_html: Duhet të ishit ridrejtuar te aplikacioni <strong>%{app_name}</strong>. Nëse s’ndodhi, provoni %{clicking_this_link}, ose të ktheheni dorazi te aplikacioni.
|
||||
registration_complete: Tanimë është plotësuar regjistrimi juaj në %{domain}!
|
||||
welcome_title: Mirë se vini, %{name}!
|
||||
wrong_email_hint: Nëse ajo adresë email s’është e saktë, mund ta ndryshoni te rregullimet e llogarisë.
|
||||
delete_account: Fshije llogarinë
|
||||
delete_account_html: Nëse dëshironi të fshihni llogarinë tuaj, mund <a href="%{path}">ta bëni që këtu</a>. Do t’ju kërkohet ta ripohoni.
|
||||
|
|
|
@ -1059,6 +1059,14 @@ sr-Latn:
|
|||
hint_html: Samo još jedna stvar! Moramo da potvrdimo da ste ljudsko biće (ovo je da bismo sprečili neželjenu poštu!). Rešite CAPTCHA ispod i kliknite na „Nastavi”.
|
||||
title: Bezbedonosna provera
|
||||
confirmations:
|
||||
awaiting_review: Vaša adresa e-pošte je potvrđena! Osoblje %{domain} sada pregleda vašu registraciju. Dobićete e-poštu ako odobre vaš nalog!
|
||||
awaiting_review_title: Vaša registracija se pregleda
|
||||
clicking_this_link: klikom na ovu vezu
|
||||
login_link: prijavi se
|
||||
proceed_to_login_html: Sada možete da pređete na %{login_link}.
|
||||
redirect_to_app_html: Trebalo je da budete preusmereni na aplikaciju <strong>%{app_name}</strong>. Ako se to nije desilo, pokušajte sa %{clicking_this_link} ili se ručno vratite u aplikaciju.
|
||||
registration_complete: Vaša registracija na %{domain} je sada kompletirana!
|
||||
welcome_title: Dobro došli, %{name}!
|
||||
wrong_email_hint: Ako ta imejl adresa nije ispravna, možete je promeniti u podešavanjima naloga.
|
||||
delete_account: Brisanje naloga
|
||||
delete_account_html: Ako želite da izbrišete vaš nalog, možete <a href="%{path}">nastaviti ovde</a>. Od vas će se tražiti potvrda.
|
||||
|
@ -1855,8 +1863,8 @@ sr-Latn:
|
|||
final_step: 'Počnite da objavljujete! Čak i bez pratilaca, Vaše javne objave su vidljive drugim ljudima, na primer na lokalnoj vremenskoj liniji ili u heš oznakama. Možda želite da se predstavite sa heš oznakom #introductions ili #predstavljanja.'
|
||||
full_handle: Vaš pun nadimak
|
||||
full_handle_hint: Ovo biste rekli svojim prijateljima kako bi vam oni poslali poruku, ili zapratili sa druge instance.
|
||||
subject: Dobrodošli na Mastodon
|
||||
title: Dobrodošli, %{name}!
|
||||
subject: Dobro došli na Mastodon
|
||||
title: Dobro došli, %{name}!
|
||||
users:
|
||||
follow_limit_reached: Ne možete pratiti više od %{limit} ljudi
|
||||
go_to_sso_account_settings: Idite na podešavanja naloga svog dobavljača identiteta
|
||||
|
|
|
@ -1059,6 +1059,14 @@ sr:
|
|||
hint_html: Само још једна ствар! Морамо да потврдимо да сте људско биће (ово је да бисмо спречили нежељену пошту!). Решите CAPTCHA испод и кликните на „Настави”.
|
||||
title: Безбедоносна провера
|
||||
confirmations:
|
||||
awaiting_review: Ваша адреса е-поште је потврђена! Особље %{domain} сада прегледа вашу регистрацију. Добићете е-пошту ако одобре ваш налог!
|
||||
awaiting_review_title: Ваша регистрација се прегледа
|
||||
clicking_this_link: кликом на ову везу
|
||||
login_link: пријави се
|
||||
proceed_to_login_html: Сада можете да пређете на %{login_link}.
|
||||
redirect_to_app_html: Требало је да будете преусмерени на апликацију <strong>%{app_name}</strong>. Ако се то није десило, покушајте са %{clicking_this_link} или се ручно вратите у апликацију.
|
||||
registration_complete: Ваша регистрација на %{domain} је сада комплетирана!
|
||||
welcome_title: Добро дошли, %{name}!
|
||||
wrong_email_hint: Ако та имејл адреса није исправна, можете је променити у подешавањима налога.
|
||||
delete_account: Брисање налога
|
||||
delete_account_html: Ако желите да избришете ваш налог, можете <a href="%{path}">наставити овде</a>. Од вас ће се тражити потврда.
|
||||
|
@ -1855,8 +1863,8 @@ sr:
|
|||
final_step: 'Почните да објављујете! Чак и без пратилаца, Ваше јавне објаве су видљиве другим људима, на пример на локалној временској линији или у хеш ознакама. Можда желите да се представите са хеш ознаком #introductions или #представљања.'
|
||||
full_handle: Ваш пун надимак
|
||||
full_handle_hint: Ово бисте рекли својим пријатељима како би вам они послали поруку, или запратили са друге инстанце.
|
||||
subject: Добродошли на Mastodon
|
||||
title: Добродошли, %{name}!
|
||||
subject: Добро дошли на Mastodon
|
||||
title: Добро дошли, %{name}!
|
||||
users:
|
||||
follow_limit_reached: Не можете пратити више од %{limit} људи
|
||||
go_to_sso_account_settings: Идите на подешавања налога свог добављача идентитета
|
||||
|
|
|
@ -1041,6 +1041,13 @@ sv:
|
|||
hint_html: En sista sak till! Vi måste bekräfta att du är en människa (för att hålla borta skräpinlägg!). Lös CAPTCHA nedan och klicka på "Fortsätt".
|
||||
title: Säkerhetskontroll
|
||||
confirmations:
|
||||
awaiting_review_title: Din registrering är under granskning
|
||||
clicking_this_link: klicka på denna länk
|
||||
login_link: logga in
|
||||
proceed_to_login_html: Du kan nu fortsätta med att %{login_link}.
|
||||
redirect_to_app_html: Du borde ha omdirigerats till appen <strong>%{app_name}</strong>. Om det inte hände, försök att %{clicking_this_link} eller återgå manuellt till appen.
|
||||
registration_complete: Din registrering på %{domain} är nu slutförd!
|
||||
welcome_title: Välkommen %{name}!
|
||||
wrong_email_hint: Om e-postadressen inte är rätt, kan du ändra den i kontoinställningarna.
|
||||
delete_account: Radera konto
|
||||
delete_account_html: Om du vill radera ditt konto kan du <a href="%{path}">fortsätta här</a>. Du kommer att bli ombedd att bekräfta.
|
||||
|
|
|
@ -1023,6 +1023,14 @@ th:
|
|||
hint_html: อีกเพียงหนึ่งสิ่งเพิ่มเติม! เราจำเป็นต้องยืนยันว่าคุณเป็นมนุษย์ (นี่ก็เพื่อให้เราสามารถกันสแปมออกไป!) แก้ CAPTCHA ด้านล่างและคลิก "ดำเนินการต่อ"
|
||||
title: การตรวจสอบความปลอดภัย
|
||||
confirmations:
|
||||
awaiting_review: ยืนยันที่อยู่อีเมลของคุณแล้ว! ตอนนี้พนักงานของ %{domain} กำลังตรวจทานการลงทะเบียนของคุณ คุณจะได้รับอีเมลหากพนักงานอนุมัติบัญชีของคุณ!
|
||||
awaiting_review_title: กำลังตรวจทานการลงทะเบียนของคุณ
|
||||
clicking_this_link: คลิกลิงก์นี้
|
||||
login_link: เข้าสู่ระบบ
|
||||
proceed_to_login_html: ตอนนี้คุณสามารถดำเนินการต่อเพื่อ %{login_link}
|
||||
redirect_to_app_html: คุณควรได้รับการเปลี่ยนเส้นทางไปยังแอป <strong>%{app_name}</strong> หากนั่นไม่เกิดขึ้น ลอง %{clicking_this_link} หรือกลับไปยังแอปด้วยตนเอง
|
||||
registration_complete: ตอนนี้การลงทะเบียนของคุณใน %{domain} เสร็จสมบูรณ์แล้ว!
|
||||
welcome_title: ยินดีต้อนรับ %{name}!
|
||||
wrong_email_hint: หากที่อยู่อีเมลนั้นไม่ถูกต้อง คุณสามารถเปลี่ยนที่อยู่อีเมลได้ในการตั้งค่าบัญชี
|
||||
delete_account: ลบบัญชี
|
||||
delete_account_html: หากคุณต้องการลบบัญชีของคุณ คุณสามารถ <a href="%{path}">ดำเนินการต่อที่นี่</a> คุณจะได้รับการถามเพื่อการยืนยัน
|
||||
|
|
|
@ -1041,6 +1041,14 @@ tr:
|
|||
hint_html: Sadece bir şey daha! Sizin bir insan olduğunuzu doğrulamamız gerekiyor (bu, spam'i dışarıda tutabilmemiz içindir!). Aşağıdaki CAPTCHA'yı çözün ve "Devam Et" düğmesini tıklayın.
|
||||
title: Güvenlik denetimi
|
||||
confirmations:
|
||||
awaiting_review: E-posta adresiniz doğrulandı! %{domain} çalışanları şimdi kaydınızı inceliyorlar. Hesabınızı onayladıklarında bir e-posta alacaksınız!
|
||||
awaiting_review_title: Kaydınız inceleniyor
|
||||
clicking_this_link: bu bağlantıyı tıklamayı
|
||||
login_link: oturum aç
|
||||
proceed_to_login_html: Şimdi %{login_link} devam edebilirsiniz.
|
||||
redirect_to_app_html: "<strong>%{app_name}</strong> uygulamasına yönlendirileceksiniz. Eğer yönlendirme olmazsa, %{clicking_this_link} veya uygulamaya geri dönmeyi deneyin."
|
||||
registration_complete: "%{domain} sunucusunda kaydınız şimdi tamamlandı!"
|
||||
welcome_title: Hoşgeldin %{name}!
|
||||
wrong_email_hint: Eğer bu e-posta adresi doğru değilse, hesap ayarlarında değiştirebilirsiniz.
|
||||
delete_account: Hesabı sil
|
||||
delete_account_html: Hesabını silmek istersen, <a href="%{path}">buradan devam edebilirsin</a>. Onay istenir.
|
||||
|
|
|
@ -1077,6 +1077,14 @@ uk:
|
|||
hint_html: Ще одне! Ми повинні пересвідчитись, що ви людина (щоб ми могли уникнути спаму!). Розв'яжіть CAPTCHA внизу і натисніть кнопку "Продовжити".
|
||||
title: Перевірка безпеки
|
||||
confirmations:
|
||||
awaiting_review: Ваша електронна адреса підтверджена! Співробітники %{domain} тепер переглядають вашу реєстрацію. Ви отримаєте електронного листа, якщо вони затвердять ваш обліковий запис!
|
||||
awaiting_review_title: Ваша реєстрація розглядається
|
||||
clicking_this_link: натисніть це посилання
|
||||
login_link: увійти
|
||||
proceed_to_login_html: Тепер ви можете перейти до %{login_link}.
|
||||
redirect_to_app_html: Ви мали бути перенаправлені до програми <strong>%{app_name}</strong>. Якщо цього не сталося, спробуйте %{clicking_this_link} або вручну поверніться до програми.
|
||||
registration_complete: Ваша реєстрація на %{domain} завершена!
|
||||
welcome_title: Ласкаво просимо, %{name}!
|
||||
wrong_email_hint: Якщо ця адреса електронної пошти неправильна, можна змінити її в налаштуваннях облікового запису.
|
||||
delete_account: Видалити обліковий запис
|
||||
delete_account_html: Якщо ви хочете видалити свій обліковий запис, ви можете <a href="%{path}">перейти сюди</a>. Вас попросять підтвердити дію.
|
||||
|
|
|
@ -1023,6 +1023,14 @@ vi:
|
|||
hint_html: Còn một xíu nữa! Chúng tôi cần xác minh bạn là con người (để chúng tôi có thể ngăn chặn thư rác!). Nhập CAPTCHA bên dưới và nhấn "Tiếp tục".
|
||||
title: Kiểm tra an toàn
|
||||
confirmations:
|
||||
awaiting_review: Đã xác minh email của bạn! Kiểm duyệt viên %{domain} đang xem xét đăng ký của bạn. Bạn sẽ nhận được một email nếu tài khoản của bạn được duyệt!
|
||||
awaiting_review_title: Đăng ký của bạn đang chờ duyệt
|
||||
clicking_this_link: nhấn vào link này
|
||||
login_link: đăng nhập
|
||||
proceed_to_login_html: Bạn có thể tiếp tục %{login_link}.
|
||||
redirect_to_app_html: Bạn đã có thể chuyển tiếp tới <strong>%{app_name}</strong>. Nếu không có gì xảy ra, thử %{clicking_this_link} hoặc tự quay lại app.
|
||||
registration_complete: Hoàn tất đăng ký trên %{domain}!
|
||||
welcome_title: Chào mừng, %{name}!
|
||||
wrong_email_hint: Nếu địa chỉ email đó không chính xác, bạn có thể thay đổi nó trong cài đặt tài khoản.
|
||||
delete_account: Xóa tài khoản
|
||||
delete_account_html: Nếu bạn muốn xóa tài khoản của mình, hãy <a href="%{path}">yêu cầu tại đây</a>. Bạn sẽ được yêu cầu xác nhận.
|
||||
|
|
|
@ -1023,6 +1023,14 @@ zh-CN:
|
|||
hint_html: 只剩最后一件事了!我们需要确认您是一个人类(这样我们才能阻止恶意访问!)。请输入下面的验证码,然后点击“继续”。
|
||||
title: 安全检查
|
||||
confirmations:
|
||||
awaiting_review: 您的电子邮件地址已确认!%{domain} 的工作人员正在审核您的注册信息。如果他们批准了您的账户,您将收到一封邮件通知!
|
||||
awaiting_review_title: 您的注册申请正在审核中
|
||||
clicking_this_link: 点击此链接
|
||||
login_link: 登录
|
||||
proceed_to_login_html: 现在您可以继续前往 %{login_link} 。
|
||||
redirect_to_app_html: 您应该已被重定向到 <strong>%{app_name}</strong> 应用程序。如果没有,请尝试 %{clicking_this_link} 或手动返回应用程序。
|
||||
registration_complete: 您在 %{domain} 上的注册现已完成!
|
||||
welcome_title: 欢迎您,%{name}!
|
||||
wrong_email_hint: 如果该电子邮件地址不正确,您可以在帐户设置中进行更改。
|
||||
delete_account: 删除帐户
|
||||
delete_account_html: 如果你想删除你的帐户,请<a href="%{path}">点击这里继续</a>。你需要确认你的操作。
|
||||
|
|
|
@ -1025,6 +1025,14 @@ zh-TW:
|
|||
hint_html: 僅再一步!我們必須確認您是位人類(這是防止垃圾訊息濫用)。請完成以下 CAPTCHA 挑戰並點擊「繼續」。
|
||||
title: 安全性檢查
|
||||
confirmations:
|
||||
awaiting_review: 已驗證您的電子郵件!%{domain} 的管理員正在審核您的註冊申請。若您的帳號通過審核,您將收到電子郵件通知。
|
||||
awaiting_review_title: 我們正在審核您的註冊申請
|
||||
clicking_this_link: 點擊此連結
|
||||
login_link: 登入
|
||||
proceed_to_login_html: 您現在可以前往 %{login_link}。
|
||||
redirect_to_app_html: 您應被重新導向至 <strong>%{app_name}</strong> 應用程式。如尚未重新導向,請嘗試 %{clicking_this_link} 或手動回到應用程式。
|
||||
registration_complete: 您於 %{domain} 之註冊申請已完成!
|
||||
welcome_title: 歡迎,%{name}!
|
||||
wrong_email_hint: 若電子郵件地址不正確,您可以於帳號設定中更改。
|
||||
delete_account: 刪除帳號
|
||||
delete_account_html: 如果您欲刪除您的帳號,請<a href="%{path}">點擊這裡繼續</a>。您需要再三確認您的操作。
|
||||
|
|
|
@ -134,7 +134,7 @@ Rails.application.routes.draw do
|
|||
get '/@:account_username/:id/embed', to: 'statuses#embed', as: :embed_short_account_status
|
||||
end
|
||||
|
||||
get '/@:username_with_domain/(*any)', to: 'home#index', constraints: { username_with_domain: %r{([^/])+?} }, format: false
|
||||
get '/@:username_with_domain/(*any)', to: 'home#index', constraints: { username_with_domain: %r{([^/])+?} }, as: :account_with_domain, format: false
|
||||
get '/settings', to: redirect('/settings/profile')
|
||||
|
||||
draw(:settings)
|
||||
|
|
|
@ -158,10 +158,8 @@ module Mastodon
|
|||
'in the body of your migration class'
|
||||
end
|
||||
|
||||
if supports_drop_index_concurrently?
|
||||
options = options.merge({ algorithm: :concurrently })
|
||||
disable_statement_timeout
|
||||
end
|
||||
options = options.merge({ algorithm: :concurrently })
|
||||
disable_statement_timeout
|
||||
|
||||
remove_index(table_name, **options.merge({ column: column_name }))
|
||||
end
|
||||
|
@ -182,28 +180,12 @@ module Mastodon
|
|||
'in the body of your migration class'
|
||||
end
|
||||
|
||||
if supports_drop_index_concurrently?
|
||||
options = options.merge({ algorithm: :concurrently })
|
||||
disable_statement_timeout
|
||||
end
|
||||
options = options.merge({ algorithm: :concurrently })
|
||||
disable_statement_timeout
|
||||
|
||||
remove_index(table_name, **options.merge({ name: index_name }))
|
||||
end
|
||||
|
||||
# Only available on Postgresql >= 9.2
|
||||
def supports_drop_index_concurrently?
|
||||
version = select_one("SELECT current_setting('server_version_num') AS v")['v'].to_i
|
||||
|
||||
version >= 90_200
|
||||
end
|
||||
|
||||
# Only available on Postgresql >= 11
|
||||
def supports_add_column_with_default?
|
||||
version = select_one("SELECT current_setting('server_version_num') AS v")['v'].to_i
|
||||
|
||||
version >= 110_000
|
||||
end
|
||||
|
||||
# Adds a foreign key with only minimal locking on the tables involved.
|
||||
#
|
||||
# This method only requires minimal locking when using PostgreSQL. When
|
||||
|
@ -420,42 +402,7 @@ module Mastodon
|
|||
# This method can also take a block which is passed directly to the
|
||||
# `update_column_in_batches` method.
|
||||
def add_column_with_default(table, column, type, default:, limit: nil, allow_null: false, &block)
|
||||
if supports_add_column_with_default?
|
||||
add_column(table, column, type, default: default, limit: limit, null: allow_null)
|
||||
return
|
||||
end
|
||||
|
||||
if transaction_open?
|
||||
raise 'add_column_with_default can not be run inside a transaction, ' \
|
||||
'you can disable transactions by calling disable_ddl_transaction! ' \
|
||||
'in the body of your migration class'
|
||||
end
|
||||
|
||||
disable_statement_timeout
|
||||
|
||||
transaction do
|
||||
if limit
|
||||
add_column(table, column, type, default: nil, limit: limit)
|
||||
else
|
||||
add_column(table, column, type, default: nil)
|
||||
end
|
||||
|
||||
# Changing the default before the update ensures any newly inserted
|
||||
# rows already use the proper default value.
|
||||
change_column_default(table, column, default)
|
||||
end
|
||||
|
||||
begin
|
||||
update_column_in_batches(table, column, default, &block)
|
||||
|
||||
change_column_null(table, column, false) unless allow_null
|
||||
# We want to rescue _all_ exceptions here, even those that don't inherit
|
||||
# from StandardError.
|
||||
rescue Exception => error # rubocop: disable all
|
||||
remove_column(table, column)
|
||||
|
||||
raise error
|
||||
end
|
||||
add_column(table, column, type, default: default, limit: limit, null: allow_null)
|
||||
end
|
||||
|
||||
# Renames a column without requiring downtime.
|
||||
|
|
|
@ -35,9 +35,11 @@ REDIS_CACHE_PARAMS = {
|
|||
url: ENV['CACHE_REDIS_URL'],
|
||||
expires_in: 10.minutes,
|
||||
namespace: cache_namespace,
|
||||
pool_size: Sidekiq.server? ? Sidekiq[:concurrency] : Integer(ENV['MAX_THREADS'] || 5),
|
||||
pool_timeout: 5,
|
||||
connect_timeout: 5,
|
||||
pool: {
|
||||
size: Sidekiq.server? ? Sidekiq[:concurrency] : Integer(ENV['MAX_THREADS'] || 5),
|
||||
timeout: 5,
|
||||
},
|
||||
}.freeze
|
||||
|
||||
REDIS_SIDEKIQ_PARAMS = {
|
||||
|
|
|
@ -33,8 +33,6 @@ RSpec.describe Admin::Disputes::AppealsController do
|
|||
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
allow(UserMailer).to receive(:appeal_approved)
|
||||
.and_return(instance_double(ActionMailer::MessageDelivery, deliver_later: nil))
|
||||
post :approve, params: { id: appeal.id }
|
||||
end
|
||||
|
||||
|
@ -47,7 +45,9 @@ RSpec.describe Admin::Disputes::AppealsController do
|
|||
end
|
||||
|
||||
it 'notifies target account about approved appeal' do
|
||||
expect(UserMailer).to have_received(:appeal_approved).with(target_account.user, appeal)
|
||||
expect(UserMailer.deliveries.size).to eq(1)
|
||||
expect(UserMailer.deliveries.first.to.first).to eq(target_account.user.email)
|
||||
expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.appeal_approved.subject', date: I18n.l(appeal.created_at)))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -55,8 +55,6 @@ RSpec.describe Admin::Disputes::AppealsController do
|
|||
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
allow(UserMailer).to receive(:appeal_rejected)
|
||||
.and_return(instance_double(ActionMailer::MessageDelivery, deliver_later: nil))
|
||||
post :reject, params: { id: appeal.id }
|
||||
end
|
||||
|
||||
|
@ -65,7 +63,9 @@ RSpec.describe Admin::Disputes::AppealsController do
|
|||
end
|
||||
|
||||
it 'notifies target account about rejected appeal' do
|
||||
expect(UserMailer).to have_received(:appeal_rejected).with(target_account.user, appeal)
|
||||
expect(UserMailer.deliveries.size).to eq(1)
|
||||
expect(UserMailer.deliveries.first.to.first).to eq(target_account.user.email)
|
||||
expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.appeal_rejected.subject', date: I18n.l(appeal.created_at)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::V1::Accounts::FeaturedTagsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -127,8 +127,6 @@ RSpec.describe Auth::SessionsController do
|
|||
|
||||
before do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return(current_ip)
|
||||
allow(UserMailer).to receive(:suspicious_sign_in)
|
||||
.and_return(instance_double(ActionMailer::MessageDelivery, deliver_later!: nil))
|
||||
user.update(current_sign_in_at: 1.month.ago)
|
||||
post :create, params: { user: { email: user.email, password: user.password } }
|
||||
end
|
||||
|
@ -142,7 +140,9 @@ RSpec.describe Auth::SessionsController do
|
|||
end
|
||||
|
||||
it 'sends a suspicious sign-in mail' do
|
||||
expect(UserMailer).to have_received(:suspicious_sign_in).with(user, current_ip, anything, anything)
|
||||
expect(UserMailer.deliveries.size).to eq(1)
|
||||
expect(UserMailer.deliveries.first.to.first).to eq(user.email)
|
||||
expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.suspicious_sign_in.subject'))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -30,6 +30,14 @@ describe 'email confirmation flow when captcha is enabled' do
|
|||
click_button I18n.t('challenge.confirm')
|
||||
expect(user.reload.confirmed?).to be true
|
||||
expect(page).to have_current_path(/\A#{client_app.confirmation_redirect_uri}/, url: true)
|
||||
|
||||
# Browsers will generally reload the original page upon redirection
|
||||
# to external handlers, so test this as well
|
||||
visit "/auth/confirmation?confirmation_token=#{user.confirmation_token}&redirect_to_app=true"
|
||||
|
||||
# It presents a page with a link to the app callback
|
||||
expect(page).to have_content(I18n.t('auth.confirmations.registration_complete', domain: 'cb6e6126.ngrok.io'))
|
||||
expect(page).to have_link(I18n.t('auth.confirmations.clicking_this_link'), href: client_app.confirmation_redirect_uri)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ContentSecurityPolicy do
|
||||
subject { described_class.new }
|
||||
|
||||
around do |example|
|
||||
original_asset_host = Rails.configuration.action_controller.asset_host
|
||||
original_web_domain = Rails.configuration.x.web_domain
|
||||
original_use_https = Rails.configuration.x.use_https
|
||||
example.run
|
||||
Rails.configuration.action_controller.asset_host = original_asset_host
|
||||
Rails.configuration.x.web_domain = original_web_domain
|
||||
Rails.configuration.x.use_https = original_use_https
|
||||
end
|
||||
|
||||
describe '#base_host' do
|
||||
before { Rails.configuration.x.web_domain = 'host.example' }
|
||||
|
||||
it 'returns the configured value for the web domain' do
|
||||
expect(subject.base_host).to eq 'host.example'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#assets_host' do
|
||||
context 'when asset_host is not configured' do
|
||||
before { Rails.configuration.action_controller.asset_host = nil }
|
||||
|
||||
context 'with a configured web domain' do
|
||||
before { Rails.configuration.x.web_domain = 'host.example' }
|
||||
|
||||
context 'when use_https is enabled' do
|
||||
before { Rails.configuration.x.use_https = true }
|
||||
|
||||
it 'returns value from base host with https protocol' do
|
||||
expect(subject.assets_host).to eq 'https://host.example'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when use_https is disabled' do
|
||||
before { Rails.configuration.x.use_https = false }
|
||||
|
||||
it 'returns value from base host with http protocol' do
|
||||
expect(subject.assets_host).to eq 'http://host.example'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when asset_host is configured' do
|
||||
before do
|
||||
Rails.configuration.action_controller.asset_host = 'https://assets.host.example'
|
||||
end
|
||||
|
||||
it 'returns full value from configured host' do
|
||||
expect(subject.assets_host).to eq 'https://assets.host.example'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#media_host' do
|
||||
context 'when there is no configured CDN' do
|
||||
it 'defaults to using the assets_host value' do
|
||||
expect(subject.media_host).to eq(subject.assets_host)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an S3 alias host is configured' do
|
||||
around do |example|
|
||||
ClimateControl.modify S3_ALIAS_HOST: 'asset-host.s3-alias.example' do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
it 'uses the s3 alias host value' do
|
||||
expect(subject.media_host).to eq 'https://asset-host.s3-alias.example'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an S3 alias host with a trailing path is configured' do
|
||||
around do |example|
|
||||
ClimateControl.modify S3_ALIAS_HOST: 'asset-host.s3-alias.example/pathname' do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
it 'uses the s3 alias host value and preserves the path' do
|
||||
expect(subject.media_host).to eq 'https://asset-host.s3-alias.example/pathname/'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an S3 cloudfront host is configured' do
|
||||
around do |example|
|
||||
ClimateControl.modify S3_CLOUDFRONT_HOST: 'asset-host.s3-cloudfront.example' do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
it 'uses the s3 cloudfront host value' do
|
||||
expect(subject.media_host).to eq 'https://asset-host.s3-cloudfront.example'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an azure alias host is configured' do
|
||||
around do |example|
|
||||
ClimateControl.modify AZURE_ALIAS_HOST: 'asset-host.azure-alias.example' do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
it 'uses the azure alias host value' do
|
||||
expect(subject.media_host).to eq 'https://asset-host.azure-alias.example'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when s3_enabled is configured' do
|
||||
around do |example|
|
||||
ClimateControl.modify S3_ENABLED: 'true', S3_HOSTNAME: 'asset-host.s3.example' do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
it 'uses the s3 hostname host value' do
|
||||
expect(subject.media_host).to eq 'https://asset-host.s3.example'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,7 +5,7 @@ require 'rails_helper'
|
|||
describe UserMailer do
|
||||
let(:receiver) { Fabricate(:user) }
|
||||
|
||||
describe 'confirmation_instructions' do
|
||||
describe '#confirmation_instructions' do
|
||||
let(:mail) { described_class.confirmation_instructions(receiver, 'spec') }
|
||||
|
||||
it 'renders confirmation instructions' do
|
||||
|
@ -20,7 +20,7 @@ describe UserMailer do
|
|||
instance: Rails.configuration.x.local_domain
|
||||
end
|
||||
|
||||
describe 'reconfirmation_instructions' do
|
||||
describe '#reconfirmation_instructions' do
|
||||
let(:mail) { described_class.confirmation_instructions(receiver, 'spec') }
|
||||
|
||||
it 'renders reconfirmation instructions' do
|
||||
|
@ -34,7 +34,7 @@ describe UserMailer do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'reset_password_instructions' do
|
||||
describe '#reset_password_instructions' do
|
||||
let(:mail) { described_class.reset_password_instructions(receiver, 'spec') }
|
||||
|
||||
it 'renders reset password instructions' do
|
||||
|
@ -47,7 +47,7 @@ describe UserMailer do
|
|||
'devise.mailer.reset_password_instructions.subject'
|
||||
end
|
||||
|
||||
describe 'password_change' do
|
||||
describe '#password_change' do
|
||||
let(:mail) { described_class.password_change(receiver) }
|
||||
|
||||
it 'renders password change notification' do
|
||||
|
@ -59,7 +59,7 @@ describe UserMailer do
|
|||
'devise.mailer.password_change.subject'
|
||||
end
|
||||
|
||||
describe 'email_changed' do
|
||||
describe '#email_changed' do
|
||||
let(:mail) { described_class.email_changed(receiver) }
|
||||
|
||||
it 'renders email change notification' do
|
||||
|
@ -71,7 +71,7 @@ describe UserMailer do
|
|||
'devise.mailer.email_changed.subject'
|
||||
end
|
||||
|
||||
describe 'warning' do
|
||||
describe '#warning' do
|
||||
let(:strike) { Fabricate(:account_warning, target_account: receiver.account, text: 'dont worry its just the testsuite', action: 'suspend') }
|
||||
let(:mail) { described_class.warning(receiver, strike) }
|
||||
|
||||
|
@ -82,7 +82,7 @@ describe UserMailer do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'webauthn_credential_deleted' do
|
||||
describe '#webauthn_credential_deleted' do
|
||||
let(:credential) { Fabricate(:webauthn_credential, user_id: receiver.id) }
|
||||
let(:mail) { described_class.webauthn_credential_deleted(receiver, credential) }
|
||||
|
||||
|
@ -95,7 +95,7 @@ describe UserMailer do
|
|||
'devise.mailer.webauthn_credential.deleted.subject'
|
||||
end
|
||||
|
||||
describe 'suspicious_sign_in' do
|
||||
describe '#suspicious_sign_in' do
|
||||
let(:ip) { '192.168.0.1' }
|
||||
let(:agent) { 'NCSA_Mosaic/2.0 (Windows 3.1)' }
|
||||
let(:timestamp) { Time.now.utc }
|
||||
|
@ -110,7 +110,7 @@ describe UserMailer do
|
|||
'user_mailer.suspicious_sign_in.subject'
|
||||
end
|
||||
|
||||
describe 'appeal_approved' do
|
||||
describe '#appeal_approved' do
|
||||
let(:appeal) { Fabricate(:appeal, account: receiver.account, approved_at: Time.now.utc) }
|
||||
let(:mail) { described_class.appeal_approved(receiver, appeal) }
|
||||
|
||||
|
@ -120,7 +120,7 @@ describe UserMailer do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'appeal_rejected' do
|
||||
describe '#appeal_rejected' do
|
||||
let(:appeal) { Fabricate(:appeal, account: receiver.account, rejected_at: Time.now.utc) }
|
||||
let(:mail) { described_class.appeal_rejected(receiver, appeal) }
|
||||
|
||||
|
@ -130,7 +130,7 @@ describe UserMailer do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'two_factor_enabled' do
|
||||
describe '#two_factor_enabled' do
|
||||
let(:mail) { described_class.two_factor_enabled(receiver) }
|
||||
|
||||
it 'renders two_factor_enabled mail' do
|
||||
|
@ -139,7 +139,7 @@ describe UserMailer do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'two_factor_disabled' do
|
||||
describe '#two_factor_disabled' do
|
||||
let(:mail) { described_class.two_factor_disabled(receiver) }
|
||||
|
||||
it 'renders two_factor_disabled mail' do
|
||||
|
@ -148,7 +148,7 @@ describe UserMailer do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'webauthn_enabled' do
|
||||
describe '#webauthn_enabled' do
|
||||
let(:mail) { described_class.webauthn_enabled(receiver) }
|
||||
|
||||
it 'renders webauthn_enabled mail' do
|
||||
|
@ -157,7 +157,7 @@ describe UserMailer do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'webauthn_disabled' do
|
||||
describe '#webauthn_disabled' do
|
||||
let(:mail) { described_class.webauthn_disabled(receiver) }
|
||||
|
||||
it 'renders webauthn_disabled mail' do
|
||||
|
@ -166,7 +166,7 @@ describe UserMailer do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'two_factor_recovery_codes_changed' do
|
||||
describe '#two_factor_recovery_codes_changed' do
|
||||
let(:mail) { described_class.two_factor_recovery_codes_changed(receiver) }
|
||||
|
||||
it 'renders two_factor_recovery_codes_changed mail' do
|
||||
|
@ -175,7 +175,7 @@ describe UserMailer do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'webauthn_credential_added' do
|
||||
describe '#webauthn_credential_added' do
|
||||
let(:credential) { Fabricate.build(:webauthn_credential) }
|
||||
let(:mail) { described_class.webauthn_credential_added(receiver, credential) }
|
||||
|
||||
|
@ -184,4 +184,23 @@ describe UserMailer do
|
|||
expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_credential.added.explanation')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#welcome' do
|
||||
let(:mail) { described_class.welcome(receiver) }
|
||||
|
||||
it 'renders welcome mail' do
|
||||
expect(mail.subject).to eq I18n.t('user_mailer.welcome.subject')
|
||||
expect(mail.body.encoded).to include I18n.t('user_mailer.welcome.explanation')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#backup_ready' do
|
||||
let(:backup) { Fabricate(:backup) }
|
||||
let(:mail) { described_class.backup_ready(receiver, backup) }
|
||||
|
||||
it 'renders backup_ready mail' do
|
||||
expect(mail.subject).to eq I18n.t('user_mailer.backup_ready.subject')
|
||||
expect(mail.body.encoded).to include I18n.t('user_mailer.backup_ready.explanation')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,6 +32,10 @@ RSpec.describe Tag do
|
|||
expect(subject.match('https://en.wikipedia.org/wiki/Ghostbusters_(song)#Lawsuit')).to be_nil
|
||||
end
|
||||
|
||||
it 'does not match URLs with hashtag-like anchors after a numeral' do
|
||||
expect(subject.match('https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111895#c4')).to be_nil
|
||||
end
|
||||
|
||||
it 'does not match URLs with hashtag-like anchors after an empty query parameter' do
|
||||
expect(subject.match('https://en.wikipedia.org/wiki/Ghostbusters_(song)?foo=#Lawsuit')).to be_nil
|
||||
end
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'account featured tags API' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:accounts' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
describe 'GET /api/v1/accounts/:id/featured_tags' do
|
||||
subject do
|
||||
get "/api/v1/accounts/#{account.id}/featured_tags", headers: headers
|
||||
end
|
||||
|
||||
before do
|
||||
account.featured_tags.create!(name: 'foo')
|
||||
account.featured_tags.create!(name: 'bar')
|
||||
end
|
||||
|
||||
it 'returns the expected tags', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json).to contain_exactly(a_hash_including({
|
||||
name: 'bar',
|
||||
url: "https://cb6e6126.ngrok.io/@#{account.username}/tagged/bar",
|
||||
}), a_hash_including({
|
||||
name: 'foo',
|
||||
url: "https://cb6e6126.ngrok.io/@#{account.username}/tagged/foo",
|
||||
}))
|
||||
end
|
||||
|
||||
context 'when the account is remote' do
|
||||
it 'returns the expected tags', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json).to contain_exactly(a_hash_including({
|
||||
name: 'bar',
|
||||
url: "https://cb6e6126.ngrok.io/@#{account.pretty_acct}/tagged/bar",
|
||||
}), a_hash_including({
|
||||
name: 'foo',
|
||||
url: "https://cb6e6126.ngrok.io/@#{account.pretty_acct}/tagged/foo",
|
||||
}))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -42,12 +42,22 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
|
|||
}
|
||||
end
|
||||
|
||||
let(:featured_with_null) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: 'https://example.com/account/collections/featured',
|
||||
totalItems: 0,
|
||||
type: 'OrderedCollection',
|
||||
}
|
||||
end
|
||||
|
||||
let(:items) do
|
||||
[
|
||||
'https://example.com/account/pinned/known', # known
|
||||
status_json_pinned_unknown_inlined, # unknown inlined
|
||||
'https://example.com/account/pinned/unknown-unreachable', # unknown unreachable
|
||||
'https://example.com/account/pinned/unknown-reachable', # unknown reachable
|
||||
'https://example.com/account/collections/featured', # featured with null
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -66,6 +76,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
|
|||
stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined))
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-unreachable').to_return(status: 404)
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_unreachable))
|
||||
stub_request(:get, 'https://example.com/account/collections/featured').to_return(status: 200, body: Oj.dump(featured_with_null))
|
||||
|
||||
subject.call(actor, note: true, hashtag: false)
|
||||
end
|
||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -1766,9 +1766,9 @@
|
|||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@material-symbols/svg-600@^0.13.1":
|
||||
version "0.13.1"
|
||||
resolved "https://registry.yarnpkg.com/@material-symbols/svg-600/-/svg-600-0.13.1.tgz#9f1c2a1fa4439e6cc9ad5f7a7ef64ce7691b42c8"
|
||||
integrity sha512-oI4De/ePwj1IBxtabmpqMy092Y4ius0byQo/BC3yvLY4WbtzQlIScxUY7bUx+Gqrwq03QZDYrgP/cU4a/TXqyA==
|
||||
version "0.13.2"
|
||||
resolved "https://registry.yarnpkg.com/@material-symbols/svg-600/-/svg-600-0.13.2.tgz#a98361ed5a100492780e3301c9d9e4d79aefe0f1"
|
||||
integrity sha512-4n/bbh6444ZfJ72VHYrWc2f2E8PCsC6ue/ou4Q4QqQFvSRbQSZjcSXuTb0lA4xkaIf2cJf4grvF8ZsskIBLbHg==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
|
@ -10945,9 +10945,9 @@ sass-loader@^10.2.0:
|
|||
semver "^7.3.2"
|
||||
|
||||
sass@^1.62.1:
|
||||
version "1.69.4"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.4.tgz#10c735f55e3ea0b7742c6efa940bce30e07fbca2"
|
||||
integrity sha512-+qEreVhqAy8o++aQfCJwp0sklr2xyEzkm9Pp/Igu9wNPoe7EZEQ8X/MBvvXggI2ql607cxKg/RKOwDj6pp2XDA==
|
||||
version "1.69.5"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.5.tgz#23e18d1c757a35f2e52cc81871060b9ad653dfde"
|
||||
integrity sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==
|
||||
dependencies:
|
||||
chokidar ">=3.0.0 <4.0.0"
|
||||
immutable "^4.0.0"
|
||||
|
|
Loading…
Reference in New Issue