M .github/workflows/test-js.yml => .github/workflows/test-js.yml +4 -0
@@ 9,6 9,8 @@ on:
- '.nvmrc'
- '**/*.js'
- '**/*.jsx'
+ - '**/*.ts'
+ - '**/*.tsx'
- '**/*.snap'
- '.github/workflows/test-js.yml'
@@ 19,6 21,8 @@ on:
- '.nvmrc'
- '**/*.js'
- '**/*.jsx'
+ - '**/*.ts'
+ - '**/*.tsx'
- '**/*.snap'
- '.github/workflows/test-js.yml'
M Gemfile => Gemfile +1 -1
@@ 120,7 120,7 @@ end
group :test do
gem 'capybara', '~> 3.39'
gem 'climate_control'
- gem 'faker', '~> 3.1'
+ gem 'faker', '~> 3.2'
gem 'json-schema', '~> 3.0'
gem 'rack-test', '~> 2.1'
gem 'rails-controller-testing', '~> 1.0'
M Gemfile.lock => Gemfile.lock +9 -9
@@ 243,7 243,7 @@ GEM
tzinfo
excon (0.95.0)
fabrication (2.30.0)
- faker (3.1.1)
+ faker (3.2.0)
i18n (>= 1.8.11, < 2)
faraday (1.10.3)
faraday-em_http (~> 1.0)
@@ 348,19 348,19 @@ GEM
ipaddress (0.8.3)
jmespath (1.6.2)
json (2.6.3)
- json-canonicalization (0.3.0)
+ json-canonicalization (0.3.1)
json-jwt (1.15.3)
activesupport (>= 4.2)
aes_key_wrap
bindata
httpclient
- json-ld (3.2.3)
+ json-ld (3.2.4)
htmlentities (~> 4.3)
json-canonicalization (~> 0.3)
link_header (~> 0.0, >= 0.0.8)
multi_json (~> 1.15)
- rack (~> 2.2)
- rdf (~> 3.2, >= 3.2.9)
+ rack (>= 2.2, < 4)
+ rdf (~> 3.2, >= 3.2.10)
json-ld-preloaded (3.2.2)
json-ld (~> 3.2)
rdf (~> 3.2)
@@ 479,7 479,7 @@ GEM
openssl-signature_algorithm (1.3.0)
openssl (> 2.0)
orm_adapter (0.5.0)
- ox (2.14.14)
+ ox (2.14.16)
parallel (1.22.1)
parser (3.2.2.0)
ast (~> 2.4.1)
@@ 487,7 487,7 @@ GEM
pastel (0.8.0)
tty-color (~> 0.5)
pg (1.4.6)
- pghero (3.3.1)
+ pghero (3.3.2)
activerecord (>= 6)
pkg-config (1.5.1)
posix-spawn (0.3.15)
@@ 557,7 557,7 @@ GEM
thor (~> 1.0)
rainbow (3.1.1)
rake (13.0.6)
- rdf (3.2.9)
+ rdf (3.2.10)
link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.5.1)
rdf (~> 3.2)
@@ 799,7 799,7 @@ DEPENDENCIES
dotenv-rails (~> 2.8)
ed25519 (~> 1.3)
fabrication (~> 2.30)
- faker (~> 3.1)
+ faker (~> 3.2)
fast_blank (~> 1.0)
fastimage
fog-core (<= 2.4.0)
A app/controllers/api/v1/admin/trends/links/preview_card_providers_controller.rb => app/controllers/api/v1/admin/trends/links/preview_card_providers_controller.rb +72 -0
@@ 0,0 1,72 @@
+# frozen_string_literal: true
+
+class Api::V1::Admin::Trends::Links::PreviewCardProvidersController < Api::BaseController
+ include Authorization
+
+ LIMIT = 100
+
+ before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
+ before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
+ before_action :set_providers, only: :index
+
+ after_action :verify_authorized
+ after_action :insert_pagination_headers, only: :index
+
+ PAGINATION_PARAMS = %i(limit).freeze
+
+ def index
+ authorize :preview_card_provider, :index?
+
+ render json: @providers, each_serializer: REST::Admin::Trends::Links::PreviewCardProviderSerializer
+ end
+
+ def approve
+ authorize :preview_card_provider, :review?
+
+ provider = PreviewCardProvider.find(params[:id])
+ provider.update(trendable: true, reviewed_at: Time.now.utc)
+ render json: provider, serializer: REST::Admin::Trends::Links::PreviewCardProviderSerializer
+ end
+
+ def reject
+ authorize :preview_card_provider, :review?
+
+ provider = PreviewCardProvider.find(params[:id])
+ provider.update(trendable: false, reviewed_at: Time.now.utc)
+ render json: provider, serializer: REST::Admin::Trends::Links::PreviewCardProviderSerializer
+ end
+
+ private
+
+ def set_providers
+ @providers = PreviewCardProvider.all.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
+ end
+
+ def insert_pagination_headers
+ set_pagination_headers(next_path, prev_path)
+ end
+
+ def next_path
+ api_v1_admin_trends_links_preview_card_providers_url(pagination_params(max_id: pagination_max_id)) if records_continue?
+ end
+
+ def prev_path
+ api_v1_admin_trends_links_preview_card_providers_url(pagination_params(min_id: pagination_since_id)) unless @providers.empty?
+ end
+
+ def pagination_max_id
+ @providers.last.id
+ end
+
+ def pagination_since_id
+ @providers.first.id
+ end
+
+ def records_continue?
+ @providers.size == limit_param(LIMIT)
+ end
+
+ def pagination_params(core_params)
+ params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params)
+ end
+end
M app/controllers/api/v1/admin/trends/links_controller.rb => app/controllers/api/v1/admin/trends/links_controller.rb +30 -1
@@ 1,7 1,36 @@
# frozen_string_literal: true
class Api::V1::Admin::Trends::LinksController < Api::V1::Trends::LinksController
- before_action -> { authorize_if_got_token! :'admin:read' }
+ include Authorization
+
+ before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
+ before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
+
+ after_action :verify_authorized, except: :index
+
+ def index
+ if current_user&.can?(:manage_taxonomies)
+ render json: @links, each_serializer: REST::Admin::Trends::LinkSerializer
+ else
+ super
+ end
+ end
+
+ def approve
+ authorize :preview_card, :review?
+
+ link = PreviewCard.find(params[:id])
+ link.update(trendable: true)
+ render json: link, serializer: REST::Admin::Trends::LinkSerializer
+ end
+
+ def reject
+ authorize :preview_card, :review?
+
+ link = PreviewCard.find(params[:id])
+ link.update(trendable: false)
+ render json: link, serializer: REST::Admin::Trends::LinkSerializer
+ end
private
M app/controllers/api/v1/admin/trends/statuses_controller.rb => app/controllers/api/v1/admin/trends/statuses_controller.rb +30 -1
@@ 1,7 1,36 @@
# frozen_string_literal: true
class Api::V1::Admin::Trends::StatusesController < Api::V1::Trends::StatusesController
- before_action -> { authorize_if_got_token! :'admin:read' }
+ include Authorization
+
+ before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
+ before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
+
+ after_action :verify_authorized, except: :index
+
+ def index
+ if current_user&.can?(:manage_taxonomies)
+ render json: @statuses, each_serializer: REST::Admin::Trends::StatusSerializer
+ else
+ super
+ end
+ end
+
+ def approve
+ authorize [:admin, :status], :review?
+
+ status = Status.find(params[:id])
+ status.update(trendable: true)
+ render json: status, serializer: REST::Admin::Trends::StatusSerializer
+ end
+
+ def reject
+ authorize [:admin, :status], :review?
+
+ status = Status.find(params[:id])
+ status.update(trendable: false)
+ render json: status, serializer: REST::Admin::Trends::StatusSerializer
+ end
private
M app/controllers/api/v1/admin/trends/tags_controller.rb => app/controllers/api/v1/admin/trends/tags_controller.rb +22 -1
@@ 1,7 1,12 @@
# frozen_string_literal: true
class Api::V1::Admin::Trends::TagsController < Api::V1::Trends::TagsController
- before_action -> { authorize_if_got_token! :'admin:read' }
+ include Authorization
+
+ before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
+ before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
+
+ after_action :verify_authorized, except: :index
def index
if current_user&.can?(:manage_taxonomies)
@@ 11,6 16,22 @@ class Api::V1::Admin::Trends::TagsController < Api::V1::Trends::TagsController
end
end
+ def approve
+ authorize :tag, :review?
+
+ tag = Tag.find(params[:id])
+ tag.update(trendable: true, reviewed_at: Time.now.utc)
+ render json: tag, serializer: REST::Admin::TagSerializer
+ end
+
+ def reject
+ authorize :tag, :review?
+
+ tag = Tag.find(params[:id])
+ tag.update(trendable: false, reviewed_at: Time.now.utc)
+ render json: tag, serializer: REST::Admin::TagSerializer
+ end
+
private
def enabled?
M app/controllers/auth/setup_controller.rb => app/controllers/auth/setup_controller.rb +3 -16
@@ 11,15 11,7 @@ class Auth::SetupController < ApplicationController
skip_before_action :require_functional!
- def show
- flash.now[:notice] = begin
- if @user.pending?
- I18n.t('devise.registrations.signed_up_but_pending')
- else
- I18n.t('devise.registrations.signed_up_but_unconfirmed')
- end
- end
- end
+ def show; end
def update
# This allows updating the e-mail without entering a password as is required
@@ 27,14 19,13 @@ class Auth::SetupController < ApplicationController
# that were not confirmed yet
if @user.update(user_params)
- redirect_to auth_setup_path, notice: I18n.t('devise.confirmations.send_instructions')
+ @user.resend_confirmation_instructions unless @user.confirmed?
+ redirect_to auth_setup_path, notice: I18n.t('auth.setup.new_confirmation_instructions_sent')
else
render :show
end
end
- helper_method :missing_email?
-
private
def require_unconfirmed_or_pending!
@@ 53,10 44,6 @@ class Auth::SetupController < ApplicationController
params.require(:user).permit(:email)
end
- def missing_email?
- truthy_param?(:missing_email)
- end
-
def set_pack
use_pack 'auth'
end
M app/helpers/application_helper.rb => app/helpers/application_helper.rb +4 -0
@@ 117,6 117,10 @@ module ApplicationHelper
content_tag(:i, nil, attributes.merge(class: class_names.join(' ')))
end
+ def check_icon
+ content_tag(:svg, tag(:path, 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z'), xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 20 20', fill: 'currentColor')
+ end
+
def visibility_icon(status)
if status.public_visibility?
fa_icon('globe', title: I18n.t('statuses.visibilities.public'))
M app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.jsx.snap => app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.jsx.snap +2 -4
@@ 3,6 3,8 @@
exports[`<AvatarOverlay renders a overlay avatar 1`] = `
<div
className="account__avatar-overlay"
+ onMouseEnter={[Function]}
+ onMouseLeave={[Function]}
style={
{
"height": 46,
@@ 15,8 17,6 @@ exports[`<AvatarOverlay renders a overlay avatar 1`] = `
>
<div
className="account__avatar"
- onMouseEnter={[Function]}
- onMouseLeave={[Function]}
style={
{
"height": "36px",
@@ 35,8 35,6 @@ exports[`<AvatarOverlay renders a overlay avatar 1`] = `
>
<div
className="account__avatar"
- onMouseEnter={[Function]}
- onMouseLeave={[Function]}
style={
{
"height": "24px",
R app/javascript/mastodon/components/animated_number.jsx => app/javascript/mastodon/components/animated_number.tsx +43 -61
@@ 1,11 1,9 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import ShortNumber from 'mastodon/components/short_number';
-import TransitionMotion from 'react-motion/lib/TransitionMotion';
-import spring from 'react-motion/lib/spring';
-import { reduceMotion } from 'mastodon/initial_state';
+import React, { useCallback, useState } from 'react';
+import ShortNumber from './short_number';
+import { TransitionMotion, spring } from 'react-motion';
+import { reduceMotion } from '../initial_state';
-const obfuscatedCount = count => {
+const obfuscatedCount = (count: number) => {
if (count < 0) {
return 0;
} else if (count <= 1) {
@@ 15,62 13,46 @@ const obfuscatedCount = count => {
}
};
-export default class AnimatedNumber extends React.PureComponent {
-
- static propTypes = {
- value: PropTypes.number.isRequired,
- obfuscate: PropTypes.bool,
- };
-
- state = {
- direction: 1,
- };
-
- componentWillReceiveProps (nextProps) {
- if (nextProps.value > this.props.value) {
- this.setState({ direction: 1 });
- } else if (nextProps.value < this.props.value) {
- this.setState({ direction: -1 });
- }
+type Props = {
+ value: number;
+ obfuscate?: boolean;
+}
+export const AnimatedNumber: React.FC<Props> = ({
+ value,
+ obfuscate,
+})=> {
+ const [previousValue, setPreviousValue] = useState(value);
+ const [direction, setDirection] = useState<1|-1>(1);
+
+ if (previousValue !== value) {
+ setPreviousValue(value);
+ setDirection(value > previousValue ? 1 : -1);
}
- willEnter = () => {
- const { direction } = this.state;
-
- return { y: -1 * direction };
- };
-
- willLeave = () => {
- const { direction } = this.state;
-
- return { y: spring(1 * direction, { damping: 35, stiffness: 400 }) };
- };
+ const willEnter = useCallback(() => ({ y: -1 * direction }), [direction]);
+ const willLeave = useCallback(() => ({ y: spring(1 * direction, { damping: 35, stiffness: 400 }) }), [direction]);
- render () {
- const { value, obfuscate } = this.props;
- const { direction } = this.state;
-
- if (reduceMotion) {
- return obfuscate ? obfuscatedCount(value) : <ShortNumber value={value} />;
- }
-
- const styles = [{
- key: `${value}`,
- data: value,
- style: { y: spring(0, { damping: 35, stiffness: 400 }) },
- }];
-
- return (
- <TransitionMotion styles={styles} willEnter={this.willEnter} willLeave={this.willLeave}>
- {items => (
- <span className='animated-number'>
- {items.map(({ key, data, style }) => (
- <span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}</span>
- ))}
- </span>
- )}
- </TransitionMotion>
- );
+ if (reduceMotion) {
+ return obfuscate ? <>{obfuscatedCount(value)}</> : <ShortNumber value={value} />;
}
-}
+ const styles = [{
+ key: `${value}`,
+ data: value,
+ style: { y: spring(0, { damping: 35, stiffness: 400 }) },
+ }];
+
+ return (
+ <TransitionMotion styles={styles} willEnter={willEnter} willLeave={willLeave}>
+ {items => (
+ <span className='animated-number'>
+ {items.map(({ key, data, style }) => (
+ <span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}</span>
+ ))}
+ </span>
+ )}
+ </TransitionMotion>
+ );
+};
+
+export default AnimatedNumber;
D app/javascript/mastodon/components/avatar_overlay.jsx => app/javascript/mastodon/components/avatar_overlay.jsx +0 -51
@@ 1,51 0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import { autoPlayGif } from '../initial_state';
-import Avatar from './avatar';
-
-export default class AvatarOverlay extends React.PureComponent {
-
- static propTypes = {
- account: ImmutablePropTypes.map.isRequired,
- friend: ImmutablePropTypes.map.isRequired,
- animate: PropTypes.bool,
- size: PropTypes.number,
- baseSize: PropTypes.number,
- overlaySize: PropTypes.number,
- };
-
- static defaultProps = {
- animate: autoPlayGif,
- size: 46,
- baseSize: 36,
- overlaySize: 24,
- };
-
- state = {
- hovering: false,
- };
-
- handleMouseEnter = () => {
- if (this.props.animate) return;
- this.setState({ hovering: true });
- };
-
- handleMouseLeave = () => {
- if (this.props.animate) return;
- this.setState({ hovering: false });
- };
-
- render() {
- const { account, friend, animate, size, baseSize, overlaySize } = this.props;
- const { hovering } = this.state;
-
- return (
- <div className='account__avatar-overlay' style={{ width: size, height: size }}>
- <div className='account__avatar-overlay-base'><Avatar animate={hovering || animate} account={account} size={baseSize} /></div>
- <div className='account__avatar-overlay-overlay'><Avatar animate={hovering || animate} account={friend} size={overlaySize} /></div>
- </div>
- );
- }
-
-}
A app/javascript/mastodon/components/avatar_overlay.tsx => app/javascript/mastodon/components/avatar_overlay.tsx +51 -0
@@ 0,0 1,51 @@
+import React from 'react';
+import type { Account } from '../../types/resources';
+import { useHovering } from '../../hooks/useHovering';
+import { autoPlayGif } from '../initial_state';
+
+type Props = {
+ account: Account;
+ friend: Account;
+ size?: number;
+ baseSize?: number;
+ overlaySize?: number;
+};
+
+export const AvatarOverlay: React.FC<Props> = ({
+ account,
+ friend,
+ size = 46,
+ baseSize = 36,
+ overlaySize = 24,
+}) => {
+ const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(autoPlayGif);
+ const accountSrc = hovering ? account?.get('avatar') : account?.get('avatar_static');
+ const friendSrc = hovering ? friend?.get('avatar') : friend?.get('avatar_static');
+
+ return (
+ <div
+ className='account__avatar-overlay' style={{ width: size, height: size }}
+ onMouseEnter={handleMouseEnter}
+ onMouseLeave={handleMouseLeave}
+ >
+ <div className='account__avatar-overlay-base'>
+ <div
+ className='account__avatar'
+ style={{ width: `${baseSize}px`, height: `${baseSize}px` }}
+ >
+ {accountSrc && <img src={accountSrc} alt={account?.get('acct')} />}
+ </div>
+ </div>
+ <div className='account__avatar-overlay-overlay'>
+ <div
+ className='account__avatar'
+ style={{ width: `${overlaySize}px`, height: `${overlaySize}px` }}
+ >
+ {friendSrc && <img src={friendSrc} alt={friend?.get('acct')} />}
+ </div>
+ </div>
+ </div>
+ );
+};
+
+export default AvatarOverlay;
R app/javascript/mastodon/components/gifv.jsx => app/javascript/mastodon/components/gifv.tsx +52 -60
@@ 1,76 1,68 @@
-import React from 'react';
-import PropTypes from 'prop-types';
+import React, { useCallback, useState } from 'react';
-export default class GIFV extends React.PureComponent {
-
- static propTypes = {
- src: PropTypes.string.isRequired,
- alt: PropTypes.string,
- lang: PropTypes.string,
- width: PropTypes.number,
- height: PropTypes.number,
- onClick: PropTypes.func,
- };
-
- state = {
- loading: true,
- };
-
- handleLoadedData = () => {
- this.setState({ loading: false });
- };
+type Props = {
+ src: string;
+ key: string;
+ alt?: string;
+ lang?: string;
+ width: number;
+ height: number;
+ onClick?: () => void;
+}
- componentWillReceiveProps (nextProps) {
- if (nextProps.src !== this.props.src) {
- this.setState({ loading: true });
- }
- }
+export const GIFV: React.FC<Props> = ({
+ src,
+ alt,
+ lang,
+ width,
+ height,
+ onClick,
+})=> {
+ const [loading, setLoading] = useState(true);
- handleClick = e => {
- const { onClick } = this.props;
+ const handleLoadedData: React.ReactEventHandler<HTMLVideoElement> = useCallback(() => {
+ setLoading(false);
+ }, [setLoading]);
+ const handleClick: React.MouseEventHandler = useCallback((e) => {
if (onClick) {
e.stopPropagation();
onClick();
}
- };
+ }, [onClick]);
- render () {
- const { src, width, height, alt, lang } = this.props;
- const { loading } = this.state;
-
- return (
- <div className='gifv' style={{ position: 'relative' }}>
- {loading && (
- <canvas
- width={width}
- height={height}
- role='button'
- tabIndex={0}
- aria-label={alt}
- title={alt}
- lang={lang}
- onClick={this.handleClick}
- />
- )}
-
- <video
- src={src}
+ return (
+ <div className='gifv' style={{ position: 'relative' }}>
+ {loading && (
+ <canvas
+ width={width}
+ height={height}
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
- muted
- loop
- autoPlay
- playsInline
- onClick={this.handleClick}
- onLoadedData={this.handleLoadedData}
- style={{ position: loading ? 'absolute' : 'static', top: 0, left: 0 }}
+ onClick={handleClick}
/>
- </div>
- );
- }
+ )}
-}
+ <video
+ src={src}
+ role='button'
+ tabIndex={0}
+ aria-label={alt}
+ title={alt}
+ lang={lang}
+ muted
+ loop
+ autoPlay
+ playsInline
+ onClick={handleClick}
+ onLoadedData={handleLoadedData}
+ style={{ position: loading ? 'absolute' : 'static', top: 0, left: 0 }}
+ />
+ </div>
+ );
+};
+
+export default GIFV;
M app/javascript/mastodon/components/status.jsx => app/javascript/mastodon/components/status.jsx +1 -1
@@ 541,7 541,7 @@ class Status extends ImmutablePureComponent {
expanded={!status.get('hidden')}
onExpandedToggle={this.handleExpandedToggle}
onTranslate={this.handleTranslate}
- collapsable
+ collapsible
onCollapsedToggle={this.handleCollapsedToggle}
/>
M app/javascript/mastodon/components/status_content.jsx => app/javascript/mastodon/components/status_content.jsx +3 -3
@@ 65,7 65,7 @@ class StatusContent extends React.PureComponent {
onExpandedToggle: PropTypes.func,
onTranslate: PropTypes.func,
onClick: PropTypes.func,
- collapsable: PropTypes.bool,
+ collapsible: PropTypes.bool,
onCollapsedToggle: PropTypes.func,
languages: ImmutablePropTypes.map,
intl: PropTypes.object,
@@ 112,10 112,10 @@ class StatusContent extends React.PureComponent {
}
if (status.get('collapsed', null) === null && onCollapsedToggle) {
- const { collapsable, onClick } = this.props;
+ const { collapsible, onClick } = this.props;
const collapsed =
- collapsable
+ collapsible
&& onClick
&& node.clientHeight > MAX_HEIGHT
&& status.get('spoiler_text').length === 0;
M app/javascript/mastodon/features/direct_timeline/components/conversation.jsx => app/javascript/mastodon/features/direct_timeline/components/conversation.jsx +1 -1
@@ 165,7 165,7 @@ class Conversation extends ImmutablePureComponent {
onClick={this.handleClick}
expanded={!lastStatus.get('hidden')}
onExpandedToggle={this.handleShowMore}
- collapsable
+ collapsible
/>
{lastStatus.get('media_attachments').size > 0 && (
M app/javascript/mastodon/features/status/index.jsx => app/javascript/mastodon/features/status/index.jsx +6 -4
@@ 69,6 69,7 @@ const messages = defineMessages({
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.' },
revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' },
hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' },
+ statusTitleWithAttachments: { id: 'status.title.with_attachments', defaultMessage: '{user} posted {attachmentCount, plural, one {an attachment} other {{attachmentCount} attachments}}' },
detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' },
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
@@ 166,13 167,14 @@ const truncate = (str, num) => {
}
};
-const titleFromStatus = status => {
+const titleFromStatus = (intl, status) => {
const displayName = status.getIn(['account', 'display_name']);
const username = status.getIn(['account', 'username']);
- const prefix = displayName.trim().length === 0 ? username : displayName;
+ const user = displayName.trim().length === 0 ? username : displayName;
const text = status.get('search_index');
+ const attachmentCount = status.get('media_attachments').size;
- return `${prefix}: "${truncate(text, 30)}"`;
+ return text ? `${user}: "${truncate(text, 30)}"` : intl.formatMessage(messages.statusTitleWithAttachments, { user, attachmentCount });
};
class Status extends ImmutablePureComponent {
@@ 670,7 672,7 @@ class Status extends ImmutablePureComponent {
</ScrollContainer>
<Helmet>
- <title>{titleFromStatus(status)}</title>
+ <title>{titleFromStatus(intl, status)}</title>
<meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} />
</Helmet>
</Column>
M app/javascript/mastodon/features/ui/components/filter_modal.jsx => app/javascript/mastodon/features/ui/components/filter_modal.jsx +1 -1
@@ 131,4 131,4 @@ class FilterModal extends ImmutablePureComponent {
}
-export default connect(injectIntl(FilterModal));
+export default connect()(injectIntl(FilterModal));
M app/javascript/mastodon/features/ui/components/focal_point_modal.jsx => app/javascript/mastodon/features/ui/components/focal_point_modal.jsx +1 -1
@@ 383,7 383,7 @@ class FocalPointModal extends ImmutablePureComponent {
{focals && (
<div className={classNames('focal-point', { dragging })} ref={this.setRef} onMouseDown={this.handleMouseDown} onTouchStart={this.handleTouchStart}>
{media.get('type') === 'image' && <ImageLoader src={media.get('url')} width={width} height={height} alt='' />}
- {media.get('type') === 'gifv' && <GIFV src={media.get('url')} width={width} height={height} />}
+ {media.get('type') === 'gifv' && <GIFV src={media.get('url')} key={media.get('url')} width={width} height={height} />}
<div className='focal-point__preview'>
<strong><FormattedMessage id='upload_modal.preview_label' defaultMessage='Preview ({ratio})' values={{ ratio: '16:9' }} /></strong>
M app/javascript/mastodon/features/ui/components/media_modal.jsx => app/javascript/mastodon/features/ui/components/media_modal.jsx +1 -1
@@ 186,7 186,7 @@ class MediaModal extends ImmutablePureComponent {
src={image.get('url')}
width={width}
height={height}
- key={image.get('preview_url')}
+ key={image.get('url')}
alt={image.get('description')}
lang={language}
onClick={this.toggleNavigation}
M app/javascript/mastodon/locales/defaultMessages.json => app/javascript/mastodon/locales/defaultMessages.json +21 -0
@@ 3733,6 3733,10 @@
"id": "status.show_less_all"
},
{
+ "defaultMessage": "{user} posted {attachmentCount, plural, one {an attachment} other {{attachmentCount} attachments}}",
+ "id": "status.title.with_attachments"
+ },
+ {
"defaultMessage": "Detailed conversation view",
"id": "status.detailed_status"
},
@@ 4354,5 4358,22 @@
}
],
"path": "app/javascript/mastodon/features/video/index.json"
+ },
+ {
+ "descriptors": [
+ {
+ "defaultMessage": "That username is taken. Try another",
+ "id": "username.taken"
+ },
+ {
+ "defaultMessage": "Password confirmation exceeds the maximum password length",
+ "id": "password_confirmation.exceeds_maxlength"
+ },
+ {
+ "defaultMessage": "Password confirmation does not match",
+ "id": "password_confirmation.mismatching"
+ }
+ ],
+ "path": "app/javascript/packs/public.json"
}
]=
\ No newline at end of file
M app/javascript/mastodon/locales/en.json => app/javascript/mastodon/locales/en.json +4 -0
@@ 443,6 443,8 @@
"notifications_permission_banner.enable": "Enable desktop notifications",
"notifications_permission_banner.how_to_control": "To receive notifications when Mastodon isn't open, enable desktop notifications. You can control precisely which types of interactions generate desktop notifications through the {icon} button above once they're enabled.",
"notifications_permission_banner.title": "Never miss a thing",
+ "password_confirmation.exceeds_maxlength": "Password confirmation exceeds the maximum password length",
+ "password_confirmation.mismatching": "Password confirmation does not match",
"picture_in_picture.restore": "Put it back",
"poll.closed": "Closed",
"poll.refresh": "Refresh",
@@ 598,6 600,7 @@
"status.show_more": "Show more",
"status.show_more_all": "Show more for all",
"status.show_original": "Show original",
+ "status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {{attachmentCount} attachments}}",
"status.translate": "Translate",
"status.translated_from_with": "Translated from {lang} using {provider}",
"status.uncached_media_warning": "Not available",
@@ 650,6 653,7 @@
"upload_modal.preview_label": "Preview ({ratio})",
"upload_progress.label": "Uploading...",
"upload_progress.processing": "Processing…",
+ "username.taken": "That username is taken. Try another",
"video.close": "Close video",
"video.download": "Download file",
"video.exit_fullscreen": "Exit full screen",
M app/javascript/mastodon/locales/es-MX.json => app/javascript/mastodon/locales/es-MX.json +1 -0
@@ 597,6 597,7 @@
"status.show_more": "Mostrar más",
"status.show_more_all": "Mostrar más para todo",
"status.show_original": "Mostrar original",
+ "status.title.with_attachments": "{user} publicó {attachmentCount, plural, one {un archivo adjunto} other {{attachmentCount} archivos adjuntos}}",
"status.translate": "Traducir",
"status.translated_from_with": "Traducido del {lang} usando {provider}",
"status.uncached_media_warning": "No disponible",
M app/javascript/packs/public.jsx => app/javascript/packs/public.jsx +33 -17
@@ 4,6 4,15 @@ import ready from '../mastodon/ready';
import { start } from '../mastodon/common';
import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions';
import 'cocoon-js-vanilla';
+import axios from 'axios';
+import { throttle } from 'lodash';
+import { defineMessages } from 'react-intl';
+
+const messages = defineMessages({
+ usernameTaken: { id: 'username.taken', defaultMessage: 'That username is taken. Try another' },
+ passwordExceedsLength: { id: 'password_confirmation.exceeds_maxlength', defaultMessage: 'Password confirmation exceeds the maximum password length' },
+ passwordDoesNotMatch: { id: 'password_confirmation.mismatching', defaultMessage: 'Password confirmation does not match' },
+});
start();
@@ 13,7 22,7 @@ function main() {
const { delegate } = require('@rails/ujs');
const emojify = require('../mastodon/features/emoji/emoji').default;
const { getLocale } = require('../mastodon/locales');
- const { messages } = getLocale();
+ const { localeData } = getLocale();
const React = require('react');
const ReactDOM = require('react-dom');
const { createBrowserHistory } = require('history');
@@ 58,6 67,11 @@ function main() {
hour12: false,
});
+ const formatMessage = ({ id, defaultMessage }, values) => {
+ const messageFormat = new IntlMessageFormat(localeData[id] || defaultMessage, locale);
+ return messageFormat.format(values);
+ };
+
[].forEach.call(document.querySelectorAll('.emojify'), (content) => {
content.innerHTML = emojify(content.innerHTML);
});
@@ 77,7 91,7 @@ function main() {
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear();
};
- const todayFormat = new IntlMessageFormat(messages['relative_format.today'] || 'Today at {time}', locale);
+ const todayFormat = new IntlMessageFormat(localeData['relative_format.today'] || 'Today at {time}', locale);
[].forEach.call(document.querySelectorAll('time.relative-formatted'), (content) => {
const datetime = new Date(content.getAttribute('datetime'));
@@ 103,7 117,7 @@ function main() {
const timeGiven = content.getAttribute('datetime').includes('T');
content.title = timeGiven ? dateTimeFormat.format(datetime) : dateFormat.format(datetime);
content.textContent = timeAgoString({
- formatMessage: ({ id, defaultMessage }, values) => (new IntlMessageFormat(messages[id] || defaultMessage, locale)).format(values),
+ formatMessage,
formatDate: (date, options) => (new Intl.DateTimeFormat(locale, options)).format(date),
}, datetime, now, now.getFullYear(), timeGiven);
});
@@ 133,17 147,19 @@ function main() {
scrollToDetailedStatus();
}
- delegate(document, '#registration_user_password_confirmation,#registration_user_password', 'input', () => {
- const password = document.getElementById('registration_user_password');
- const confirmation = document.getElementById('registration_user_password_confirmation');
- if (confirmation.value && confirmation.value.length > password.maxLength) {
- confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.exceeds_maxlength'] || 'Password confirmation exceeds the maximum password length', locale)).format());
- } else if (password.value && password.value !== confirmation.value) {
- confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.mismatching'] || 'Password confirmation does not match', locale)).format());
+ delegate(document, '#user_account_attributes_username', 'input', throttle(() => {
+ const username = document.getElementById('user_account_attributes_username');
+
+ if (username.value && username.value.length > 0) {
+ axios.get('/api/v1/accounts/lookup', { params: { acct: username.value } }).then(() => {
+ username.setCustomValidity(formatMessage(messages.usernameTaken));
+ }).catch(() => {
+ username.setCustomValidity('');
+ });
} else {
- confirmation.setCustomValidity('');
+ username.setCustomValidity('');
}
- });
+ }, 500, { leading: false, trailing: true }));
delegate(document, '#user_password,#user_password_confirmation', 'input', () => {
const password = document.getElementById('user_password');
@@ 151,9 167,9 @@ function main() {
if (!confirmation) return;
if (confirmation.value && confirmation.value.length > password.maxLength) {
- confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.exceeds_maxlength'] || 'Password confirmation exceeds the maximum password length', locale)).format());
+ confirmation.setCustomValidity(formatMessage(messages.passwordExceedsLength));
} else if (password.value && password.value !== confirmation.value) {
- confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.mismatching'] || 'Password confirmation does not match', locale)).format());
+ confirmation.setCustomValidity(formatMessage(messages.passwordDoesNotMatch));
} else {
confirmation.setCustomValidity('');
}
@@ 167,10 183,10 @@ function main() {
if (statusEl.dataset.spoiler === 'expanded') {
statusEl.dataset.spoiler = 'folded';
- this.textContent = (new IntlMessageFormat(messages['status.show_more'] || 'Show more', locale)).format();
+ this.textContent = (new IntlMessageFormat(localeData['status.show_more'] || 'Show more', locale)).format();
} else {
statusEl.dataset.spoiler = 'expanded';
- this.textContent = (new IntlMessageFormat(messages['status.show_less'] || 'Show less', locale)).format();
+ this.textContent = (new IntlMessageFormat(localeData['status.show_less'] || 'Show less', locale)).format();
}
return false;
@@ 178,7 194,7 @@ function main() {
[].forEach.call(document.querySelectorAll('.status__content__spoiler-link'), (spoilerLink) => {
const statusEl = spoilerLink.parentNode.parentNode;
- const message = (statusEl.dataset.spoiler === 'expanded') ? (messages['status.show_less'] || 'Show less') : (messages['status.show_more'] || 'Show more');
+ const message = (statusEl.dataset.spoiler === 'expanded') ? (localeData['status.show_less'] || 'Show less') : (localeData['status.show_more'] || 'Show more');
spoilerLink.textContent = (new IntlMessageFormat(message, locale)).format();
});
});
M app/javascript/styles/mastodon/forms.scss => app/javascript/styles/mastodon/forms.scss +86 -0
@@ 1112,3 1112,89 @@ code {
white-space: nowrap;
}
}
+
+.progress-tracker {
+ display: flex;
+ align-items: center;
+ padding-bottom: 30px;
+ margin-bottom: 30px;
+
+ li {
+ flex: 0 0 auto;
+ position: relative;
+ }
+
+ .separator {
+ height: 2px;
+ background: $ui-base-lighter-color;
+ flex: 1 1 auto;
+
+ &.completed {
+ background: $highlight-text-color;
+ }
+ }
+
+ .circle {
+ box-sizing: border-box;
+ position: relative;
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ border: 2px solid $ui-base-lighter-color;
+ flex: 0 0 auto;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ svg {
+ width: 16px;
+ }
+ }
+
+ .label {
+ position: absolute;
+ font-size: 14px;
+ font-weight: 500;
+ color: $secondary-text-color;
+ padding-top: 10px;
+ text-align: center;
+ width: 100px;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+
+ li:first-child .label {
+ left: auto;
+ inset-inline-start: 0;
+ text-align: start;
+ transform: none;
+ }
+
+ li:last-child .label {
+ left: auto;
+ inset-inline-end: 0;
+ text-align: end;
+ transform: none;
+ }
+
+ .active .circle {
+ border-color: $highlight-text-color;
+
+ &::before {
+ content: '';
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ background: $highlight-text-color;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ }
+ }
+
+ .completed .circle {
+ border-color: $highlight-text-color;
+ background: $highlight-text-color;
+ }
+}
M app/mailers/notification_mailer.rb => app/mailers/notification_mailer.rb +5 -5
@@ 14,7 14,7 @@ class NotificationMailer < ApplicationMailer
locale_for_account(@me) do
thread_by_conversation(@status.conversation)
- mail to: @me.user.email, subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct)
+ mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct)
end
end
@@ 25,7 25,7 @@ class NotificationMailer < ApplicationMailer
return unless @me.user.functional?
locale_for_account(@me) do
- mail to: @me.user.email, subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)
+ mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)
end
end
@@ 38,7 38,7 @@ class NotificationMailer < ApplicationMailer
locale_for_account(@me) do
thread_by_conversation(@status.conversation)
- mail to: @me.user.email, subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct)
+ mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct)
end
end
@@ 51,7 51,7 @@ class NotificationMailer < ApplicationMailer
locale_for_account(@me) do
thread_by_conversation(@status.conversation)
- mail to: @me.user.email, subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct)
+ mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct)
end
end
@@ 62,7 62,7 @@ class NotificationMailer < ApplicationMailer
return unless @me.user.functional?
locale_for_account(@me) do
- mail to: @me.user.email, subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)
+ mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)
end
end
M app/models/account_filter.rb => app/models/account_filter.rb +1 -1
@@ 55,7 55,7 @@ class AccountFilter
when 'by_domain'
Account.where(domain: value.to_s.strip)
when 'username'
- Account.matches_username(value.to_s.strip)
+ Account.matches_username(value.to_s.strip.delete_prefix('@'))
when 'display_name'
Account.matches_display_name(value.to_s.strip)
when 'email'
M app/models/preview_card_provider.rb => app/models/preview_card_provider.rb +1 -0
@@ 18,6 18,7 @@
#
class PreviewCardProvider < ApplicationRecord
+ include Paginable
include DomainNormalizable
include Attachmentable
A app/serializers/rest/admin/trends/link_serializer.rb => app/serializers/rest/admin/trends/link_serializer.rb +9 -0
@@ 0,0 1,9 @@
+# frozen_string_literal: true
+
+class REST::Admin::Trends::LinkSerializer < REST::Trends::LinkSerializer
+ attributes :id, :requires_review
+
+ def requires_review
+ object.requires_review?
+ end
+end
A app/serializers/rest/admin/trends/links/preview_card_provider_serializer.rb => app/serializers/rest/admin/trends/links/preview_card_provider_serializer.rb +10 -0
@@ 0,0 1,10 @@
+# frozen_string_literal: true
+
+class REST::Admin::Trends::Links::PreviewCardProviderSerializer < ActiveModel::Serializer
+ attributes :id, :domain, :trendable, :reviewed_at,
+ :requested_review_at, :requires_review
+
+ def requires_review
+ object.requires_review?
+ end
+end
A app/serializers/rest/admin/trends/status_serializer.rb => app/serializers/rest/admin/trends/status_serializer.rb +9 -0
@@ 0,0 1,9 @@
+# frozen_string_literal: true
+
+class REST::Admin::Trends::StatusSerializer < REST::StatusSerializer
+ attributes :requires_review
+
+ def requires_review
+ object.requires_review?
+ end
+end
M app/services/notify_service.rb => app/services/notify_service.rb +1 -0
@@ 7,6 7,7 @@ class NotifyService < BaseService
admin.report
admin.sign_up
update
+ poll
).freeze
def call(recipient, type, activity)
M app/views/auth/registrations/new.html.haml => app/views/auth/registrations/new.html.haml +6 -2
@@ 5,6 5,8 @@
= render partial: 'shared/og', locals: { description: description_for_sign_up }
= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { novalidate: false }) do |f|
+ = render 'auth/shared/progress', stage: 'details'
+
%h1.title= t('auth.sign_up.title', domain: site_hostname)
%p.lead= t('auth.sign_up.preamble')
@@ 18,7 20,7 @@
.fields-group
= f.simple_fields_for :account do |ff|
= ff.input :display_name, wrapper: :with_label, label: false, required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.display_name'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.display_name') }
- = ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false
+ = ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}"
= f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'username' }, hint: false
= f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: false
= f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_password'), autocomplete: 'new-password' }, hint: false
@@ 26,9 28,11 @@
= f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' }
- if approved_registrations? && !@invite.present?
+ %p.lead= t('auth.sign_up.manual_review', domain: site_hostname)
+
.fields-group
= 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
+ = 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]
M app/views/auth/registrations/rules.html.haml => app/views/auth/registrations/rules.html.haml +2 -0
@@ 5,6 5,8 @@
= render partial: 'shared/og', locals: { description: description_for_sign_up }
.simple_form
+ = render 'auth/shared/progress', stage: 'rules'
+
%h1.title= t('auth.rules.title')
%p.lead= t('auth.rules.preamble', domain: site_hostname)
M app/views/auth/setup/show.html.haml => app/views/auth/setup/show.html.haml +14 -12
@@ 1,20 1,22 @@
- content_for :page_title do
= t('auth.setup.title')
-- if missing_email?
- = simple_form_for(@user, url: auth_setup_path) do |f|
- = render 'shared/error_messages', object: @user
+= simple_form_for(@user, url: auth_setup_path) do |f|
+ = render 'auth/shared/progress', stage: 'confirm'
- .fields-group
- %p.hint= t('auth.setup.email_below_hint_html')
+ %h1.title= t('auth.setup.title')
+ %p.lead= t('auth.setup.email_settings_hint_html', email: content_tag(:strong, @user.email))
- .fields-group
- = f.input :email, required: true, hint: false, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' }
+ = render 'shared/error_messages', object: @user
- .actions
- = f.submit t('admin.accounts.change_email.label'), class: 'button'
-- else
- .simple_form
- %p.hint= t('auth.setup.email_settings_hint_html', email: content_tag(:strong, @user.email))
+ %p.lead
+ %strong= t('auth.setup.link_not_received')
+ %p.lead= t('auth.setup.email_below_hint_html')
+
+ .fields-group
+ = f.input :email, required: true, hint: false, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' }
+
+ .actions
+ = f.submit t('auth.resend_confirmation'), class: 'button'
.form-footer= render 'auth/shared/links'
M app/views/auth/shared/_links.html.haml => app/views/auth/shared/_links.html.haml +1 -1
@@ 14,5 14,5 @@
- if controller_name != 'confirmations' && (!user_signed_in? || !current_user.confirmed? || current_user.unconfirmed_email.present?)
%li= link_to t('auth.didnt_get_confirmation'), new_user_confirmation_path
- - if user_signed_in? && controller_name != 'setup'
+ - if user_signed_in?
%li= link_to t('auth.logout'), destroy_user_session_path, data: { method: :delete }
A app/views/auth/shared/_progress.html.haml => app/views/auth/shared/_progress.html.haml +25 -0
@@ 0,0 1,25 @@
+- progress_index = { rules: 0, details: 1, confirm: 2 }[stage.to_sym]
+
+%ol.progress-tracker
+ %li{ class: progress_index.positive? ? 'completed' : 'active' }
+ .circle
+ - if progress_index.positive?
+ = check_icon
+ .label= t('auth.progress.rules')
+ %li.separator{ class: progress_index.positive? ? 'completed' : nil }
+ %li{ class: [progress_index > 1 && 'completed', progress_index == 1 && 'active'] }
+ .circle
+ - if progress_index > 1
+ = check_icon
+ .label= t('auth.progress.details')
+ %li.separator{ class: progress_index > 1 ? 'completed' : nil }
+ %li{ class: [progress_index > 2 && 'completed', progress_index == 2 && 'active'] }
+ .circle
+ - if progress_index > 2
+ = check_icon
+ .label= t('auth.progress.confirm')
+ - if approved_registrations?
+ %li.separator{ class: progress_index > 2 ? 'completed' : nil }
+ %li
+ .circle
+ .label= t('auth.progress.review')
M config/locales/en.yml => config/locales/en.yml +15 -7
@@ 125,8 125,8 @@ en:
removed_header_msg: Successfully removed %{username}'s header image
resend_confirmation:
already_confirmed: This user is already confirmed
- send: Resend confirmation email
- success: Confirmation email successfully sent!
+ send: Resend confirmation link
+ success: Confirmation link successfully sent!
reset: Reset
reset_password: Reset password
resubscribe: Resubscribe
@@ 988,7 988,7 @@ en:
prefix_invited_by_user: "@%{name} invites you to join this server of Mastodon!"
prefix_sign_up: Sign up on Mastodon today!
suffix: With an account, you will be able to follow people, post updates and exchange messages with users from any Mastodon server and more!
- didnt_get_confirmation: Didn't receive confirmation instructions?
+ didnt_get_confirmation: Didn't receive a confirmation link?
dont_have_your_security_key: Don't have your security key?
forgot_password: Forgot your password?
invalid_reset_password_token: Password reset token is invalid or expired. Please request a new one.
@@ 1001,12 1001,17 @@ en:
migrate_account_html: If you wish to redirect this account to a different one, you can <a href="%{path}">configure it here</a>.
or_log_in_with: Or log in with
privacy_policy_agreement_html: I have read and agree to the <a href="%{privacy_policy_path}" target="_blank">privacy policy</a>
+ progress:
+ confirm: Confirm e-mail
+ details: Your details
+ review: Our review
+ rules: Accept rules
providers:
cas: CAS
saml: SAML
register: Sign up
registration_closed: "%{instance} is not accepting new members"
- resend_confirmation: Resend confirmation instructions
+ resend_confirmation: Resend confirmation link
reset_password: Reset password
rules:
accept: Accept
@@ 1016,13 1021,16 @@ en:
security: Security
set_new_password: Set new password
setup:
- email_below_hint_html: If the below e-mail address is incorrect, you can change it here and receive a new confirmation e-mail.
- email_settings_hint_html: The confirmation e-mail was sent to %{email}. If that e-mail address is not correct, you can change it in account settings.
- title: Setup
+ email_below_hint_html: Check your spam folder, or request another one. You can correct your e-mail address if it's wrong.
+ email_settings_hint_html: Click the link we sent you to verify %{email}. We'll wait right here.
+ link_not_received: Didn't get a link?
+ new_confirmation_instructions_sent: You will receive a new e-mail with the confirmation link in a few minutes!
+ title: Check your inbox
sign_in:
preamble_html: Sign in with your <strong>%{domain}</strong> credentials. If your account is hosted on a different server, you will not be able to log in here.
title: Sign in to %{domain}
sign_up:
+ manual_review: Sign-ups on %{domain} go through manual review by our moderators. To help us process your registration, write a bit about yourself and why you want an account on %{domain}.
preamble: With an account on this Mastodon server, you'll be able to follow any other person on the network, regardless of where their account is hosted.
title: Let's get you set up on %{domain}.
status:
M config/locales/simple_form.an.yml => config/locales/simple_form.an.yml +0 -1
@@ 59,7 59,6 @@ an:
setting_show_application: L'aplicación que utiliza vusté pa publicar publicacions s'amostrará en a vista detallada d'as suyas publicacions
setting_use_blurhash: Los gradientes se basan en as colors d'as imachens amagadas pero fendo borrosos los detalles
setting_use_pending_items: Amagar nuevos estaus dezaga d'un clic en cuenta de desplazar automaticament lo feed
- username: Lo tuyo nombre d'usuario será solo en %{domain}
whole_word: Quan la parola clau u frase ye nomás alfanumerica, nomás será aplicau si concuerda con tota la parola
domain_allow:
domain: Este dominio podrá obtener datos d'este servidor y los datos dentrants serán procesaus y archivados
M config/locales/simple_form.ar.yml => config/locales/simple_form.ar.yml +0 -1
@@ 59,7 59,6 @@ ar:
setting_show_application: سيُعرَض اسم التطبيق الذي تستخدمه عند النشر في العرض المفصّل لمنشوراتك
setting_use_blurhash: الألوان التدرّجية مبنية على ألوان المرئيات المخفية ولكنها تحجب كافة التفاصيل
setting_use_pending_items: إخفاء تحديثات الخط وراء نقرة بدلًا مِن التمرير التلقائي للتدفق
- username: اسم المستخدم الخاص بك سوف يكون فريدا مِن نوعه على %{domain}
whole_word: إذا كانت الكلمة أو العبارة مكونة من أرقام وحروف فقط سوف يتم تطبيقها فقط عند مطابقة الكلمة ككل
domain_allow:
domain: سيكون بإمكان هذا النطاق جلب البيانات من هذا الخادم ومعالجة وتخزين البيانات الواردة منه
M config/locales/simple_form.ast.yml => config/locales/simple_form.ast.yml +0 -1
@@ 35,7 35,6 @@ ast:
setting_noindex: Afeuta al perfil públicu ya a les páxines de los artículos
setting_show_application: L'aplicación qu'uses pa espublizar apaez na vista detallada de los tos artículos
setting_use_blurhash: Los dilíos básense nos colores del conteníu multimedia anubríu mas desenfonca los detalles
- username: 'El nome d''usuariu va ser únicu en: %{domain}'
featured_tag:
name: 'Equí tán dalgunes de les etiquetes qu''usesti apocayá:'
form_admin_settings:
M config/locales/simple_form.be.yml => config/locales/simple_form.be.yml +0 -1
@@ 59,7 59,6 @@ be:
setting_show_application: Праграма, праз якую вы ствараеце допісы, будзе паказвацца ў падрабязнасцях пра допісы
setting_use_blurhash: Градыенты заснаваны на колерах схаваных выяў, але размываюць дэталі
setting_use_pending_items: Схаваць абнаўленні стужкі за клікам замест аўтаматычнага пракручвання стужкі
- username: Ваша імя карыстальніка будзе ўнікальным на %{domain}
whole_word: Калі ключавое слова ці фраза складаецца толькі з літар і лічбаў, яно будзе ўжытае толькі калі супадае з усім словам
domain_allow:
domain: Гэты дамен зможа атрымліваць даныя з гэтага сервера. Даныя з гэтага дамену будуць апрацаваныя ды захаваныя
M config/locales/simple_form.bg.yml => config/locales/simple_form.bg.yml +0 -1
@@ 59,7 59,6 @@ bg:
setting_show_application: Приложението, което ползвате за публикуване, ще се показва в подробностите на публикацията ви
setting_use_blurhash: Преливането е въз основа на цветовете на скритите визуализации, но се замъгляват подробностите
setting_use_pending_items: Да се показват обновявания на часовата ос само след щракване вместо автоматично превъртане на инфоканала
- username: Вашето потребителско име ще е неповторимо в %{domain}
whole_word: Ако ключовата дума или фраза е само буквеноцифрена, то ще се приложи само, ако съвпадне с цялата дума
domain_allow:
domain: Домейнът ще може да извлича данни от този сървър и входящите данни от него ще се обработят и съхранят
M config/locales/simple_form.ca.yml => config/locales/simple_form.ca.yml +0 -1
@@ 59,7 59,6 @@ ca:
setting_show_application: L'aplicació que fas servir per a publicar es mostrarà a la vista detallada dels teus tuts
setting_use_blurhash: Els degradats es basen en els colors de les imatges ocultes, però n'enfosqueixen els detalls
setting_use_pending_items: Amaga les actualitzacions de la línia de temps després de fer un clic, en lloc de desplaçar-les automàticament
- username: El teu nom d'usuari serà únic a %{domain}
whole_word: Quan la paraula clau o la frase sigui només alfanumèrica, s'aplicarà si coincideix amb la paraula sencera
domain_allow:
domain: Aquest domini podrà obtenir dades d’aquest servidor i les dades entrants d’aquests seran processades i emmagatzemades
M config/locales/simple_form.ckb.yml => config/locales/simple_form.ckb.yml +0 -1
@@ 51,7 51,6 @@ ckb:
setting_show_application: بەرنامەیەک کە بە یارمەتیت توت دەکەیت، لە دیمەنی وردی توتەکان پیشان دەدرێت
setting_use_blurhash: سێبەرەکان لە سەر بنەمای ڕەنگەکانی بەکارهاتوو لە وێنە داشاراوەکان دروست دەبن بەڵام وردەزانیاری وێنە تێیدا ڕوون نییە
setting_use_pending_items: لەجیاتی ئەوەی بە خۆکارانە کێشان هەبێت لە نووسراوەکان بە کرتەیەک بەڕۆژبوونی پێرستی نووسراوەکان بشارەوە
- username: ناوی بەکارهێنەری ئێوە لەسەر %{domain} یەکتا دەبێت
whole_word: کاتێک کلیلوشە بریتییە لە ژمارە و پیت، تنەها کاتێک پەیدا دەبێت کە لەگەڵ گشتی وشە لە نێو دەقەکە هاوئاهەنگ بێت، نە تەنها لەگەڵ بەشێک لە وشە
domain_allow:
domain: ئەم دۆمەینە دەتوانێت دراوە لە ئەم ڕاژە وەربگرێت و دراوەی ئەم دۆمەینە لێرە ڕێکدەخرین و پاشکەوت دەکرێن
M config/locales/simple_form.co.yml => config/locales/simple_form.co.yml +0 -1
@@ 49,7 49,6 @@ co:
setting_show_application: L'applicazione chì voi utilizate per mandà statuti sarà affissata indè a vista ditagliata di quelli
setting_use_blurhash: I digradati blurhash sò basati nant'à i culori di u ritrattu piattatu ma senza i ditagli
setting_use_pending_items: Clicchi per messe à ghjornu i statuti invece di fà sfilà a linea autumaticamente
- username: U vostru cugnome sarà unicu nant'à %{domain}
whole_word: Quandu a parolla o a frasa sana hè alfanumerica, sarà applicata solu s'ella currisponde à a parolla sana
domain_allow:
domain: Stu duminiu puderà ricuperà i dati di stu servore è i dati ch'affaccanu da quallà saranu trattati è cunservati
M config/locales/simple_form.cs.yml => config/locales/simple_form.cs.yml +0 -1
@@ 59,7 59,6 @@ cs:
setting_show_application: Aplikace, kterou používáte k odeslání příspěvků, bude zobrazena jejich detailním zobrazení
setting_use_blurhash: Gradienty jsou založeny na barvách skryté grafiky, ale zakrývají jakékoliv detaily
setting_use_pending_items: Aktualizovat časovou osu až po kliknutí namísto automatického rolování kanálu
- username: Vaše uživatelské jméno bude na serveru %{domain} unikátní
whole_word: Je-li klíčové slovo či fráze pouze alfanumerická, bude aplikován pouze, pokud se shoduje s celým slovem
domain_allow:
domain: Tato doména bude moci stahovat data z tohoto serveru a příchozí data z ní budou zpracována a uložena
M config/locales/simple_form.cy.yml => config/locales/simple_form.cy.yml +0 -1
@@ 59,7 59,6 @@ cy:
setting_show_application: Bydd y cymhwysiad a ddefnyddiwch i bostio yn cael ei arddangos yng ngolwg fanwl eich postiadau
setting_use_blurhash: Mae graddiannau wedi'u seilio ar liwiau'r delweddau cudd ond maen nhw'n cuddio unrhyw fanylion
setting_use_pending_items: Cuddio diweddariadau llinell amser y tu ôl i glic yn lle sgrolio'n awtomatig
- username: Bydd eich enw defnyddiwr yn unigryw ar %{domain}
whole_word: Os yw'r allweddair neu'r ymadrodd yn alffaniwmerig yn unig, mi fydd ond yn cael ei osod os yw'n cyfateb a'r gair cyfan
domain_allow:
domain: Bydd y parth hwn yn gallu nôl data o'r gweinydd hwn a bydd data sy'n dod i mewn ohono yn cael ei brosesu a'i storio
M config/locales/simple_form.da.yml => config/locales/simple_form.da.yml +0 -1
@@ 59,7 59,6 @@ da:
setting_show_application: Applikationen, hvormed der postes, vil fremgå af detailvisningen af dine indlæg
setting_use_blurhash: Gradienter er baseret på de skjulte grafikelementers farver, men slører alle detaljer
setting_use_pending_items: Skjul tidslinjeopdateringer bag et klik i stedet for brug af auto-feedrulning
- username: Dit brugernavn vil være unikt på %{domain}
whole_word: Ved rent alfanumeriske nøgleord/-sætning, forudsætter brugen matchning af hele ordet
domain_allow:
domain: Dette domæne vil kunne hente data, som efterfølgende behandles og gemmes, fra denne server
M config/locales/simple_form.de.yml => config/locales/simple_form.de.yml +0 -1
@@ 59,7 59,6 @@ de:
setting_show_application: Die Anwendung die du nutzt wird in der detaillierten Ansicht deiner Beiträge angezeigt
setting_use_blurhash: Die Farbverläufe basieren auf den Farben der verborgenen Medien, verschleiern aber jegliche Details
setting_use_pending_items: Neue Beiträge hinter einem Klick verstecken, anstatt des automatischen Bildlaufs
- username: Dein Profilname wird auf %{domain} einmalig sein
whole_word: Wenn das Wort oder die Formulierung nur aus Buchstaben oder Zahlen besteht, tritt der Filter nur dann in Kraft, wenn er exakt dieser Zeichenfolge entspricht
domain_allow:
domain: Diese Domain kann Daten von diesem Server abrufen, und eingehende Daten werden verarbeitet und gespeichert
M config/locales/simple_form.el.yml => config/locales/simple_form.el.yml +0 -1
@@ 59,7 59,6 @@ el:
setting_show_application: Η εφαρμογή που χρησιμοποιείς για να στέλνεις τα τουτ σου θα εμφανίζεται στις αναλυτικές λεπτομέρειες τους
setting_use_blurhash: Οι χρωματισμοί βασίζονται στα χρώματα του κρυμμένου πολυμέσου αλλά θολώνουν τις λεπτομέρειες
setting_use_pending_items: Εμφάνιση ενημερώσεων ροής μετά από κλικ αντί για αυτόματη κύλισή τους
- username: Το όνομα χρήστη σου θα είναι μοναδικό στο %{domain}
whole_word: Όταν η λέξη ή η φράση κλειδί είναι μόνο αλφαριθμητική, θα εφαρμοστεί μόνο αν ταιριάζει με ολόκληρη τη λέξη
domain_allow:
domain: Ο τομέας αυτός θα επιτρέπεται να ανακτά δεδομένα από αυτό τον διακομιστή και τα εισερχόμενα δεδομένα θα επεξεργάζονται και θα αποθηκεύονται
M config/locales/simple_form.en-GB.yml => config/locales/simple_form.en-GB.yml +0 -1
@@ 59,7 59,6 @@ en-GB:
setting_show_application: The application you use to post will be displayed in the detailed view of your posts
setting_use_blurhash: Gradients are based on the colors of the hidden visuals but obfuscate any details
setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed
- username: Your username will be unique on %{domain}
whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word
domain_allow:
domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored
M config/locales/simple_form.en.yml => config/locales/simple_form.en.yml +1 -1
@@ 59,7 59,7 @@ en:
setting_show_application: The application you use to post will be displayed in the detailed view of your posts
setting_use_blurhash: Gradients are based on the colors of the hidden visuals but obfuscate any details
setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed
- username: Your username will be unique on %{domain}
+ username: You can use letters, numbers, and underscores
whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word
domain_allow:
domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored
M config/locales/simple_form.eo.yml => config/locales/simple_form.eo.yml +0 -1
@@ 59,7 59,6 @@ eo:
setting_show_application: La aplikaĵo, kiun vi uzas por afiŝi, estos montrita en la detala vido de viaj afiŝoj
setting_use_blurhash: Transirojn estas bazita sur la koloroj de la kaŝitaj aŭdovidaĵoj sed ne montri iun ajn detalon
setting_use_pending_items: Kaŝi tempoliniajn ĝisdatigojn malantaŭ klako anstataŭ aŭtomate rulumi la fluon
- username: Via uzantnomo estos unika en %{domain}
whole_word: Kiam la vorto aŭ frazo estas nur litera aŭ cifera, ĝi estos uzata nur se ĝi kongruas kun la tuta vorto
domain_allow:
domain: Ĉi tiu domajno povos akiri datumon de ĉi tiu servilo kaj envenanta datumo estos prilaborita kaj konservita
M config/locales/simple_form.es-AR.yml => config/locales/simple_form.es-AR.yml +0 -1
@@ 59,7 59,6 @@ es-AR:
setting_show_application: La aplicación que usás para enviar mensajes se mostrará en la vista detallada de tus mensajes
setting_use_blurhash: Los gradientes se basan en los colores de las imágenes ocultas pero haciendo borrosos los detalles
setting_use_pending_items: Ocultar actualizaciones de la línea temporal detrás de un clic en lugar de desplazar automáticamente el flujo
- username: Tu nombre de usuario será único en %{domain}
whole_word: Cuando la palabra clave o frase es sólo alfanumérica, sólo será aplicado si coincide con toda la palabra
domain_allow:
domain: Este dominio podrá recolectar datos de este servidor, y los datos entrantes serán procesados y archivados
M config/locales/simple_form.es-MX.yml => config/locales/simple_form.es-MX.yml +0 -1
@@ 59,7 59,6 @@ es-MX:
setting_show_application: La aplicación que utiliza usted para publicar toots se mostrará en la vista detallada de sus toots
setting_use_blurhash: Los gradientes se basan en los colores de las imágenes ocultas pero haciendo borrosos los detalles
setting_use_pending_items: Ocultar nuevos estados detrás de un clic en lugar de desplazar automáticamente el feed
- username: Tu nombre de usuario será único en %{domain}
whole_word: Cuando la palabra clave o frase es solo alfanumérica, solo será aplicado si concuerda con toda la palabra
domain_allow:
domain: Este dominio podrá obtener datos de este servidor y los datos entrantes serán procesados y archivados
M config/locales/simple_form.es.yml => config/locales/simple_form.es.yml +0 -1
@@ 59,7 59,6 @@ es:
setting_show_application: La aplicación que utiliza usted para publicar publicaciones se mostrará en la vista detallada de sus publicaciones
setting_use_blurhash: Los gradientes se basan en los colores de las imágenes ocultas pero haciendo borrosos los detalles
setting_use_pending_items: Ocultar nuevos estados detrás de un clic en lugar de desplazar automáticamente el feed
- username: Tu nombre de usuario será único en %{domain}
whole_word: Cuando la palabra clave o frase es solo alfanumérica, solo será aplicado si concuerda con toda la palabra
domain_allow:
domain: Este dominio podrá obtener datos de este servidor y los datos entrantes serán procesados y archivados
M config/locales/simple_form.et.yml => config/locales/simple_form.et.yml +0 -1
@@ 59,7 59,6 @@ et:
setting_show_application: Postitamiseks kasutatud rakenduse infot kuvatakse postituse üksikasjavaates
setting_use_blurhash: Värvid põhinevad peidetud visuaalidel, kuid hägustavad igasuguseid detaile
setting_use_pending_items: Voo automaatse kerimise asemel peida ajajoone uuendused kliki taha
- username: Sinu kasutajanimi on %{domain}-il unikaalne
whole_word: Kui võtmesõna või fraas on ainult tähtnumbriline, rakendub see ainult siis, kui see kattub terve sõnaga
domain_allow:
domain: See domeen saab tõmmata andmeid sellelt serverilt ning sissetulevad andmed sellelt domeenilt töödeldakse ning salvestatakse
M config/locales/simple_form.eu.yml => config/locales/simple_form.eu.yml +0 -1
@@ 59,7 59,6 @@ eu:
setting_show_application: Tootak bidaltzeko erabiltzen duzun aplikazioa zure tooten ikuspegi xehetsuan bistaratuko da
setting_use_blurhash: Gradienteak ezkutatutakoaren koloreetan oinarritzen dira, baina xehetasunak ezkutatzen dituzte
setting_use_pending_items: Ezkutatu denbora-lerroko eguneraketak klik baten atzean jarioa automatikoki korritu ordez
- username: Zure erabiltzaile-izena bakana izango da %{domain} domeinuan
whole_word: Hitz eta esaldi gakoa alfanumerikoa denean, hitz osoarekin bat datorrenean besterik ez da aplikatuko
domain_allow:
domain: Domeinu honek zerbitzari honetatik datuak hartu ahal izango ditu eta bertatik jasotako informazioa prozesatu eta gordeko da
M config/locales/simple_form.fa.yml => config/locales/simple_form.fa.yml +0 -1
@@ 59,7 59,6 @@ fa:
setting_show_application: برنامهای که به کمک آن فرسته میزنید، در جزئیات فرسته شما نمایش خواهد یافت
setting_use_blurhash: سایهها بر اساس رنگهای بهکاررفته در تصویر پنهانشده ساخته میشوند ولی جزئیات تصویر در آنها آشکار نیست
setting_use_pending_items: به جای پیشرفتن خودکار در فهرست، بهروزرسانی فهرست نوشتهها را پشت یک کلیک پنهان کن
- username: نام کاربری شما روی %{domain} یکتا خواهد بود
whole_word: اگر کلیدواژه فقط دارای حروف و اعداد باشد، تنها وقتی پیدا میشود که با کل یک واژه در متن منطبق باشد، نه با بخشی از یک واژه
domain_allow:
domain: این دامین خواهد توانست دادهها از این سرور را دریافت کند و دادههای از این دامین در اینجا پردازش و ذخیره خواهند شد
M config/locales/simple_form.fi.yml => config/locales/simple_form.fi.yml +0 -1
@@ 59,7 59,6 @@ fi:
setting_show_application: Viestittelyyn käyttämäsi sovellus näkyy viestiesi yksityiskohtaisessa näkymässä
setting_use_blurhash: Liukuvärit perustuvat piilotettujen kuvien väreihin, mutta sumentavat yksityiskohdat
setting_use_pending_items: Piilota aikajanan päivitykset napsautuksen taakse sen sijaan, että vierittäisi syötettä automaattisesti
- username: Käyttäjänimesi tulee olemaan yksilöllinen %{domain}
whole_word: Kun avainsana tai lause on vain aakkosnumeerinen, se otetaan käyttöön, jos se vastaa koko sanaa
domain_allow:
domain: Tämä verkkotunnus voi noutaa tietoja tältä palvelimelta ja sieltä saapuvat tiedot käsitellään ja tallennetaan
M config/locales/simple_form.fo.yml => config/locales/simple_form.fo.yml +0 -1
@@ 59,7 59,6 @@ fo:
setting_show_application: Nýtsluskipanin, sum tú brúkar at posta við, verður víst í nágreinligu vísingini av postum tínum
setting_use_blurhash: Gradientar eru grundaðir á litirnar av fjaldu myndunum, men grugga allar smálutir
setting_use_pending_items: Fjal tíðarlinjudagføringar aftan fyri eitt klikk heldur enn at skrulla tilføringina sjálvvirkandi
- username: Brúkaranavnið hjá tær verður eindømi á %{domain}
whole_word: Tá lyklaorðið ella frasan einans hevur bókstavir og tøl, so verður hon einans nýtt, um tú samsvarar við alt orðið
domain_allow:
domain: Økisnavnið kann heinta dátur frá hesum ambætaranum og inngangandi dátur frá honum verða viðgjørdar og goymdar
M config/locales/simple_form.fr-QC.yml => config/locales/simple_form.fr-QC.yml +0 -1
@@ 59,7 59,6 @@ fr-QC:
setting_show_application: Le nom de l’application que vous utilisez pour publier sera affichée dans la vue détaillée de vos messages
setting_use_blurhash: Les dégradés sont basés sur les couleurs des images cachées mais n’en montrent pas les détails
setting_use_pending_items: Cacher les mises à jour des fils d’actualités derrière un clic, au lieu de les afficher automatiquement
- username: Votre nom d’utilisateur sera unique sur %{domain}
whole_word: Si le mot-clé ou la phrase est alphanumérique, alors le filtre ne sera appliqué que s’il correspond au mot entier
domain_allow:
domain: Ce domaine pourra récupérer des données de ce serveur et les données entrantes seront traitées et stockées
M config/locales/simple_form.fr.yml => config/locales/simple_form.fr.yml +0 -1
@@ 59,7 59,6 @@ fr:
setting_show_application: Le nom de l’application que vous utilisez pour publier sera affichée dans la vue détaillée de vos messages
setting_use_blurhash: Les dégradés sont basés sur les couleurs des images cachées mais n’en montrent pas les détails
setting_use_pending_items: Cacher les mises à jour des fils d’actualités derrière un clic, au lieu de les afficher automatiquement
- username: Votre identifiant sera unique sur %{domain}
whole_word: Si le mot-clé ou la phrase est alphanumérique, alors le filtre ne sera appliqué que s’il correspond au mot entier
domain_allow:
domain: Ce domaine pourra récupérer des données de ce serveur et les données entrantes seront traitées et stockées
M config/locales/simple_form.fy.yml => config/locales/simple_form.fy.yml +0 -1
@@ 59,7 59,6 @@ fy:
setting_show_application: De tapassing dy’t jo brûke om berjochten te pleatsen, wurdt yn de detaillearre werjefte fan it berjocht toand
setting_use_blurhash: Dizige kleuroergongen binne basearre op de kleuren fan de ferstoppe media, wêrmei elk detail ferdwynt
setting_use_pending_items: De tiidline wurdt bywurke troch op it oantal nije items te klikken, yn stee fan dat dizze automatysk bywurke wurdt
- username: Jo brûkersnamme is unyk op %{domain}
whole_word: Wannear it trefwurd of part fan de sin alfanumeryk is, wurdt it allinnich filtere wannear’t it hiele wurd oerienkomt
domain_allow:
domain: Dit domein is yn steat om gegevens fan dizze server op te heljen, en ynkommende gegevens wurde ferwurke en bewarre
M config/locales/simple_form.gd.yml => config/locales/simple_form.gd.yml +0 -1
@@ 59,7 59,6 @@ gd:
setting_show_application: Chithear cò an aplacaid a chleachd thu airson post a sgrìobhadh ann an seallaidhean mionaideach nam postaichean agad
setting_use_blurhash: Tha caiseadan stèidhichte air dathan nan nithean lèirsinneach a chaidh fhalach ach chan fhaicear am mion-fhiosrachadh
setting_use_pending_items: Falaich ùrachaidhean na loidhne-ama air cùlaibh briogaidh seach a bhith a’ sgroladh nam postaichean gu fèin-obrachail
- username: Bidh ainm-cleachdaiche àraidh agad air %{domain}
whole_word: Mur eil ach litrichean is àireamhan san fhacal-luirg, cha dèid a chur an sàs ach ma bhios e a’ maidseadh an fhacail shlàin
domain_allow:
domain: "’S urrainn dhan àrainn seo dàta fhaighinn on fhrithealaiche seo agus thèid an dàta a thig a-steach uaithe a phròiseasadh ’s a stòradh"
M config/locales/simple_form.gl.yml => config/locales/simple_form.gl.yml +0 -1
@@ 59,7 59,6 @@ gl:
setting_show_application: A aplicación que estás a utilizar para enviar publicacións mostrarase na vista detallada da publicación
setting_use_blurhash: Os gradientes toman as cores da imaxe oculta pero esvaecendo tódolos detalles
setting_use_pending_items: Agochar actualizacións da cronoloxía tras un click no lugar de desprazar automáticamente os comentarios
- username: O teu nome de usuaria será único en %{domain}
whole_word: Se a chave ou frase de paso é só alfanumérica, só se aplicará se concorda a palabra completa
domain_allow:
domain: Este dominio estará en disposición de obter datos desde este servidor e datos de entrada a el poderán ser procesados e gardados
M config/locales/simple_form.he.yml => config/locales/simple_form.he.yml +0 -1
@@ 59,7 59,6 @@ he:
setting_show_application: היישום בו נעשה שימוש כדי לחצרץ יופיע בתצוגה המפורטת של החצרוץ
setting_use_blurhash: הגראדיינטים מבוססים על תוכן התמונה המוסתרת, אבל מסתירים את כל הפרטים
setting_use_pending_items: הסתר עדכוני פיד מאחורי קליק במקום לגלול את הפיד אוטומטית
- username: שם המשתמש שלך יהיה ייחודי ב- %{domain}
whole_word: אם מילת מפתח או ביטוי הם אלפאנומריים בלבד, הם יופעלו רק אם נמצאה התאמה למילה שלמה
domain_allow:
domain: דומיין זה יוכל לייבא מידע משרת זה והמידע המגיע ממנו יעובד ויאופסן
M config/locales/simple_form.hu.yml => config/locales/simple_form.hu.yml +0 -1
@@ 59,7 59,6 @@ hu:
setting_show_application: A bejegyzések részletes nézetében látszani fog, milyen alkalmazást használtál a bejegyzés közzétételéhez
setting_use_blurhash: A kihomályosítás az eredeti képből történik, de minden részletet elrejt
setting_use_pending_items: Idővonal frissítése csak kattintásra automatikus görgetés helyett
- username: A felhasználói neved egyedi lesz a %{domain} domainen
whole_word: Ha a kulcsszó alfanumerikus, csak akkor minősül majd találatnak, ha teljes szóra illeszkedik
domain_allow:
domain: Ez a domain adatokat kérhet le erről a kiszolgálóról, és a bejövő adatok fel lesznek dolgozva és tárolva lesznek
M config/locales/simple_form.hy.yml => config/locales/simple_form.hy.yml +0 -1
@@ 49,7 49,6 @@ hy:
setting_show_application: Գրառման մանրամասներում կերեւայ թէ որ ծրագրով ես հրապարակել այն
setting_use_blurhash: Կտորները հիմնուում են թաքցուած վիզուալի վրայ՝ խամրեցնելով դետալները
setting_use_pending_items: Թաքցնել հոսքի թարմացումները կտտոի ետեւում՝ աւտօմատ թարմացուող հոսքի փոխարէն
- username: Քո օգտանունը պէտք է եզակի լինի %{domain}-ում։
whole_word: Եթէ բանալի բառը կամ արտայայտութիւնը պարունակում է միայն այբբենական նիշեր եւ թուեր, ապա այն կիրառուելու է ամբողջ բառի հետ համընկնելու դէպքում միայն
domain_allow:
domain: Այս տիրոյթը կարող է ստանալ տուեալներ այս սպասարկչից եւ ստացուող տուեալները կարող են օգտագործուել եւ պահուել
M config/locales/simple_form.id.yml => config/locales/simple_form.id.yml +0 -1
@@ 57,7 57,6 @@ id:
setting_show_application: Aplikasi yang Anda pakai untuk men-toot akan ditampilkan di tampilan detail toot
setting_use_blurhash: Gradien didasarkan pada warna visual yang tersembunyi tetapi mengaburkan setiap detail
setting_use_pending_items: Sembunyikan pembaruan linimasa di balik klik alih-alih bergulir secara otomatis
- username: Nama pengguna Anda unik di %{domain}
whole_word: Ketika kata kunci/frasa hanya alfanumerik, maka itu hanya akan diterapkan jika cocok dengan semua kata
domain_allow:
domain: Domain ini dapat mengambil data dari server ini dan data yang diterima akan diproses dan disimpan
M config/locales/simple_form.io.yml => config/locales/simple_form.io.yml +0 -1
@@ 57,7 57,6 @@ io:
setting_show_application: Softwaro quon vu uzar por postigar montresos che detala vidajo di vua posti
setting_use_blurhash: Inklini esas segun kolori di celesis vidaji ma kovras irga detali
setting_use_pending_items: Celez tempolineonovi dop kliktar e ne automatike movigar niuzeto
- username: Vua uzantonomo esos nura che %{domain}
whole_word: Kande klefvorto o fraz esas nur litera e nombra, ol nur aplikesos se ol parigesas la tota vorto
domain_allow:
domain: Ca domeno povas ganar informi de ca servilo e venanta informo de ol procedagesos e sparesos
M config/locales/simple_form.is.yml => config/locales/simple_form.is.yml +0 -1
@@ 59,7 59,6 @@ is:
setting_show_application: Nafnið á forritinu sem þú notar til að senda færslur mun birtast í ítarlegri sýn á færslunum þínum
setting_use_blurhash: Litstiglarnir byggja á litunum í földu myndunum, en gera öll smáatriði óskýr
setting_use_pending_items: Fela uppfærslur tímalínu þar til smellt er, í stað þess að hún skruni streyminu sjálfvirkt
- username: Notandanafnið þitt verður einstakt á %{domain}
whole_word: Þegar stikkorð eða setning er einungis tölur og bókstafir, verður það aðeins notað ef það samsvarar heilu orði
domain_allow:
domain: Þetta lén mun geta sótt gögn af þessum vefþjóni og tekið verður á móti innsendum gögnum frá léninu til vinnslu og geymslu
M config/locales/simple_form.it.yml => config/locales/simple_form.it.yml +0 -1
@@ 59,7 59,6 @@ it:
setting_show_application: L'applicazione che usi per pubblicare i toot sarà mostrata nella vista di dettaglio dei tuoi toot
setting_use_blurhash: I gradienti sono basati sui colori delle immagini nascoste ma offuscano tutti i dettagli
setting_use_pending_items: Fare clic per mostrare i nuovi messaggi invece di aggiornare la timeline automaticamente
- username: Il tuo nome utente sarà unico su %{domain}
whole_word: Quando la parola chiave o la frase è solo alfanumerica, si applica solo se corrisponde alla parola intera
domain_allow:
domain: Questo dominio potrà recuperare i dati da questo server e i dati in arrivo da esso verranno elaborati e memorizzati
M config/locales/simple_form.ja.yml => config/locales/simple_form.ja.yml +0 -1
@@ 59,7 59,6 @@ ja:
setting_show_application: 投稿するのに使用したアプリが投稿の詳細ビューに表示されるようになります
setting_use_blurhash: ぼかしはメディアの色を元に生成されますが、細部は見えにくくなっています
setting_use_pending_items: 新着があってもタイムラインを自動的にスクロールしないようにします
- username: あなたのユーザー名は%{domain}の中で重複していない必要があります
whole_word: キーワードまたはフレーズが英数字のみの場合、単語全体と一致する場合のみ適用されるようになります
domain_allow:
domain: 登録するとこのサーバーからデータを受信したり、このドメインから受信するデータを処理して保存できるようになります
M config/locales/simple_form.kab.yml => config/locales/simple_form.kab.yml +0 -1
@@ 20,7 20,6 @@ kab:
setting_display_media_hide_all: Ffer yal tikkelt akk taywalt
setting_display_media_show_all: Ffer yal tikkelt teywalt yettwacreḍ d tanafrit
setting_hide_network: Wid i teṭṭafaṛeḍ d wid i k-yeṭṭafaṛen ur d-ttwaseknen ara deg umaγnu-inek
- username: Isem-ik n umseqdac ad yili d ayiwen, ulac am netta deg %{domain}
imports:
data: Afaylu CSV id yusan seg uqeddac-nniḍen n Maṣṭudun
ip_block:
M config/locales/simple_form.ko.yml => config/locales/simple_form.ko.yml +0 -1
@@ 59,7 59,6 @@ ko:
setting_show_application: 당신이 게시물을 작성하는데에 사용한 앱이 게시물의 상세정보에 표시 됩니다
setting_use_blurhash: 그라디언트는 숨겨진 내용의 색상을 기반으로 하지만 상세 내용은 보이지 않게 합니다
setting_use_pending_items: 타임라인의 새 게시물을 자동으로 보여 주는 대신, 클릭해서 나타내도록 합니다
- username: 당신의 사용자명은 %{domain} 안에서 유일해야 합니다
whole_word: 키워드가 영문과 숫자로만 이루어 진 경우, 단어 전체에 매칭 되었을 때에만 작동하게 합니다
domain_allow:
domain: 이 도메인은 이 서버에서 데이터를 가져갈 수 있고 이 도메인에서 보내진 데이터는 처리되고 저장 됩니다
M config/locales/simple_form.ku.yml => config/locales/simple_form.ku.yml +0 -1
@@ 59,7 59,6 @@ ku:
setting_show_application: Navê sepana ku tu ji bo şandinê wê bi kar tîne dê di dîtinê berferh ên di şandiyên te de were xuyakirin
setting_use_blurhash: Gradyen xwe bi rengên dîtbarîyên veşartî ve radigire, lê belê hûrgilîyan diveşêre
setting_use_pending_items: Li şûna ku herkê wek bixweber bizivirînî nûvekirina demnameyê li paş tikandinekî veşêre
- username: Navê te yê bikarhênerî li ser %{domain} de bêhempa be
whole_word: Dema peyvkilîd an jî hevok bi tenê alfahejmarî çêbe, bi tenê hemû bêjeyê re li hev bike wê pêk bê
domain_allow:
domain: Ev navê navperê, ji vê rajekarê wê daneyan bistîne û daneyên ku jê bê wê were sazkirin û veşartin
M config/locales/simple_form.lv.yml => config/locales/simple_form.lv.yml +0 -1
@@ 59,7 59,6 @@ lv:
setting_show_application: Lietojumprogramma, ko tu izmanto publicēšanai, tiks parādīta tavu ziņu detalizētajā skatā
setting_use_blurhash: Gradientu pamatā ir paslēpto vizuālo attēlu krāsas, bet neskaidras visas detaļas
setting_use_pending_items: Paslēpt laika skalas atjauninājumus aiz klikšķa, nevis automātiski ritini plūsmu
- username: Tavs lietotājvārds %{domain} būs unikāls
whole_word: Ja atslēgvārds vai frāze ir tikai burtciparu, tas tiks lietots tikai tad, ja tas atbilst visam vārdam
domain_allow:
domain: Šis domēns varēs izgūt datus no šī servera, un no tā ienākošie dati tiks apstrādāti un saglabāti
M config/locales/simple_form.my.yml => config/locales/simple_form.my.yml +0 -1
@@ 59,7 59,6 @@ my:
setting_show_application: ပို့စ်တင်ရန်အတွက် သင်အသုံးပြုသည့် အက်ပလီကေးရှင်းကို သင့်ပို့စ်များ၏ အသေးစိတ်ကြည့်ရှုမှုတွင် ပြသမည်ဖြစ်သည်
setting_use_blurhash: Gradients မှာ ဖျောက်ထားသောရုပ်ပုံများ၏ အရောင်များကိုအခြေခံသော်လည်း မည်သည့်အသေးစိတ်အချက်အလက်ကိုမဆို ရှုပ်ထွေးစေနိုင်ပါသည်။
setting_use_pending_items: အပေါ်အောက်လှိမ့်မည့်အစား ကလစ်တစ်ခုနောက်တွင် စာမျက်နှာအပ်ဒိတ်များကို ဖျောက်ထားပါ။
- username: "%{domain} ရှိ သင့်အသုံးပြုသူအမည်မှာ တူညီ၍မရပါ"
whole_word: အဓိကစကားလုံး သို့မဟုတ် စကားစုသည် အက္ခရာဂဏန်းများသာဖြစ်ပါကစကားလုံးတစ်ခုလုံးနှင့် ကိုက်ညီမှသာ အသုံးပြုနိုင်မည်ဖြစ်သည်
domain_allow:
domain: ဤဒိုမိန်းသည် ဤဆာဗာမှ အချက်အလက်များကို ရယူနိုင်မည်ဖြစ်ပြီး ဝင်လာသောအချက်အလက်များကို စီမံဆောင်ရွက်ပေးပြီး သိမ်းဆည်းသွားမည်ဖြစ်သည်
M config/locales/simple_form.nl.yml => config/locales/simple_form.nl.yml +0 -1
@@ 59,7 59,6 @@ nl:
setting_show_application: De toepassing de je gebruikt om berichten te plaatsen wordt in de gedetailleerde weergave van het bericht getoond
setting_use_blurhash: Wazige kleurovergangen zijn gebaseerd op de kleuren van de verborgen media, waarmee elk detail verdwijnt
setting_use_pending_items: De tijdlijn wordt bijgewerkt door op het aantal nieuwe items te klikken, in plaats van dat deze automatisch wordt bijgewerkt
- username: Jouw gebruikersnaam is uniek op %{domain}
whole_word: Wanneer het trefwoord of zinsdeel alfanumeriek is, wordt het alleen gefilterd wanneer het hele woord overeenkomt
domain_allow:
domain: Dit domein is in staat om gegevens van deze server op te halen, en binnenkomende gegevens worden verwerkt en opgeslagen
M config/locales/simple_form.nn.yml => config/locales/simple_form.nn.yml +0 -1
@@ 57,7 57,6 @@ nn:
setting_show_application: Programmet du brukar for å tuta blir vist i den detaljerte visninga av tuta dine
setting_use_blurhash: Overgangar er basert på fargane til skjulte grafikkelement, men gjer detaljar utydelege
setting_use_pending_items: Gøym tidslineoppdateringar bak eit klikk, i staden for å rulla ned automatisk
- username: Brukarnamnet ditt vert unikt på %{domain}
whole_word: Når søkjeordet eller setninga berre er alfanumerisk, nyttast det berre om det samsvarar med heile ordet
domain_allow:
domain: Dette domenet er i stand til å henta data frå denne tenaren og innkomande data vert handsama og lagra
M config/locales/simple_form.no.yml => config/locales/simple_form.no.yml +0 -1
@@ 57,7 57,6 @@
setting_show_application: Appen du bruker til å publisere innlegg vil bli vist i den detaljerte visningen til innleggene dine
setting_use_blurhash: Gradientene er basert på fargene til de skjulte visualitetene, men gjør alle detaljer uklare
setting_use_pending_items: Skjul tidslinjeoppdateringer bak et klikk, i stedet for å automatisk la strømmen skrolle
- username: Brukernavnet ditt vil være unikt på %{domain}
whole_word: Når søkeordet eller setningen bare er alfanumerisk, aktiveres det bare hvis det samsvarer med hele ordet
domain_allow:
domain: Dette domenet vil være i stand til å hente data fra denne serveren og dets innkommende data vil bli prosessert og lagret
M config/locales/simple_form.oc.yml => config/locales/simple_form.oc.yml +0 -1
@@ 52,7 52,6 @@ oc:
setting_show_application: Lo nom de l’aplicacion qu’utilizatz per publicar serà mostrat dins la vista detalhada de vòstres tuts
setting_use_blurhash: Los degradats venon de las colors de l’imatge rescondut en enfoscar los detalhs
setting_use_pending_items: Rescondre las actualizacions del flux d’actualitat aprèp un clic allòc de desfilar lo flux automaticament
- username: Vòstre nom d’utilizaire serà unic sus %{domain}
whole_word: Quand lo mot-clau o frasa es solament alfranumeric, serà pas qu’aplicat se correspond al mot complèt
domain_allow:
domain: Aqueste domeni poirà recuperar las donadas d’aqueste servidor estant e las donadas venent d’aqueste domeni seràn tractadas e gardadas
M config/locales/simple_form.pl.yml => config/locales/simple_form.pl.yml +0 -1
@@ 59,7 59,6 @@ pl:
setting_show_application: W informacjach o wpisie będzie widoczna informacja o aplikacji, z której został wysłany
setting_use_blurhash: Gradienty są oparte na kolorach ukrywanej zawartości, ale uniewidaczniają wszystkie szczegóły
setting_use_pending_items: Ukryj aktualizacje osi czasu za kliknięciem, zamiast automatycznego przewijania strumienia
- username: Twoja nazwa użytkownika będzie niepowtarzalna na %{domain}
whole_word: Jeśli słowo lub fraza składa się jedynie z liter lub cyfr, filtr będzie zastosowany tylko do pełnych wystąpień
domain_allow:
domain: Ta domena będzie mogła pobierać dane z serwera, a dane przychodzące z niej będą przetwarzane i przechowywane
M config/locales/simple_form.pt-BR.yml => config/locales/simple_form.pt-BR.yml +0 -1
@@ 59,7 59,6 @@ pt-BR:
setting_show_application: O aplicativo que você usar para publicar será exibido na visão detalhada das suas publicações
setting_use_blurhash: O blur é baseado nas cores da imagem oculta, ofusca a maioria dos detalhes
setting_use_pending_items: Ocultar atualizações da linha do tempo atrás de um clique ao invés de rolar automaticamente
- username: Seu nome de usuário será único em %{domain}
whole_word: Quando a palavra-chave ou frase é inteiramente alfanumérica, ela será aplicada somente se corresponder a palavra inteira
domain_allow:
domain: Este domínio poderá obter dados deste servidor e os dados recebidos dele serão processados e armazenados
M config/locales/simple_form.pt-PT.yml => config/locales/simple_form.pt-PT.yml +0 -1
@@ 59,7 59,6 @@ pt-PT:
setting_show_application: A aplicação que usa para publicar será mostrada na vista pormenorizada das suas publicações
setting_use_blurhash: Os gradientes são baseados nas cores das imagens escondidas, mas ofuscam quaisquer pormenores
setting_use_pending_items: Ocultar atualizações da cronologia por detrás dum clique, em vez de rolar automaticamente o fluxo
- username: O teu nome de utilizador será único em %{domain}
whole_word: Quando a palavra-chave ou expressão-chave é somente alfanumérica, ela só será aplicada se corresponder à palavra completa
domain_allow:
domain: Este domínio será capaz de obter dados desta instância e os dados dele recebidos serão processados e armazenados
M config/locales/simple_form.ro.yml => config/locales/simple_form.ro.yml +0 -1
@@ 49,7 49,6 @@ ro:
setting_show_application: Aplicația pe care o utilizați pentru a posta va fi afișată în vizualizarea detaliată a postărilor
setting_use_blurhash: Gradienții sunt bazați pe culorile vizualelor ascunse, dar ofuscă orice detalii
setting_use_pending_items: Ascunde actualizările cronologice din spatele unui click în loc de a derula automat fluxul
- username: Numele tău de utilizator va fi unic pe %{domain}
whole_word: Când fraza sau cuvântul este doar alfanumeric, acesta se aplică doar dacă există o potrivire completă
domain_allow:
domain: Acest domeniu va putea prelua date de pe acest server și datele primite de la el vor fi procesate și stocate
M config/locales/simple_form.ru.yml => config/locales/simple_form.ru.yml +0 -1
@@ 59,7 59,6 @@ ru:
setting_show_application: При просмотре поста будет видно из какого приложения он отправлен.
setting_use_blurhash: Градиенты основаны на цветах скрытых медиа, но скрывают любые детали.
setting_use_pending_items: Показывать обновления в ленте только после клика вместо автоматической прокрутки.
- username: Ваше имя пользователя будет уникальным на %{domain}
whole_word: Если слово или фраза состоит только из букв и цифр, сопоставление произойдёт только по полному совпадению
domain_allow:
domain: Этот домен сможет получать данные с этого сервера и его входящие данные будут обрабатываться и сохранены
M config/locales/simple_form.sc.yml => config/locales/simple_form.sc.yml +0 -1
@@ 53,7 53,6 @@ sc:
setting_show_application: S'aplicatzione chi impreas pro publicare tuts at a èssere ammustrada in sa visualizatzione de detàlliu de is tuts
setting_use_blurhash: Is gradientes sunt basados in subra de is colores de is immàgines cuadas ma imbelant totu is detàllios
setting_use_pending_items: Cua is atualizatziones in segus de un'incarcu imbetzes de iscùrrere in automàticu su flussu de publicatziones
- username: Su nòmine de utente tuo at a èssere ùnicu in %{domain}
whole_word: Cando sa crae (faeddu o fràsia) siat isceti alfanumèrica, s'at a aplicare isceti si currispondet a su faeddu intreu
domain_allow:
domain: Custu domìniu at a pòdere recuperare datos dae custu serbidore e is datos in intrada dae cue ant a èssere protzessados e archiviados
M config/locales/simple_form.sco.yml => config/locales/simple_form.sco.yml +0 -1
@@ 57,7 57,6 @@ sco:
setting_show_application: The application thit ye uise fir tae post wull be displayed in the detailt view o yer posts
setting_use_blurhash: Gradients is based aff o the colors o the image thit's hid, but ye cannae see onie details
setting_use_pending_items: Plank timeline updates ahin a chap insteid o automatic scrowin o the feed
- username: Yer uisernemm wull be a ane aff on %{domain}
whole_word: Whan the keywird or phrase is alphanumeric ainly, it wull ainly get applied if it matches the haill wird
domain_allow:
domain: This domain wull be able tae get data fae this server an data comin in fae it wull get processed an stowed
M config/locales/simple_form.si.yml => config/locales/simple_form.si.yml +0 -1
@@ 57,7 57,6 @@ si:
setting_show_application: ඔබ පළ කිරීමට භාවිතා කරන යෙදුම ඔබගේ පළ කිරීම් වල සවිස්තරාත්මක දර්ශනයේ පෙන්වනු ඇත
setting_use_blurhash: අනුක්රමණ සැඟවුණු දෘශ්යවල වර්ණ මත පදනම් වන නමුත් ඕනෑම විස්තරයක් අපැහැදිලි කරයි
setting_use_pending_items: සංග්රහය ස්වයංක්රීයව අනුචලනය කරනවා වෙනුවට ක්ලික් කිරීමක් පිටුපස කාලරේඛා යාවත්කාලීන සඟවන්න
- username: ඔබගේ පරිශීලක නාමය %{domain}හි අද්විතීය වනු ඇත
whole_word: මූල පදය හෝ වාක්ය ඛණ්ඩය අක්ෂරාංක පමණක් වන විට, එය යෙදෙන්නේ එය සම්පූර්ණ වචනයට ගැලපේ නම් පමණි
domain_allow:
domain: මෙම වසමට මෙම සේවාදායකයෙන් දත්ත ලබා ගැනීමට හැකි වන අතර එයින් ලැබෙන දත්ත සකස් කර ගබඩා කරනු ලැබේ
M config/locales/simple_form.sk.yml => config/locales/simple_form.sk.yml +0 -1
@@ 42,7 42,6 @@ sk:
setting_show_application: Aplikácia, ktorú používaš na písanie príspevkov, bude zobrazená v podrobnom náhľade jednotlivých tvojích príspevkov
setting_use_blurhash: Prechody sú založené na farbách skrytých vizuálov, ale zahaľujú akékoľvek podrobnosti
setting_use_pending_items: Skry aktualizovanie časovej osi tak, aby bola načitávaná iba po kliknutí, namiesto samostatného posúvania
- username: Tvoja prezývka bude unikátna pre server %{domain}
whole_word: Ak je kľúčové slovo, alebo fráza poskladaná iba s písmen a čísel, bude použité iba ak sa zhoduje s celým výrazom
domain_allow:
domain: Táto doména bude schopná získavať dáta z tohto servera, a prichádzajúce dáta ním budú spracovávané a uložené
M config/locales/simple_form.sl.yml => config/locales/simple_form.sl.yml +0 -1
@@ 59,7 59,6 @@ sl:
setting_show_application: Aplikacija, ki jo uporabljate za objavljanje, bo prikazana v podrobnem pogledu vaših objav
setting_use_blurhash: Prelivi temeljijo na barvah skrite vizualne slike, vendar zakrivajo vse podrobnosti
setting_use_pending_items: Skrij posodobitev časovnice za klikom namesto samodejnega posodabljanja
- username: Vaše uporabniško ime bo edinstveno na %{domain}
whole_word: Ko je ključna beseda ali fraza samo alfanumerična, se bo uporabljala le, če se bo ujemala s celotno besedo
domain_allow:
domain: Ta domena bo lahko prejela podatke s tega strežnika, dohodni podatki z nje pa bodo obdelani in shranjeni
M config/locales/simple_form.sq.yml => config/locales/simple_form.sq.yml +0 -1
@@ 59,7 59,6 @@ sq:
setting_show_application: Aplikacioni që përdorni për mesazhe do të shfaqet te pamja e hollësishme për mesazhet tuaj
setting_use_blurhash: Gradientët bazohen në ngjyrat e elementëve pamorë të fshehur, por errësojnë çfarëdo hollësie
setting_use_pending_items: Fshihi përditësimet e rrjedhës kohore pas një klikimi, në vend të rrëshqitjes automatike nëpër prurje
- username: Emri juaj i përdoruesit do të jetë unik në %{domain}
whole_word: Kur fjalëkyçi ose fraza është vetëm numerike, do të aplikohet vetëm nëse përputhet me krejt fjalën
domain_allow:
domain: Kjo përkatësi do të jetë në gjendje të sjellë të dhëna prej këtij shërbyesi dhe të dhënat ardhëse prej tij do të përpunohen dhe depozitohen
M config/locales/simple_form.sr-Latn.yml => config/locales/simple_form.sr-Latn.yml +0 -1
@@ 59,7 59,6 @@ sr-Latn:
setting_show_application: Aplikacija koju koristite za objavljivanje će biti prikazana u detaljnom prikazu vaših objava
setting_use_blurhash: Gradijenti se formiraju na osnovu bojâ skrivenih slika i zamućuju prikaz, prikrivajući detalje
setting_use_pending_items: Sakriva ažuriranja vremenske linije iza klika umesto automatskog ažuriranja i pomeranja vremenske linije
- username: Vaš nadimak će biti jedinstven na %{domain}
whole_word: Kada je ključna reč ili fraza isključivo alfanumerička, biće primenjena samo ako se podudara sa celom rečju
domain_allow:
domain: Ovaj domen će moći da preuzima podatke sa ovog servera i dolazni podaci sa njega će se obrađivati i čuvati
M config/locales/simple_form.sr.yml => config/locales/simple_form.sr.yml +0 -1
@@ 59,7 59,6 @@ sr:
setting_show_application: Апликација коју користите за објављивање ће бити приказана у детаљном приказу ваших објава
setting_use_blurhash: Градијенти се формирају на основу бојâ скривених слика и замућују приказ, прикривајући детаље
setting_use_pending_items: Сакрива ажурирања временске линије иза клика уместо аутоматског ажурирања и померања временске линије
- username: Ваш надимак ће бити јединствен на %{domain}
whole_word: Када је кључна реч или фраза искључиво алфанумеричка, биће примењена само ако се подудара са целом речjу
domain_allow:
domain: Овај домен ће моћи да преузима податке са овог сервера и долазни подаци са њега ће се обрађивати и чувати
M config/locales/simple_form.sv.yml => config/locales/simple_form.sv.yml +0 -1
@@ 59,7 59,6 @@ sv:
setting_show_application: Applikationen du använder för att göra inlägg kommer visas i detaljvyn för dina inlägg
setting_use_blurhash: Gradienter är baserade på färgerna av de dolda objekten men fördunklar alla detaljer
setting_use_pending_items: Dölj tidslinjeuppdateringar bakom ett klick istället för att automatiskt bläddra i flödet
- username: Ditt användarnamn måste vara unikt på %{domain}
whole_word: När sökordet eller frasen endast är alfanumerisk, kommer det endast att tillämpas om det matchar hela ordet
domain_allow:
domain: Denna domän kommer att kunna hämta data från denna server och inkommande data från den kommer att behandlas och lagras
M config/locales/simple_form.th.yml => config/locales/simple_form.th.yml +0 -1
@@ 59,7 59,6 @@ th:
setting_show_application: จะแสดงแอปพลิเคชันที่คุณใช้ในการโพสต์ในมุมมองโดยละเอียดของโพสต์ของคุณ
setting_use_blurhash: การไล่ระดับสีอิงตามสีของภาพที่ซ่อนอยู่แต่ทำให้รายละเอียดใด ๆ คลุมเครือ
setting_use_pending_items: ซ่อนการอัปเดตเส้นเวลาไว้หลังการคลิกแทนที่จะเลื่อนฟีดโดยอัตโนมัติ
- username: ชื่อผู้ใช้ของคุณจะไม่ซ้ำกันใน %{domain}
whole_word: เมื่อคำสำคัญหรือวลีเป็นตัวอักษรและตัวเลขเท่านั้น จะนำไปใช้กับคำสำคัญหรือวลีหากตรงกันทั้งคำเท่านั้น
domain_allow:
domain: โดเมนนี้จะสามารถดึงข้อมูลจากเซิร์ฟเวอร์นี้และจะประมวลผลและจัดเก็บข้อมูลขาเข้าจากโดเมน
M config/locales/simple_form.tr.yml => config/locales/simple_form.tr.yml +0 -1
@@ 59,7 59,6 @@ tr:
setting_show_application: Gönderi gönderimi için kullandığınız uygulama, gönderilerinizin ayrıntılı görünümünde gösterilecektir
setting_use_blurhash: Gradyenler gizli görsellerin renklerine dayanır, ancak detayları gizler
setting_use_pending_items: Akışı otomatik olarak kaydırmak yerine, zaman çizelgesi güncellemelerini tek bir tıklamayla gizleyin
- username: Kullanıcı adınız %{domain} alanında benzersiz olacak
whole_word: Anahtar kelime veya kelime öbeği yalnızca alfasayısal olduğunda, yalnızca tüm sözcükle eşleşirse uygulanır
domain_allow:
domain: Bu alan adı, bu sunucudan veri alabilecek ve ondan gelen veri işlenecek ve saklanacaktır
M config/locales/simple_form.uk.yml => config/locales/simple_form.uk.yml +0 -1
@@ 59,7 59,6 @@ uk:
setting_show_application: Застосунок, за допомогою якого ви зробили допис, буде показано серед подробиць допису
setting_use_blurhash: Градієнти, що базуються на кольорах прихованих медіа, але роблять нерозрізненними будь-які деталі
setting_use_pending_items: Не додавати нові повідомлення до стрічок миттєво, показувати лише після додаткового клацання
- username: Ваше ім'я користувача буде унікальним у %{domain}
whole_word: Якщо пошукове слово або фраза містить лише літери та цифри, воно має збігатися цілком
domain_allow:
domain: Цей домен зможе отримувати дані з цього сервера. Вхідні дані будуть оброблені та збережені
M config/locales/simple_form.vi.yml => config/locales/simple_form.vi.yml +0 -1
@@ 59,7 59,6 @@ vi:
setting_show_application: Tên ứng dụng bạn dùng để đăng tút sẽ hiện trong chi tiết của tút
setting_use_blurhash: Lớp phủ mờ dựa trên màu sắc của hình ảnh nhạy cảm
setting_use_pending_items: Dồn lại toàn bộ tút mới và chỉ hiển thị khi nhấn vào
- username: Tên người dùng của bạn sẽ là duy nhất trên %{domain}
whole_word: Khi từ khóa hoặc cụm từ là chữ và số, nó sẽ chỉ hiện ra những từ chính xác như vậy
domain_allow:
domain: Máy chủ này sẽ tiếp nhận dữ liệu, rồi sau đó xử lý và lưu trữ
M config/locales/simple_form.zh-CN.yml => config/locales/simple_form.zh-CN.yml +0 -1
@@ 59,7 59,6 @@ zh-CN:
setting_show_application: 你用来发表嘟文的应用程序将会在你嘟文的详细内容中显示
setting_use_blurhash: 渐变是基于模糊后的隐藏内容生成的
setting_use_pending_items: 关闭自动滚动更新,时间轴会在点击后更新
- username: 你的用户名在 %{domain} 上是唯一的
whole_word: 如果关键词只包含字母和数字,将只在词语完全匹配时才会应用
domain_allow:
domain: 该站点将能够从该服务器上拉取数据,并处理和存储收到的数据。
M config/locales/simple_form.zh-HK.yml => config/locales/simple_form.zh-HK.yml +0 -1
@@ 59,7 59,6 @@ zh-HK:
setting_show_application: 你用來發表文章的應用程式,將會顯示在你文章的詳細檢視中
setting_use_blurhash: 漸變圖樣會基於隱藏媒體內容產生,但所有細節會變得模糊
setting_use_pending_items: 關閉自動滾動更新,時間軸會在點擊後更新
- username: 你的使用者名稱在 %{domain} 將是獨一無二的
whole_word: 如果關鍵字或詞組僅有字母與數字,則其將只在符合整個單字的時候才會套用
domain_allow:
domain: 此網域將能從此站獲取資料,而此站發出的數據也會被處理和存儲。
M config/locales/simple_form.zh-TW.yml => config/locales/simple_form.zh-TW.yml +0 -1
@@ 59,7 59,6 @@ zh-TW:
setting_show_application: 您用來發嘟文的應用程式將會在您嘟文的詳細檢視顯示
setting_use_blurhash: 彩色漸層圖樣是基於隱藏媒體內容顏色產生,所有細節會變得模糊
setting_use_pending_items: 關閉自動捲動更新,時間軸只會在點擊後更新
- username: 您的使用者名稱將於 %{domain} 是獨一無二的
whole_word: 如果關鍵字或詞組僅有字母與數字,則其將只在符合整個單字的時候才會套用
domain_allow:
domain: 此網域將能夠攫取本站資料,而自該網域發出的資料也會於本站處理和留存。
M config/routes.rb => config/routes.rb +27 -3
@@ 667,9 667,33 @@ Rails.application.routes.draw do
resources :ip_blocks, only: [:index, :show, :update, :create, :destroy]
namespace :trends do
- resources :tags, only: [:index]
- resources :links, only: [:index]
- resources :statuses, only: [:index]
+ resources :tags, only: [:index] do
+ member do
+ post :approve
+ post :reject
+ end
+ end
+ resources :links, only: [:index] do
+ member do
+ post :approve
+ post :reject
+ end
+ end
+ resources :statuses, only: [:index] do
+ member do
+ post :approve
+ post :reject
+ end
+ end
+
+ namespace :links do
+ resources :preview_card_providers, only: [:index], path: :publishers do
+ member do
+ post :approve
+ post :reject
+ end
+ end
+ end
end
post :measures, to: 'measures#create'
M jest.config.js => jest.config.js +1 -1
@@ 13,7 13,7 @@ const config = {
setupFiles: ['raf/polyfill'],
setupFilesAfterEnv: ['<rootDir>/app/javascript/mastodon/test_setup.js'],
collectCoverageFrom: [
- 'app/javascript/mastodon/**/*.js',
+ 'app/javascript/mastodon/**/*.{js,jsx,ts,tsx}',
'!app/javascript/mastodon/features/emoji/emoji_compressed.js',
'!app/javascript/mastodon/locales/locale-data/*.js',
'!app/javascript/mastodon/service_worker/entry.js',
M lib/mastodon/accounts_cli.rb => lib/mastodon/accounts_cli.rb +8 -2
@@ 57,6 57,7 @@ module Mastodon
option :role
option :reattach, type: :boolean
option :force, type: :boolean
+ option :approve, type: :boolean
desc 'create USERNAME', 'Create a new user account'
long_desc <<-LONG_DESC
Create a new user account with a given USERNAME and an
@@ 72,6 73,8 @@ module Mastodon
account is still in use by someone else, you can supply
the --force option to delete the old record and reattach the
username to the new account anyway.
+
+ With the --approve option, the account will be approved.
LONG_DESC
def create(username)
role_id = nil
@@ 89,7 92,7 @@ module Mastodon
account = Account.new(username: username)
password = SecureRandom.hex
- user = User.new(email: options[:email], password: password, agreement: true, approved: true, role_id: role_id, confirmed_at: options[:confirmed] ? Time.now.utc : nil, bypass_invite_request_check: true)
+ user = User.new(email: options[:email], password: password, agreement: true, role_id: role_id, confirmed_at: options[:confirmed] ? Time.now.utc : nil, bypass_invite_request_check: true)
if options[:reattach]
account = Account.find_local(username) || Account.new(username: username)
@@ 112,6 115,8 @@ module Mastodon
user.confirm!
end
+ user.approve! if options[:approve]
+
say('OK', :green)
say("New password: #{password}")
else
@@ 184,9 189,10 @@ module Mastodon
user.disabled = true if options[:disable]
user.approved = true if options[:approve]
user.otp_required_for_login = false if options[:disable_2fa]
- user.confirm if options[:confirm]
if user.save
+ user.confirm if options[:confirm]
+
say('OK', :green)
say("New password: #{password}") if options[:reset_password]
else
M package.json => package.json +3 -3
@@ 68,7 68,7 @@
"fuzzysort": "^2.0.4",
"glob": "^10.0.0",
"history": "^4.10.1",
- "http-link-header": "^1.1.0",
+ "http-link-header": "^1.1.1",
"immutable": "^4.3.0",
"imports-loader": "^1.2.0",
"intl": "^1.2.5",
@@ 86,7 86,7 @@
"path-complete-extname": "^1.0.0",
"pg": "^8.5.0",
"pg-connection-string": "^2.5.0",
- "postcss": "^8.4.21",
+ "postcss": "^8.4.22",
"postcss-loader": "^4.3.0",
"promise.prototype.finally": "^3.1.4",
"prop-types": "^15.8.1",
@@ 116,7 116,7 @@
"redux-thunk": "^2.4.2",
"regenerator-runtime": "^0.13.11",
"requestidlecallback": "^0.3.0",
- "reselect": "^4.1.7",
+ "reselect": "^4.1.8",
"rimraf": "^5.0.0",
"sass": "^1.61.0",
"sass-loader": "^10.2.0",
A spec/controllers/api/v1/admin/trends/links/preview_card_providers_controller_spec.rb => spec/controllers/api/v1/admin/trends/links/preview_card_providers_controller_spec.rb +68 -0
@@ 0,0 1,68 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Api::V1::Admin::Trends::Links::PreviewCardProvidersController do
+ render_views
+
+ let(:role) { UserRole.find_by(name: 'Admin') }
+ let(:user) { Fabricate(:user, role: role) }
+ let(:scopes) { 'admin:read admin:write' }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
+ let(:account) { Fabricate(:account) }
+ let(:preview_card_provider) { Fabricate(:preview_card_provider) }
+
+ before do
+ allow(controller).to receive(:doorkeeper_token) { token }
+ end
+
+ shared_examples 'forbidden for wrong scope' do |wrong_scope|
+ let(:scopes) { wrong_scope }
+
+ it 'returns http forbidden' do
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ shared_examples 'forbidden for wrong role' do |wrong_role|
+ let(:role) { UserRole.find_by(name: wrong_role) }
+
+ it 'returns http forbidden' do
+ expect(response).to have_http_status(403)
+ end
+ 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
+
+ describe 'POST #approve' do
+ before do
+ post :approve, params: { id: preview_card_provider.id }
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns http success' do
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ describe 'POST #reject' do
+ before do
+ post :reject, params: { id: preview_card_provider.id }
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns http success' do
+ expect(response).to have_http_status(200)
+ end
+ end
+end
M spec/controllers/api/v1/admin/trends/links_controller_spec.rb => spec/controllers/api/v1/admin/trends/links_controller_spec.rb +47 -2
@@ 5,14 5,33 @@ require 'rails_helper'
describe Api::V1::Admin::Trends::LinksController do
render_views
- let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'admin:read') }
+ let(:role) { UserRole.find_by(name: 'Admin') }
+ let(:user) { Fabricate(:user, role: role) }
+ let(:scopes) { 'admin:read admin:write' }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:account) { Fabricate(:account) }
+ let(:preview_card) { Fabricate(:preview_card) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
+ shared_examples 'forbidden for wrong scope' do |wrong_scope|
+ let(:scopes) { wrong_scope }
+
+ it 'returns http forbidden' do
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ shared_examples 'forbidden for wrong role' do |wrong_role|
+ let(:role) { UserRole.find_by(name: wrong_role) }
+
+ it 'returns http forbidden' do
+ expect(response).to have_http_status(403)
+ end
+ end
+
describe 'GET #index' do
it 'returns http success' do
get :index, params: { account_id: account.id, limit: 2 }
@@ 20,4 39,30 @@ describe Api::V1::Admin::Trends::LinksController do
expect(response).to have_http_status(200)
end
end
+
+ describe 'POST #approve' do
+ before do
+ post :approve, params: { id: preview_card.id }
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns http success' do
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ describe 'POST #reject' do
+ before do
+ post :reject, params: { id: preview_card.id }
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns http success' do
+ expect(response).to have_http_status(200)
+ end
+ end
end
M spec/controllers/api/v1/admin/trends/statuses_controller_spec.rb => spec/controllers/api/v1/admin/trends/statuses_controller_spec.rb +47 -2
@@ 5,14 5,33 @@ require 'rails_helper'
describe Api::V1::Admin::Trends::StatusesController do
render_views
- let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'admin:read') }
+ let(:role) { UserRole.find_by(name: 'Admin') }
+ let(:user) { Fabricate(:user, role: role) }
+ let(:scopes) { 'admin:read admin:write' }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:account) { Fabricate(:account) }
+ let(:status) { Fabricate(:status) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
+ shared_examples 'forbidden for wrong scope' do |wrong_scope|
+ let(:scopes) { wrong_scope }
+
+ it 'returns http forbidden' do
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ shared_examples 'forbidden for wrong role' do |wrong_role|
+ let(:role) { UserRole.find_by(name: wrong_role) }
+
+ it 'returns http forbidden' do
+ expect(response).to have_http_status(403)
+ end
+ end
+
describe 'GET #index' do
it 'returns http success' do
get :index, params: { account_id: account.id, limit: 2 }
@@ 20,4 39,30 @@ describe Api::V1::Admin::Trends::StatusesController do
expect(response).to have_http_status(200)
end
end
+
+ describe 'POST #approve' do
+ before do
+ post :approve, params: { id: status.id }
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns http success' do
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ describe 'POST #reject' do
+ before do
+ post :reject, params: { id: status.id }
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns http success' do
+ expect(response).to have_http_status(200)
+ end
+ end
end
M spec/controllers/api/v1/admin/trends/tags_controller_spec.rb => spec/controllers/api/v1/admin/trends/tags_controller_spec.rb +47 -2
@@ 5,14 5,33 @@ require 'rails_helper'
describe Api::V1::Admin::Trends::TagsController do
render_views
- let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
- let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'admin:read') }
+ let(:role) { UserRole.find_by(name: 'Admin') }
+ let(:user) { Fabricate(:user, role: role) }
+ let(:scopes) { 'admin:read admin:write' }
+ let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:account) { Fabricate(:account) }
+ let(:tag) { Fabricate(:tag) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
+ shared_examples 'forbidden for wrong scope' do |wrong_scope|
+ let(:scopes) { wrong_scope }
+
+ it 'returns http forbidden' do
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ shared_examples 'forbidden for wrong role' do |wrong_role|
+ let(:role) { UserRole.find_by(name: wrong_role) }
+
+ it 'returns http forbidden' do
+ expect(response).to have_http_status(403)
+ end
+ end
+
describe 'GET #index' do
it 'returns http success' do
get :index, params: { account_id: account.id, limit: 2 }
@@ 20,4 39,30 @@ describe Api::V1::Admin::Trends::TagsController do
expect(response).to have_http_status(200)
end
end
+
+ describe 'POST #approve' do
+ before do
+ post :approve, params: { id: tag.id }
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns http success' do
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ describe 'POST #reject' do
+ before do
+ post :reject, params: { id: tag.id }
+ end
+
+ it_behaves_like 'forbidden for wrong scope', 'write:statuses'
+ it_behaves_like 'forbidden for wrong role', ''
+
+ it 'returns http success' do
+ expect(response).to have_http_status(200)
+ end
+ end
end
M spec/mailers/notification_mailer_spec.rb => spec/mailers/notification_mailer_spec.rb +5 -5
@@ 29,7 29,7 @@ RSpec.describe NotificationMailer, type: :mailer do
it 'renders the headers' do
expect(mail.subject).to eq('You were mentioned by bob')
- expect(mail.to).to eq([receiver.email])
+ expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>")
end
it 'renders the body' do
@@ 46,7 46,7 @@ RSpec.describe NotificationMailer, type: :mailer do
it 'renders the headers' do
expect(mail.subject).to eq('bob is now following you')
- expect(mail.to).to eq([receiver.email])
+ expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>")
end
it 'renders the body' do
@@ 62,7 62,7 @@ RSpec.describe NotificationMailer, type: :mailer do
it 'renders the headers' do
expect(mail.subject).to eq('bob favourited your post')
- expect(mail.to).to eq([receiver.email])
+ expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>")
end
it 'renders the body' do
@@ 79,7 79,7 @@ RSpec.describe NotificationMailer, type: :mailer do
it 'renders the headers' do
expect(mail.subject).to eq('bob boosted your post')
- expect(mail.to).to eq([receiver.email])
+ expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>")
end
it 'renders the body' do
@@ 96,7 96,7 @@ RSpec.describe NotificationMailer, type: :mailer do
it 'renders the headers' do
expect(mail.subject).to eq('Pending follower: bob')
- expect(mail.to).to eq([receiver.email])
+ expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>")
end
it 'renders the body' do
M spec/models/account_filter_spec.rb => spec/models/account_filter_spec.rb +19 -0
@@ 44,4 44,23 @@ describe AccountFilter do
expect(filter.results).to match_array [remote_account_one]
end
end
+
+ describe 'with username' do
+ let!(:local_account) { Fabricate(:account, domain: nil, username: 'validUserName') }
+
+ it 'works with @ at the beginning of the username' do
+ filter = described_class.new(username: '@validUserName')
+ expect(filter.results).to match_array [local_account]
+ end
+
+ it 'does not work with more than one @ at the beginning of the username' do
+ filter = described_class.new(username: '@@validUserName')
+ expect(filter.results).to_not match_array [local_account]
+ end
+
+ it 'does not work with @ outside the beginning of the username' do
+ filter = described_class.new(username: 'validUserName@')
+ expect(filter.results).to_not match_array [local_account]
+ end
+ end
end
M spec/services/reblog_service_spec.rb => spec/services/reblog_service_spec.rb +17 -5
@@ 35,13 35,25 @@ RSpec.describe ReblogService, type: :service do
end
context 'when the reblogged status is discarded in the meantime' do
- let(:status) { Fabricate(:status, account: alice, visibility: :public) }
+ let(:status) { Fabricate(:status, account: alice, visibility: :public, text: 'discard-status-text') }
+ # Add a callback to discard the status being reblogged after the
+ # validations pass but before the database commit is executed.
before do
- # Update the in-database attribute without reflecting the change in
- # the object. This cannot simulate all race conditions, but it is
- # pretty close.
- Status.where(id: status.id).update_all(deleted_at: Time.now.utc) # rubocop:disable Rails/SkipsModelValidations
+ Status.class_eval do
+ before_save :discard_status
+ def discard_status
+ Status
+ .where(id: reblog_of_id)
+ .where(text: 'discard-status-text')
+ .update_all(deleted_at: Time.now.utc) # rubocop:disable Rails/SkipsModelValidations
+ end
+ end
+ end
+
+ # Remove race condition simulating `discard_status` callback.
+ after do
+ Status._save_callbacks.delete(:discard_status)
end
it 'raises an exception' do
M yarn.lock => yarn.lock +17 -17
@@ 6047,10 6047,10 @@ http-errors@~1.6.2:
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
-http-link-header@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/http-link-header/-/http-link-header-1.1.0.tgz#a1ca87efdbcb7778d8d0d4525de1e6964ec1f129"
- integrity sha512-pj6N1yxOz/ANO8HHsWGg/OoIL1kmRYvQnXQ7PIRpgp+15AnEsRH8fmIJE6D1OdWG2Bov+BJHVla1fFXxg1JbbA==
+http-link-header@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/http-link-header/-/http-link-header-1.1.1.tgz#f0e6971b0ed86e858d2077066ecb7ba4f2e50de9"
+ integrity sha512-mW3N/rTYpCn99s1do0zx6nzFZSwLH9HGfUM4ZqLWJ16ylmYaC2v5eYGqrNTQlByx8AzUgGI+V/32gXPugs1+Sw==
http-parser-js@>=0.5.1:
version "0.5.3"
@@ 8020,10 8020,10 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
-nanoid@^3.3.4:
- version "3.3.4"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
- integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
+nanoid@^3.3.6:
+ version "3.3.6"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
+ integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
nanomatch@^1.2.9:
version "1.2.13"
@@ 9022,12 9022,12 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
-postcss@^8.2.15, postcss@^8.4.21:
- version "8.4.21"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4"
- integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
+postcss@^8.2.15, postcss@^8.4.21, postcss@^8.4.22:
+ version "8.4.22"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.22.tgz#c29e6776b60ab3af602d4b513d5bd2ff9aa85dc1"
+ integrity sha512-XseknLAfRHzVWjCEtdviapiBtfLdgyzExD50Rg2ePaucEesyh8Wv4VPdW0nbyDa1ydbrAxV19jvMT4+LFmcNUA==
dependencies:
- nanoid "^3.3.4"
+ nanoid "^3.3.6"
picocolors "^1.0.0"
source-map-js "^1.0.2"
@@ 9804,10 9804,10 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
-reselect@^4.1.7:
- version "4.1.7"
- resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.7.tgz#56480d9ff3d3188970ee2b76527bd94a95567a42"
- integrity sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==
+reselect@^4.1.8:
+ version "4.1.8"
+ resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524"
+ integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==
resolve-cwd@^2.0.0:
version "2.0.0"