mirror of
https://github.com/glitch-soc/mastodon.git
synced 2024-11-27 10:30:15 -05:00
Merge commit 'b2c5b20ef27edd948eca8d6bd2014b7a5efaec11' into glitch-soc/merge-upstream
This commit is contained in:
commit
a111fd7a0b
@ -43,23 +43,6 @@ Metrics/CyclomaticComplexity:
|
|||||||
Metrics/PerceivedComplexity:
|
Metrics/PerceivedComplexity:
|
||||||
Max: 27
|
Max: 27
|
||||||
|
|
||||||
RSpec/AnyInstance:
|
|
||||||
Exclude:
|
|
||||||
- 'spec/controllers/activitypub/inboxes_controller_spec.rb'
|
|
||||||
- 'spec/controllers/admin/accounts_controller_spec.rb'
|
|
||||||
- 'spec/controllers/admin/resets_controller_spec.rb'
|
|
||||||
- 'spec/controllers/auth/sessions_controller_spec.rb'
|
|
||||||
- 'spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb'
|
|
||||||
- 'spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb'
|
|
||||||
- 'spec/lib/request_spec.rb'
|
|
||||||
- 'spec/lib/status_filter_spec.rb'
|
|
||||||
- 'spec/models/account_spec.rb'
|
|
||||||
- 'spec/models/setting_spec.rb'
|
|
||||||
- 'spec/services/activitypub/process_collection_service_spec.rb'
|
|
||||||
- 'spec/validators/follow_limit_validator_spec.rb'
|
|
||||||
- 'spec/workers/activitypub/delivery_worker_spec.rb'
|
|
||||||
- 'spec/workers/web/push_notification_worker_spec.rb'
|
|
||||||
|
|
||||||
# Configuration parameters: CountAsOne.
|
# Configuration parameters: CountAsOne.
|
||||||
RSpec/ExampleLength:
|
RSpec/ExampleLength:
|
||||||
Max: 22
|
Max: 22
|
||||||
|
@ -7,6 +7,7 @@ class Api::BaseController < ApplicationController
|
|||||||
include RateLimitHeaders
|
include RateLimitHeaders
|
||||||
include AccessTokenTrackingConcern
|
include AccessTokenTrackingConcern
|
||||||
include ApiCachingConcern
|
include ApiCachingConcern
|
||||||
|
include Api::ContentSecurityPolicy
|
||||||
|
|
||||||
skip_before_action :require_functional!, unless: :limited_federation_mode?
|
skip_before_action :require_functional!, unless: :limited_federation_mode?
|
||||||
|
|
||||||
@ -17,26 +18,6 @@ class Api::BaseController < ApplicationController
|
|||||||
|
|
||||||
protect_from_forgery with: :null_session
|
protect_from_forgery with: :null_session
|
||||||
|
|
||||||
content_security_policy do |p|
|
|
||||||
# Set every directive that does not have a fallback
|
|
||||||
p.default_src :none
|
|
||||||
p.frame_ancestors :none
|
|
||||||
p.form_action :none
|
|
||||||
|
|
||||||
# Disable every directive with a fallback to cut on response size
|
|
||||||
p.base_uri false
|
|
||||||
p.font_src false
|
|
||||||
p.img_src false
|
|
||||||
p.style_src false
|
|
||||||
p.media_src false
|
|
||||||
p.frame_src false
|
|
||||||
p.manifest_src false
|
|
||||||
p.connect_src false
|
|
||||||
p.script_src false
|
|
||||||
p.child_src false
|
|
||||||
p.worker_src false
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
|
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
|
||||||
render json: { error: e.to_s }, status: 422
|
render json: { error: e.to_s }, status: 422
|
||||||
end
|
end
|
||||||
|
@ -13,7 +13,7 @@ class Api::V1::Instances::DomainBlocksController < Api::V1::Instances::BaseContr
|
|||||||
cache_if_unauthenticated!
|
cache_if_unauthenticated!
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: (Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?))
|
render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: show_rationale_in_response?
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -25,4 +25,16 @@ class Api::V1::Instances::DomainBlocksController < Api::V1::Instances::BaseContr
|
|||||||
def set_domain_blocks
|
def set_domain_blocks
|
||||||
@domain_blocks = DomainBlock.with_user_facing_limitations.by_severity
|
@domain_blocks = DomainBlock.with_user_facing_limitations.by_severity
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show_rationale_in_response?
|
||||||
|
always_show_rationale? || show_rationale_for_user?
|
||||||
|
end
|
||||||
|
|
||||||
|
def always_show_rationale?
|
||||||
|
Setting.show_domain_blocks_rationale == 'all'
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_rationale_for_user?
|
||||||
|
Setting.show_domain_blocks_rationale == 'users' && user_signed_in?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
16
app/controllers/api/v1/statuses/base_controller.rb
Normal file
16
app/controllers/api/v1/statuses/base_controller.rb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Statuses::BaseController < Api::BaseController
|
||||||
|
include Authorization
|
||||||
|
|
||||||
|
before_action :set_status
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_status
|
||||||
|
@status = Status.find(params[:status_id])
|
||||||
|
authorize @status, :show?
|
||||||
|
rescue Mastodon::NotPermittedError
|
||||||
|
not_found
|
||||||
|
end
|
||||||
|
end
|
@ -1,11 +1,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Statuses::BookmarksController < Api::BaseController
|
class Api::V1::Statuses::BookmarksController < Api::V1::Statuses::BaseController
|
||||||
include Authorization
|
|
||||||
|
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:bookmarks' }
|
before_action -> { doorkeeper_authorize! :write, :'write:bookmarks' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_status, only: [:create]
|
skip_before_action :set_status, only: [:destroy]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
current_account.bookmarks.find_or_create_by!(account: current_account, status: @status)
|
current_account.bookmarks.find_or_create_by!(account: current_account, status: @status)
|
||||||
@ -28,13 +26,4 @@ class Api::V1::Statuses::BookmarksController < Api::BaseController
|
|||||||
rescue Mastodon::NotPermittedError
|
rescue Mastodon::NotPermittedError
|
||||||
not_found
|
not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def set_status
|
|
||||||
@status = Status.find(params[:status_id])
|
|
||||||
authorize @status, :show?
|
|
||||||
rescue Mastodon::NotPermittedError
|
|
||||||
not_found
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
|
class Api::V1::Statuses::FavouritedByAccountsController < Api::V1::Statuses::BaseController
|
||||||
include Authorization
|
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :read, :'read:accounts' }
|
before_action -> { authorize_if_got_token! :read, :'read:accounts' }
|
||||||
before_action :set_status
|
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@ -61,13 +58,6 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
|
|||||||
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
|
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_status
|
|
||||||
@status = Status.find(params[:status_id])
|
|
||||||
authorize @status, :show?
|
|
||||||
rescue Mastodon::NotPermittedError
|
|
||||||
not_found
|
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_params(core_params)
|
def pagination_params(core_params)
|
||||||
params.slice(:limit).permit(:limit).merge(core_params)
|
params.slice(:limit).permit(:limit).merge(core_params)
|
||||||
end
|
end
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Statuses::FavouritesController < Api::BaseController
|
class Api::V1::Statuses::FavouritesController < Api::V1::Statuses::BaseController
|
||||||
include Authorization
|
|
||||||
|
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:favourites' }
|
before_action -> { doorkeeper_authorize! :write, :'write:favourites' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_status, only: [:create]
|
skip_before_action :set_status, only: [:destroy]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
FavouriteService.new.call(current_account, @status)
|
FavouriteService.new.call(current_account, @status)
|
||||||
@ -30,13 +28,4 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController
|
|||||||
rescue Mastodon::NotPermittedError
|
rescue Mastodon::NotPermittedError
|
||||||
not_found
|
not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def set_status
|
|
||||||
@status = Status.find(params[:status_id])
|
|
||||||
authorize @status, :show?
|
|
||||||
rescue Mastodon::NotPermittedError
|
|
||||||
not_found
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Statuses::HistoriesController < Api::BaseController
|
class Api::V1::Statuses::HistoriesController < Api::V1::Statuses::BaseController
|
||||||
include Authorization
|
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :read, :'read:statuses' }
|
before_action -> { authorize_if_got_token! :read, :'read:statuses' }
|
||||||
before_action :set_status
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
cache_if_unauthenticated!
|
cache_if_unauthenticated!
|
||||||
@ -16,11 +13,4 @@ class Api::V1::Statuses::HistoriesController < Api::BaseController
|
|||||||
def status_edits
|
def status_edits
|
||||||
@status.edits.includes(:account, status: [:account]).to_a.presence || [@status.build_snapshot(at_time: @status.edited_at || @status.created_at)]
|
@status.edits.includes(:account, status: [:account]).to_a.presence || [@status.build_snapshot(at_time: @status.edited_at || @status.created_at)]
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_status
|
|
||||||
@status = Status.find(params[:status_id])
|
|
||||||
authorize @status, :show?
|
|
||||||
rescue Mastodon::NotPermittedError
|
|
||||||
not_found
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Statuses::MutesController < Api::BaseController
|
class Api::V1::Statuses::MutesController < Api::V1::Statuses::BaseController
|
||||||
include Authorization
|
|
||||||
|
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:mutes' }
|
before_action -> { doorkeeper_authorize! :write, :'write:mutes' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_status
|
|
||||||
before_action :set_conversation
|
before_action :set_conversation
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@ -24,13 +21,6 @@ class Api::V1::Statuses::MutesController < Api::BaseController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_status
|
|
||||||
@status = Status.find(params[:status_id])
|
|
||||||
authorize @status, :show?
|
|
||||||
rescue Mastodon::NotPermittedError
|
|
||||||
not_found
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_conversation
|
def set_conversation
|
||||||
@conversation = @status.conversation
|
@conversation = @status.conversation
|
||||||
raise Mastodon::ValidationError if @conversation.nil?
|
raise Mastodon::ValidationError if @conversation.nil?
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Statuses::PinsController < Api::BaseController
|
class Api::V1::Statuses::PinsController < Api::V1::Statuses::BaseController
|
||||||
include Authorization
|
|
||||||
|
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }
|
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_status
|
|
||||||
|
|
||||||
def create
|
def create
|
||||||
StatusPin.create!(account: current_account, status: @status)
|
StatusPin.create!(account: current_account, status: @status)
|
||||||
@ -26,10 +23,6 @@ class Api::V1::Statuses::PinsController < Api::BaseController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_status
|
|
||||||
@status = Status.find(params[:status_id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def distribute_add_activity!
|
def distribute_add_activity!
|
||||||
json = ActiveModelSerializers::SerializableResource.new(
|
json = ActiveModelSerializers::SerializableResource.new(
|
||||||
@status,
|
@status,
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
|
class Api::V1::Statuses::RebloggedByAccountsController < Api::V1::Statuses::BaseController
|
||||||
include Authorization
|
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :read, :'read:accounts' }
|
before_action -> { authorize_if_got_token! :read, :'read:accounts' }
|
||||||
before_action :set_status
|
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@ -57,13 +54,6 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
|
|||||||
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
|
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_status
|
|
||||||
@status = Status.find(params[:status_id])
|
|
||||||
authorize @status, :show?
|
|
||||||
rescue Mastodon::NotPermittedError
|
|
||||||
not_found
|
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_params(core_params)
|
def pagination_params(core_params)
|
||||||
params.slice(:limit).permit(:limit).merge(core_params)
|
params.slice(:limit).permit(:limit).merge(core_params)
|
||||||
end
|
end
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Statuses::ReblogsController < Api::BaseController
|
class Api::V1::Statuses::ReblogsController < Api::V1::Statuses::BaseController
|
||||||
include Authorization
|
|
||||||
include Redisable
|
include Redisable
|
||||||
include Lockable
|
include Lockable
|
||||||
|
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }
|
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_reblog, only: [:create]
|
before_action :set_reblog, only: [:create]
|
||||||
|
skip_before_action :set_status
|
||||||
|
|
||||||
override_rate_limit_headers :create, family: :statuses
|
override_rate_limit_headers :create, family: :statuses
|
||||||
|
|
||||||
|
@ -1,21 +1,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Statuses::SourcesController < Api::BaseController
|
class Api::V1::Statuses::SourcesController < Api::V1::Statuses::BaseController
|
||||||
include Authorization
|
|
||||||
|
|
||||||
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }
|
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }
|
||||||
before_action :set_status
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
render json: @status, serializer: REST::StatusSourceSerializer
|
render json: @status, serializer: REST::StatusSourceSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def set_status
|
|
||||||
@status = Status.find(params[:status_id])
|
|
||||||
authorize @status, :show?
|
|
||||||
rescue Mastodon::NotPermittedError
|
|
||||||
not_found
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Statuses::TranslationsController < Api::BaseController
|
class Api::V1::Statuses::TranslationsController < Api::V1::Statuses::BaseController
|
||||||
include Authorization
|
|
||||||
|
|
||||||
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }
|
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }
|
||||||
before_action :set_status
|
|
||||||
before_action :set_translation
|
before_action :set_translation
|
||||||
|
|
||||||
rescue_from TranslationService::NotConfiguredError, with: :not_found
|
rescue_from TranslationService::NotConfiguredError, with: :not_found
|
||||||
@ -24,13 +21,6 @@ class Api::V1::Statuses::TranslationsController < Api::BaseController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_status
|
|
||||||
@status = Status.find(params[:status_id])
|
|
||||||
authorize @status, :show?
|
|
||||||
rescue Mastodon::NotPermittedError
|
|
||||||
not_found
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_translation
|
def set_translation
|
||||||
@translation = TranslateStatusService.new.call(@status, content_locale)
|
@translation = TranslateStatusService.new.call(@status, content_locale)
|
||||||
end
|
end
|
||||||
|
27
app/controllers/concerns/api/content_security_policy.rb
Normal file
27
app/controllers/concerns/api/content_security_policy.rb
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api::ContentSecurityPolicy
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
content_security_policy do |policy|
|
||||||
|
# Set every directive that does not have a fallback
|
||||||
|
policy.default_src :none
|
||||||
|
policy.frame_ancestors :none
|
||||||
|
policy.form_action :none
|
||||||
|
|
||||||
|
# Disable every directive with a fallback to cut on response size
|
||||||
|
policy.base_uri false
|
||||||
|
policy.font_src false
|
||||||
|
policy.img_src false
|
||||||
|
policy.style_src false
|
||||||
|
policy.media_src false
|
||||||
|
policy.frame_src false
|
||||||
|
policy.manifest_src false
|
||||||
|
policy.connect_src false
|
||||||
|
policy.script_src false
|
||||||
|
policy.child_src false
|
||||||
|
policy.worker_src false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -19,6 +19,8 @@ import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/s
|
|||||||
import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg';
|
import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg';
|
||||||
import { ReactComponent as VisibilityIcon } from '@material-symbols/svg-600/outlined/visibility.svg';
|
import { ReactComponent as VisibilityIcon } from '@material-symbols/svg-600/outlined/visibility.svg';
|
||||||
|
|
||||||
|
import { ReactComponent as RepeatDisabledIcon } from 'mastodon/../svg-icons/repeat_disabled.svg';
|
||||||
|
import { ReactComponent as RepeatPrivateIcon } from 'mastodon/../svg-icons/repeat_private.svg';
|
||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
|
||||||
@ -348,6 +350,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
let replyIcon;
|
let replyIcon;
|
||||||
let replyIconComponent;
|
let replyIconComponent;
|
||||||
let replyTitle;
|
let replyTitle;
|
||||||
|
|
||||||
if (status.get('in_reply_to_id', null) === null) {
|
if (status.get('in_reply_to_id', null) === null) {
|
||||||
replyIcon = 'reply';
|
replyIcon = 'reply';
|
||||||
replyIconComponent = ReplyIcon;
|
replyIconComponent = ReplyIcon;
|
||||||
@ -360,15 +363,20 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
|
|
||||||
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
|
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
|
||||||
|
|
||||||
let reblogTitle = '';
|
let reblogTitle, reblogIconComponent;
|
||||||
|
|
||||||
if (status.get('reblogged')) {
|
if (status.get('reblogged')) {
|
||||||
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
||||||
|
reblogIconComponent = publicStatus ? RepeatIcon : RepeatPrivateIcon;
|
||||||
} else if (publicStatus) {
|
} else if (publicStatus) {
|
||||||
reblogTitle = intl.formatMessage(messages.reblog);
|
reblogTitle = intl.formatMessage(messages.reblog);
|
||||||
|
reblogIconComponent = RepeatIcon;
|
||||||
} else if (reblogPrivate) {
|
} else if (reblogPrivate) {
|
||||||
reblogTitle = intl.formatMessage(messages.reblog_private);
|
reblogTitle = intl.formatMessage(messages.reblog_private);
|
||||||
|
reblogIconComponent = RepeatPrivateIcon;
|
||||||
} else {
|
} else {
|
||||||
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
||||||
|
reblogIconComponent = RepeatDisabledIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterButton = this.props.onFilter && (
|
const filterButton = this.props.onFilter && (
|
||||||
@ -380,7 +388,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
return (
|
return (
|
||||||
<div className='status__action-bar'>
|
<div className='status__action-bar'>
|
||||||
<IconButton className='status__action-bar__button' title={replyTitle} icon={isReply ? 'reply' : replyIcon} iconComponent={isReply ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
|
<IconButton className='status__action-bar__button' title={replyTitle} icon={isReply ? 'reply' : replyIcon} iconComponent={isReply ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
|
||||||
<IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
|
<IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
|
||||||
<IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
|
<IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
|
||||||
<IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />
|
<IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ class ListTimeline extends PureComponent {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='setting-toggle'>
|
<div className='setting-toggle'>
|
||||||
<Toggle id={`list-${id}-exclusive`} defaultChecked={isExclusive} onChange={this.onExclusiveToggle} />
|
<Toggle id={`list-${id}-exclusive`} checked={isExclusive} onChange={this.onExclusiveToggle} />
|
||||||
<label htmlFor={`list-${id}-exclusive`} className='setting-toggle__label'>
|
<label htmlFor={`list-${id}-exclusive`} className='setting-toggle__label'>
|
||||||
<FormattedMessage id='lists.exclusive' defaultMessage='Hide these posts from home' />
|
<FormattedMessage id='lists.exclusive' defaultMessage='Hide these posts from home' />
|
||||||
</label>
|
</label>
|
||||||
|
@ -18,6 +18,8 @@ import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlin
|
|||||||
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
|
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
|
||||||
import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg';
|
import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg';
|
||||||
|
|
||||||
|
import { ReactComponent as RepeatDisabledIcon } from 'mastodon/../svg-icons/repeat_disabled.svg';
|
||||||
|
import { ReactComponent as RepeatPrivateIcon } from 'mastodon/../svg-icons/repeat_private.svg';
|
||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
|
||||||
@ -280,6 +282,7 @@ class ActionBar extends PureComponent {
|
|||||||
|
|
||||||
let replyIcon;
|
let replyIcon;
|
||||||
let replyIconComponent;
|
let replyIconComponent;
|
||||||
|
|
||||||
if (status.get('in_reply_to_id', null) === null) {
|
if (status.get('in_reply_to_id', null) === null) {
|
||||||
replyIcon = 'reply';
|
replyIcon = 'reply';
|
||||||
replyIconComponent = ReplyIcon;
|
replyIconComponent = ReplyIcon;
|
||||||
@ -290,21 +293,26 @@ class ActionBar extends PureComponent {
|
|||||||
|
|
||||||
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
|
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
|
||||||
|
|
||||||
let reblogTitle;
|
let reblogTitle, reblogIconComponent;
|
||||||
|
|
||||||
if (status.get('reblogged')) {
|
if (status.get('reblogged')) {
|
||||||
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
||||||
|
reblogIconComponent = publicStatus ? RepeatIcon : RepeatPrivateIcon;
|
||||||
} else if (publicStatus) {
|
} else if (publicStatus) {
|
||||||
reblogTitle = intl.formatMessage(messages.reblog);
|
reblogTitle = intl.formatMessage(messages.reblog);
|
||||||
|
reblogIconComponent = RepeatIcon;
|
||||||
} else if (reblogPrivate) {
|
} else if (reblogPrivate) {
|
||||||
reblogTitle = intl.formatMessage(messages.reblog_private);
|
reblogTitle = intl.formatMessage(messages.reblog_private);
|
||||||
|
reblogIconComponent = RepeatPrivateIcon;
|
||||||
} else {
|
} else {
|
||||||
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
||||||
|
reblogIconComponent = RepeatDisabledIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='detailed-status__action-bar'>
|
<div className='detailed-status__action-bar'>
|
||||||
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} /></div>
|
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} /></div>
|
||||||
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} /></div>
|
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} /></div>
|
||||||
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} /></div>
|
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} /></div>
|
||||||
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} /></div>
|
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} /></div>
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"account.badges.group": "Groep",
|
"account.badges.group": "Groep",
|
||||||
"account.block": "Blokkeer @{name}",
|
"account.block": "Blokkeer @{name}",
|
||||||
"account.block_domain": "Blokkeer domein {domain}",
|
"account.block_domain": "Blokkeer domein {domain}",
|
||||||
|
"account.block_short": "Blokkeer",
|
||||||
"account.blocked": "Geblokkeer",
|
"account.blocked": "Geblokkeer",
|
||||||
"account.browse_more_on_origin_server": "Verken die oorspronklike profiel",
|
"account.browse_more_on_origin_server": "Verken die oorspronklike profiel",
|
||||||
"account.cancel_follow_request": "Herroep volgversoek",
|
"account.cancel_follow_request": "Herroep volgversoek",
|
||||||
@ -45,6 +46,7 @@
|
|||||||
"account.posts_with_replies": "Plasings en antwoorde",
|
"account.posts_with_replies": "Plasings en antwoorde",
|
||||||
"account.report": "Rapporteer @{name}",
|
"account.report": "Rapporteer @{name}",
|
||||||
"account.requested": "Wag op goedkeuring. Klik om volgversoek te kanselleer",
|
"account.requested": "Wag op goedkeuring. Klik om volgversoek te kanselleer",
|
||||||
|
"account.requested_follow": "{name} het versoek om jou te volg",
|
||||||
"account.share": "Deel @{name} se profiel",
|
"account.share": "Deel @{name} se profiel",
|
||||||
"account.show_reblogs": "Wys aangestuurde plasings van @{name}",
|
"account.show_reblogs": "Wys aangestuurde plasings van @{name}",
|
||||||
"account.statuses_counter": "{count, plural, one {{counter} Plaas} other {{counter} Plasings}}",
|
"account.statuses_counter": "{count, plural, one {{counter} Plaas} other {{counter} Plasings}}",
|
||||||
@ -82,6 +84,7 @@
|
|||||||
"column.community": "Plaaslike tydlyn",
|
"column.community": "Plaaslike tydlyn",
|
||||||
"column.directory": "Blaai deur profiele",
|
"column.directory": "Blaai deur profiele",
|
||||||
"column.domain_blocks": "Geblokkeerde domeine",
|
"column.domain_blocks": "Geblokkeerde domeine",
|
||||||
|
"column.favourites": "Gunstelinge",
|
||||||
"column.follow_requests": "Volgversoeke",
|
"column.follow_requests": "Volgversoeke",
|
||||||
"column.home": "Tuis",
|
"column.home": "Tuis",
|
||||||
"column.lists": "Lyste",
|
"column.lists": "Lyste",
|
||||||
@ -271,6 +274,7 @@
|
|||||||
"privacy.unlisted.short": "Ongelys",
|
"privacy.unlisted.short": "Ongelys",
|
||||||
"privacy_policy.last_updated": "Laaste bywerking op {date}",
|
"privacy_policy.last_updated": "Laaste bywerking op {date}",
|
||||||
"privacy_policy.title": "Privaatheidsbeleid",
|
"privacy_policy.title": "Privaatheidsbeleid",
|
||||||
|
"regeneration_indicator.sublabel": "Jou tuis-voer word voorberei!",
|
||||||
"reply_indicator.cancel": "Kanselleer",
|
"reply_indicator.cancel": "Kanselleer",
|
||||||
"report.placeholder": "Type or paste additional comments",
|
"report.placeholder": "Type or paste additional comments",
|
||||||
"report.submit": "Submit report",
|
"report.submit": "Submit report",
|
||||||
|
@ -201,7 +201,7 @@
|
|||||||
"disabled_account_banner.text": "Ваш уліковы запіс {disabledAccount} часова адключаны.",
|
"disabled_account_banner.text": "Ваш уліковы запіс {disabledAccount} часова адключаны.",
|
||||||
"dismissable_banner.community_timeline": "Гэта самыя апошнія допісы ад людзей, уліковыя запісы якіх размяшчаюцца на {domain}.",
|
"dismissable_banner.community_timeline": "Гэта самыя апошнія допісы ад людзей, уліковыя запісы якіх размяшчаюцца на {domain}.",
|
||||||
"dismissable_banner.dismiss": "Адхіліць",
|
"dismissable_banner.dismiss": "Адхіліць",
|
||||||
"dismissable_banner.explore_links": "Гэтыя навіны абмяркоўваюцца прама зараз на гэтым і іншых серверах дэцэнтралізаванай сеткі.",
|
"dismissable_banner.explore_links": "Гэтыя навіны абмяркоўваюцца цяпер на гэтым і іншых серверах дэцэнтралізаванай сеткі.",
|
||||||
"dismissable_banner.explore_statuses": "Допісы з гэтага і іншых сервераў дэцэнтралізаванай сеткі, якія набіраюць папулярнасць прама зараз.",
|
"dismissable_banner.explore_statuses": "Допісы з гэтага і іншых сервераў дэцэнтралізаванай сеткі, якія набіраюць папулярнасць прама зараз.",
|
||||||
"dismissable_banner.explore_tags": "Гэтыя хэштэгі зараз набіраюць папулярнасць сярод людзей на гэтым і іншых серверах дэцэнтралізаванай сеткі",
|
"dismissable_banner.explore_tags": "Гэтыя хэштэгі зараз набіраюць папулярнасць сярод людзей на гэтым і іншых серверах дэцэнтралізаванай сеткі",
|
||||||
"dismissable_banner.public_timeline": "Гэта апошнія публічныя допісы людзей з усей сеткі, за якімі сочаць карыстальнікі {domain}.",
|
"dismissable_banner.public_timeline": "Гэта апошнія публічныя допісы людзей з усей сеткі, за якімі сочаць карыстальнікі {domain}.",
|
||||||
@ -482,7 +482,7 @@
|
|||||||
"onboarding.share.lead": "Дайце людзям ведаць, як яны могуць знайсці вас на Mastodon!",
|
"onboarding.share.lead": "Дайце людзям ведаць, як яны могуць знайсці вас на Mastodon!",
|
||||||
"onboarding.share.message": "Я {username} на #Mastodon! Сачыце за мной на {url}",
|
"onboarding.share.message": "Я {username} на #Mastodon! Сачыце за мной на {url}",
|
||||||
"onboarding.share.next_steps": "Магчымыя наступныя крокі:",
|
"onboarding.share.next_steps": "Магчымыя наступныя крокі:",
|
||||||
"onboarding.share.title": "Падзяліцеся сваім профілем",
|
"onboarding.share.title": "Абагульце свой профіль",
|
||||||
"onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:",
|
"onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:",
|
||||||
"onboarding.start.skip": "Want to skip right ahead?",
|
"onboarding.start.skip": "Want to skip right ahead?",
|
||||||
"onboarding.start.title": "Вы зрабілі гэта!",
|
"onboarding.start.title": "Вы зрабілі гэта!",
|
||||||
@ -493,7 +493,7 @@
|
|||||||
"onboarding.steps.setup_profile.body": "Others are more likely to interact with you with a filled out profile.",
|
"onboarding.steps.setup_profile.body": "Others are more likely to interact with you with a filled out profile.",
|
||||||
"onboarding.steps.setup_profile.title": "Customize your profile",
|
"onboarding.steps.setup_profile.title": "Customize your profile",
|
||||||
"onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!",
|
"onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!",
|
||||||
"onboarding.steps.share_profile.title": "Share your profile",
|
"onboarding.steps.share_profile.title": "Абагульць ваш профіль у Mastodon",
|
||||||
"onboarding.tips.2fa": "<strong>Ці вы ведаеце?</strong> Вы можаце абараніць свой уліковы запіс, усталяваўшы двухфактарную аўтэнтыфікацыю ў наладах уліковага запісу. Яна працуе з любой праграмай TOTP на ваш выбар, нумар тэлефона не патрэбны!",
|
"onboarding.tips.2fa": "<strong>Ці вы ведаеце?</strong> Вы можаце абараніць свой уліковы запіс, усталяваўшы двухфактарную аўтэнтыфікацыю ў наладах уліковага запісу. Яна працуе з любой праграмай TOTP на ваш выбар, нумар тэлефона не патрэбны!",
|
||||||
"onboarding.tips.accounts_from_other_servers": "<strong>Ці вы ведаеце?</strong> Паколькі Mastodon дэцэнтралізаваны, некаторыя профілі, якія вам трапляюцца, будуць размяшчацца на іншых серверах, адрозных ад вашага. І ўсё ж вы можаце бесперашкодна ўзаемадзейнічаць з імі! Іх сервер пазначаны ў другой палове імя карыстальніка!",
|
"onboarding.tips.accounts_from_other_servers": "<strong>Ці вы ведаеце?</strong> Паколькі Mastodon дэцэнтралізаваны, некаторыя профілі, якія вам трапляюцца, будуць размяшчацца на іншых серверах, адрозных ад вашага. І ўсё ж вы можаце бесперашкодна ўзаемадзейнічаць з імі! Іх сервер пазначаны ў другой палове імя карыстальніка!",
|
||||||
"onboarding.tips.migration": "<strong>Ці вы ведаеце?</strong> Калі вы адчуваеце, што {domain} не з'яўляецца для вас лепшым выбарам у будучыні, вы можаце перайсці на іншы сервер Mastodon, не губляючы сваіх падпісчыкаў. Вы нават можаце стварыць свой уласны сервер!",
|
"onboarding.tips.migration": "<strong>Ці вы ведаеце?</strong> Калі вы адчуваеце, што {domain} не з'яўляецца для вас лепшым выбарам у будучыні, вы можаце перайсці на іншы сервер Mastodon, не губляючы сваіх падпісчыкаў. Вы нават можаце стварыць свой уласны сервер!",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"emoji_button.search_results": "Resultats de la cerca",
|
"emoji_button.search_results": "Resultats de la cerca",
|
||||||
"emoji_button.symbols": "Símbols",
|
"emoji_button.symbols": "Símbols",
|
||||||
"emoji_button.travel": "Viatges i llocs",
|
"emoji_button.travel": "Viatges i llocs",
|
||||||
|
"empty_column.account_hides_collections": "Aquest usuari ha elegit no mostrar aquesta informació",
|
||||||
"empty_column.account_suspended": "Compte suspès",
|
"empty_column.account_suspended": "Compte suspès",
|
||||||
"empty_column.account_timeline": "No hi ha tuts aquí!",
|
"empty_column.account_timeline": "No hi ha tuts aquí!",
|
||||||
"empty_column.account_unavailable": "Perfil no disponible",
|
"empty_column.account_unavailable": "Perfil no disponible",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"emoji_button.search_results": "Sykresultaten",
|
"emoji_button.search_results": "Sykresultaten",
|
||||||
"emoji_button.symbols": "Symboalen",
|
"emoji_button.symbols": "Symboalen",
|
||||||
"emoji_button.travel": "Reizgje en lokaasjes",
|
"emoji_button.travel": "Reizgje en lokaasjes",
|
||||||
|
"empty_column.account_hides_collections": "Dizze brûker hat derfoar keazen dizze ynformaasje net beskikber te meitsjen",
|
||||||
"empty_column.account_suspended": "Account beskoattele",
|
"empty_column.account_suspended": "Account beskoattele",
|
||||||
"empty_column.account_timeline": "Hjir binne gjin berjochten!",
|
"empty_column.account_timeline": "Hjir binne gjin berjochten!",
|
||||||
"empty_column.account_unavailable": "Profyl net beskikber",
|
"empty_column.account_unavailable": "Profyl net beskikber",
|
||||||
|
@ -41,6 +41,8 @@
|
|||||||
"account.languages": "Keisti prenumeruojamas kalbas",
|
"account.languages": "Keisti prenumeruojamas kalbas",
|
||||||
"account.locked_info": "Šios paskyros privatumo būsena nustatyta kaip užrakinta. Savininkas (-ė) rankiniu būdu peržiūri, kas gali sekti.",
|
"account.locked_info": "Šios paskyros privatumo būsena nustatyta kaip užrakinta. Savininkas (-ė) rankiniu būdu peržiūri, kas gali sekti.",
|
||||||
"account.media": "Medija",
|
"account.media": "Medija",
|
||||||
|
"account.mention": "Paminėti @{name}",
|
||||||
|
"account.moved_to": "{name} nurodė, kad dabar jų nauja paskyra yra:",
|
||||||
"account.mute": "Užtildyti @{name}",
|
"account.mute": "Užtildyti @{name}",
|
||||||
"account.muted": "Užtildytas",
|
"account.muted": "Užtildytas",
|
||||||
"account.posts": "Toots",
|
"account.posts": "Toots",
|
||||||
@ -53,10 +55,15 @@
|
|||||||
"account.unfollow": "Nebesekti",
|
"account.unfollow": "Nebesekti",
|
||||||
"account.unmute_short": "Atitildyti",
|
"account.unmute_short": "Atitildyti",
|
||||||
"account_note.placeholder": "Click to add a note",
|
"account_note.placeholder": "Click to add a note",
|
||||||
"alert.unexpected.title": "Oi!",
|
"alert.unexpected.message": "Įvyko netikėta klaida.",
|
||||||
|
"alert.unexpected.title": "Ups!",
|
||||||
"announcement.announcement": "Skelbimas",
|
"announcement.announcement": "Skelbimas",
|
||||||
|
"attachments_list.unprocessed": "(neapdorotas)",
|
||||||
"audio.hide": "Slėpti garsą",
|
"audio.hide": "Slėpti garsą",
|
||||||
"autosuggest_hashtag.per_week": "{count} per savaitę",
|
"autosuggest_hashtag.per_week": "{count} per savaitę",
|
||||||
|
"boost_modal.combo": "Gali spausti {combo}, kad praleisti kitą kartą",
|
||||||
|
"bundle_column_error.copy_stacktrace": "Kopijuoti klaidos ataskaitą",
|
||||||
|
"bundle_column_error.error.body": "Užklausos puslapio nepavyko atvaizduoti. Tai gali būti dėl mūsų kodo klaidos arba naršyklės suderinamumo problemos.",
|
||||||
"bundle_column_error.error.title": "O, ne!",
|
"bundle_column_error.error.title": "O, ne!",
|
||||||
"column.domain_blocks": "Hidden domains",
|
"column.domain_blocks": "Hidden domains",
|
||||||
"column.lists": "Sąrašai",
|
"column.lists": "Sąrašai",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"emoji_button.search_results": "Rezultati iskanja",
|
"emoji_button.search_results": "Rezultati iskanja",
|
||||||
"emoji_button.symbols": "Simboli",
|
"emoji_button.symbols": "Simboli",
|
||||||
"emoji_button.travel": "Potovanja in kraji",
|
"emoji_button.travel": "Potovanja in kraji",
|
||||||
|
"empty_column.account_hides_collections": "Ta uporabnik se je odločil, da te informacije ne bo dal na voljo",
|
||||||
"empty_column.account_suspended": "Račun je suspendiran",
|
"empty_column.account_suspended": "Račun je suspendiran",
|
||||||
"empty_column.account_timeline": "Tukaj ni objav!",
|
"empty_column.account_timeline": "Tukaj ni objav!",
|
||||||
"empty_column.account_unavailable": "Profil ni na voljo",
|
"empty_column.account_unavailable": "Profil ni na voljo",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"emoji_button.search_results": "Rezultati pretrage",
|
"emoji_button.search_results": "Rezultati pretrage",
|
||||||
"emoji_button.symbols": "Simboli",
|
"emoji_button.symbols": "Simboli",
|
||||||
"emoji_button.travel": "Putovanja i mesta",
|
"emoji_button.travel": "Putovanja i mesta",
|
||||||
|
"empty_column.account_hides_collections": "Ovaj korisnik je odlučio da ove informacije ne učini dostupnim",
|
||||||
"empty_column.account_suspended": "Nalog je suspendovan",
|
"empty_column.account_suspended": "Nalog je suspendovan",
|
||||||
"empty_column.account_timeline": "Nema objava ovde!",
|
"empty_column.account_timeline": "Nema objava ovde!",
|
||||||
"empty_column.account_unavailable": "Profil je nedostupan",
|
"empty_column.account_unavailable": "Profil je nedostupan",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"emoji_button.search_results": "Резултати претраге",
|
"emoji_button.search_results": "Резултати претраге",
|
||||||
"emoji_button.symbols": "Симболи",
|
"emoji_button.symbols": "Симболи",
|
||||||
"emoji_button.travel": "Путовања и места",
|
"emoji_button.travel": "Путовања и места",
|
||||||
|
"empty_column.account_hides_collections": "Овај корисник је одлучио да ове информације не учини доступним",
|
||||||
"empty_column.account_suspended": "Налог је суспендован",
|
"empty_column.account_suspended": "Налог је суспендован",
|
||||||
"empty_column.account_timeline": "Нема објава овде!",
|
"empty_column.account_timeline": "Нема објава овде!",
|
||||||
"empty_column.account_unavailable": "Профил је недоступан",
|
"empty_column.account_unavailable": "Профил је недоступан",
|
||||||
|
5
app/javascript/svg-icons/repeat_disabled.svg
Executable file
5
app/javascript/svg-icons/repeat_disabled.svg
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19 13V17.8787L17 15.8787V13H19Z"/>
|
||||||
|
<path d="M2.41421 2.70711L1 4.12132L5 8.12132V11H7V10.1213L13.8787 17H6.85L8.4 15.45L7 14L3 18L7 22L8.4 20.55L6.85 19H15.8787L19.3848 22.5061L20.799 21.0919L2.41421 2.70711Z"/>
|
||||||
|
<path d="M17.15 7H8.12132L6.12132 5H17.15L15.6 3.45L17 2L21 6L17 10L15.6 8.55L17.15 7Z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 415 B |
5
app/javascript/svg-icons/repeat_private.svg
Executable file
5
app/javascript/svg-icons/repeat_private.svg
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.4 15.45L7 14L3 18L7 22L8.4 20.55L6.85 19H13.5V18C13.5 17.6567 13.5638 17.3171 13.6988 17H6.85L8.4 15.45Z"/>
|
||||||
|
<path d="M5 5V11H7V7H17.15L15.6 8.55L17 10L21 6L17 2L15.6 3.45L17.15 5H5Z"/>
|
||||||
|
<path d="M16 22C15.7167 22 15.475 21.9083 15.275 21.725C15.0917 21.525 15 21.2833 15 21V18C15 17.7167 15.0917 17.4833 15.275 17.3C15.475 17.1 15.7167 17 16 17V16C16 15.45 16.1917 14.9833 16.575 14.6C16.975 14.2 17.45 14 18 14C18.55 14 19.0167 14.2 19.4 14.6C19.8 14.9833 20 15.45 20 16V17C20.2833 17 20.5167 17.1 20.7 17.3C20.9 17.4833 21 17.7167 21 18V21C21 21.2833 20.9 21.525 20.7 21.725C20.5167 21.9083 20.2833 22 20 22H16ZM17 17H19V16C19 15.7167 18.9 15.4833 18.7 15.3C18.5167 15.1 18.2833 15 18 15C17.7167 15 17.475 15.1 17.275 15.3C17.0917 15.4833 17 15.7167 17 16V17Z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 879 B |
@ -33,11 +33,11 @@ class Webhook < ApplicationRecord
|
|||||||
validates :secret, presence: true, length: { minimum: 12 }
|
validates :secret, presence: true, length: { minimum: 12 }
|
||||||
validates :events, presence: true
|
validates :events, presence: true
|
||||||
|
|
||||||
validate :validate_events
|
validate :events_validation_error, if: :invalid_events?
|
||||||
validate :validate_permissions
|
validate :validate_permissions
|
||||||
validate :validate_template
|
validate :validate_template
|
||||||
|
|
||||||
before_validation :strip_events
|
normalizes :events, with: ->(events) { events.filter_map { |event| event.strip.presence } }
|
||||||
before_validation :generate_secret
|
before_validation :generate_secret
|
||||||
|
|
||||||
def rotate_secret!
|
def rotate_secret!
|
||||||
@ -69,8 +69,12 @@ class Webhook < ApplicationRecord
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def validate_events
|
def events_validation_error
|
||||||
errors.add(:events, :invalid) if events.any? { |e| EVENTS.exclude?(e) }
|
errors.add(:events, :invalid)
|
||||||
|
end
|
||||||
|
|
||||||
|
def invalid_events?
|
||||||
|
events.blank? || events.difference(EVENTS).any?
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_permissions
|
def validate_permissions
|
||||||
@ -88,10 +92,6 @@ class Webhook < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def strip_events
|
|
||||||
self.events = events.filter_map { |str| str.strip.presence } if events.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_secret
|
def generate_secret
|
||||||
self.secret = SecureRandom.hex(20) if secret.blank?
|
self.secret = SecureRandom.hex(20) if secret.blank?
|
||||||
end
|
end
|
||||||
|
@ -180,7 +180,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
|||||||
end
|
end
|
||||||
|
|
||||||
def check_links!
|
def check_links!
|
||||||
VerifyAccountLinksWorker.perform_async(@account.id)
|
VerifyAccountLinksWorker.perform_in(rand(10.minutes.to_i), @account.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_duplicate_accounts!
|
def process_duplicate_accounts!
|
||||||
|
@ -30,11 +30,7 @@ class UpdateAccountService < BaseService
|
|||||||
def check_links(account)
|
def check_links(account)
|
||||||
return unless account.fields.any?(&:requires_verification?)
|
return unless account.fields.any?(&:requires_verification?)
|
||||||
|
|
||||||
if account.local?
|
|
||||||
VerifyAccountLinksWorker.perform_async(account.id)
|
VerifyAccountLinksWorker.perform_async(account.id)
|
||||||
else
|
|
||||||
VerifyAccountLinksWorker.perform_in(rand(10.minutes.to_i), account.id)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_hashtags(account)
|
def process_hashtags(account)
|
||||||
|
@ -53,3 +53,7 @@ af:
|
|||||||
position:
|
position:
|
||||||
elevated: kan nie hoër as jou huidige rol wees nie
|
elevated: kan nie hoër as jou huidige rol wees nie
|
||||||
own_role: kan nie verander word met jou huidige rol nie
|
own_role: kan nie verander word met jou huidige rol nie
|
||||||
|
webhook:
|
||||||
|
attributes:
|
||||||
|
events:
|
||||||
|
invalid_permissions: geleenthede waartoe jy nie toegang het nie mag nie ingesluit word nie
|
||||||
|
@ -5,7 +5,23 @@ af:
|
|||||||
contact_unavailable: NVT
|
contact_unavailable: NVT
|
||||||
hosted_on: Mastodon gehuisves op %{domain}
|
hosted_on: Mastodon gehuisves op %{domain}
|
||||||
title: Aangaande
|
title: Aangaande
|
||||||
|
accounts:
|
||||||
|
follow: Volg
|
||||||
|
followers:
|
||||||
|
one: Volgeling
|
||||||
|
other: Volgelinge
|
||||||
|
following: Volg
|
||||||
|
nothing_here: Daar is niks hier nie!
|
||||||
|
posts:
|
||||||
|
one: Plasing
|
||||||
|
other: Plasings
|
||||||
|
posts_tab_heading: Plasings
|
||||||
admin:
|
admin:
|
||||||
|
account_actions:
|
||||||
|
action: Voer aksie uit
|
||||||
|
title: Voer modereer aksie uit op %{acct}
|
||||||
|
account_moderation_notes:
|
||||||
|
create: Los nota
|
||||||
accounts:
|
accounts:
|
||||||
location:
|
location:
|
||||||
local: Plaaslik
|
local: Plaaslik
|
||||||
@ -102,6 +118,7 @@ af:
|
|||||||
types:
|
types:
|
||||||
bookmarks: Boekmerke
|
bookmarks: Boekmerke
|
||||||
invites:
|
invites:
|
||||||
|
invalid: Hierdie uitnodiging is nie geldig nie
|
||||||
title: Nooi ander
|
title: Nooi ander
|
||||||
login_activities:
|
login_activities:
|
||||||
description_html: Indien jy onbekende aktiwiteite gewaar, oorweeg dit om jou wagwoord te verander en tweefaktorverifikasie te aktiveer.
|
description_html: Indien jy onbekende aktiwiteite gewaar, oorweeg dit om jou wagwoord te verander en tweefaktorverifikasie te aktiveer.
|
||||||
|
@ -1418,6 +1418,7 @@ be:
|
|||||||
'86400': 1 дзень
|
'86400': 1 дзень
|
||||||
expires_in_prompt: Ніколі
|
expires_in_prompt: Ніколі
|
||||||
generate: Стварыць запрашальную спасылку
|
generate: Стварыць запрашальную спасылку
|
||||||
|
invalid: Гэта запрашэнне несапраўднае
|
||||||
invited_by: 'Вас запрасіў(-ла):'
|
invited_by: 'Вас запрасіў(-ла):'
|
||||||
max_uses:
|
max_uses:
|
||||||
few: "%{count} выкарыстанні"
|
few: "%{count} выкарыстанні"
|
||||||
|
@ -1358,6 +1358,7 @@ ca:
|
|||||||
'86400': 1 dia
|
'86400': 1 dia
|
||||||
expires_in_prompt: Mai
|
expires_in_prompt: Mai
|
||||||
generate: Genera
|
generate: Genera
|
||||||
|
invalid: Aquesta invitació no és vàlida
|
||||||
invited_by: 'Has estat invitat per:'
|
invited_by: 'Has estat invitat per:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 ús
|
one: 1 ús
|
||||||
|
@ -1468,6 +1468,7 @@ cy:
|
|||||||
'86400': 1 diwrnod
|
'86400': 1 diwrnod
|
||||||
expires_in_prompt: Byth
|
expires_in_prompt: Byth
|
||||||
generate: Cynhyrchu dolen wahoddiad
|
generate: Cynhyrchu dolen wahoddiad
|
||||||
|
invalid: Nid yw'r gwahoddiad hwn yn ddilys
|
||||||
invited_by: 'Cawsoch eich gwahodd gan:'
|
invited_by: 'Cawsoch eich gwahodd gan:'
|
||||||
max_uses:
|
max_uses:
|
||||||
few: "%{count} defnydd"
|
few: "%{count} defnydd"
|
||||||
|
@ -1110,6 +1110,7 @@ da:
|
|||||||
functional: Din konto er fuldt funktionel.
|
functional: Din konto er fuldt funktionel.
|
||||||
pending: Din ansøgning afventer gennemgang af vores medarbejdere. Dette kan tage noget tid. Du modtager en e-mail, hvis din ansøgning godkendes.
|
pending: Din ansøgning afventer gennemgang af vores medarbejdere. Dette kan tage noget tid. Du modtager en e-mail, hvis din ansøgning godkendes.
|
||||||
redirecting_to: Din konto er inaktiv, da den pt. er omdirigerer til %{acct}.
|
redirecting_to: Din konto er inaktiv, da den pt. er omdirigerer til %{acct}.
|
||||||
|
self_destruct: Da %{domain} er under nedlukning, vil kontoadgangen være begrænset.
|
||||||
view_strikes: Se tidligere anmeldelser af din konto
|
view_strikes: Se tidligere anmeldelser af din konto
|
||||||
too_fast: Formularen indsendt for hurtigt, forsøg igen.
|
too_fast: Formularen indsendt for hurtigt, forsøg igen.
|
||||||
use_security_key: Brug sikkerhedsnøgle
|
use_security_key: Brug sikkerhedsnøgle
|
||||||
@ -1367,6 +1368,7 @@ da:
|
|||||||
'86400': 1 dag
|
'86400': 1 dag
|
||||||
expires_in_prompt: Aldrig
|
expires_in_prompt: Aldrig
|
||||||
generate: Generér invitationslink
|
generate: Generér invitationslink
|
||||||
|
invalid: Denne invitation er ikke gyldig
|
||||||
invited_by: 'Du blev inviteret af:'
|
invited_by: 'Du blev inviteret af:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 benyttelse
|
one: 1 benyttelse
|
||||||
@ -1579,6 +1581,9 @@ da:
|
|||||||
over_daily_limit: Den daglige grænse på %{limit} planlagte indlæg er nået
|
over_daily_limit: Den daglige grænse på %{limit} planlagte indlæg er nået
|
||||||
over_total_limit: Grænsen på %{limit} planlagte indlæg er nået
|
over_total_limit: Grænsen på %{limit} planlagte indlæg er nået
|
||||||
too_soon: Den planlagte dato skal være i fremtiden
|
too_soon: Den planlagte dato skal være i fremtiden
|
||||||
|
self_destruct:
|
||||||
|
lead_html: Desværre lukker <strong>%{domain}</strong> permanent. Har man en konto dér, vil fortsat brug heraf ikke være mulig. Man kan dog stadig anmode om en sikkerhedskopi af sine data.
|
||||||
|
title: Denne server er under nedlukning
|
||||||
sessions:
|
sessions:
|
||||||
activity: Seneste aktivitet
|
activity: Seneste aktivitet
|
||||||
browser: Browser
|
browser: Browser
|
||||||
|
@ -1368,6 +1368,7 @@ de:
|
|||||||
'86400': 1 Tag
|
'86400': 1 Tag
|
||||||
expires_in_prompt: Nie
|
expires_in_prompt: Nie
|
||||||
generate: Einladungslink erstellen
|
generate: Einladungslink erstellen
|
||||||
|
invalid: Diese Einladung ist ungültig
|
||||||
invited_by: 'Du wurdest eingeladen von:'
|
invited_by: 'Du wurdest eingeladen von:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: Eine Verwendung
|
one: Eine Verwendung
|
||||||
|
@ -18,7 +18,7 @@ be:
|
|||||||
unconfirmed: Вы павінны пацвердзіць свой адрас электроннай пошты, перш чым працягнуць
|
unconfirmed: Вы павінны пацвердзіць свой адрас электроннай пошты, перш чым працягнуць
|
||||||
mailer:
|
mailer:
|
||||||
confirmation_instructions:
|
confirmation_instructions:
|
||||||
action: Пацвердзіце адрас электроннай пошты
|
action: Пацвердзіць адрас электроннай пошты
|
||||||
action_with_app: Пацвердзіць і вярнуцца да %{app}
|
action_with_app: Пацвердзіць і вярнуцца да %{app}
|
||||||
explanation: Вы стварылі ўліковы запіс на %{host} з гэтым адрасам электроннай пошты. Вам спатрэбіцца ўсяго адзін клік, каб пацвердзіць яго. Калі гэта былі не вы, то проста праігнаруйце гэты ліст.
|
explanation: Вы стварылі ўліковы запіс на %{host} з гэтым адрасам электроннай пошты. Вам спатрэбіцца ўсяго адзін клік, каб пацвердзіць яго. Калі гэта былі не вы, то проста праігнаруйце гэты ліст.
|
||||||
explanation_when_pending: Вы падалі заяўку на запрашэнне на %{host} з гэтым адрасам электроннай пошты. Як толькі вы пацвердзіце свой адрас электроннай пошты, мы разгледзім вашу заяўку. Вы можаце ўвайсці, каб змяніць свае дадзеныя або выдаліць свой уліковы запіс, але вы не можаце атрымаць доступ да большасці функцый, пакуль ваш уліковы запіс не будзе зацверджаны. Калі ваша заяўка будзе адхілена, вашы даныя будуць выдалены, таму ад вас не спатрэбіцца ніякіх дадатковых дзеянняў. Калі гэта былі не вы, ігнаруйце гэты ліст
|
explanation_when_pending: Вы падалі заяўку на запрашэнне на %{host} з гэтым адрасам электроннай пошты. Як толькі вы пацвердзіце свой адрас электроннай пошты, мы разгледзім вашу заяўку. Вы можаце ўвайсці, каб змяніць свае дадзеныя або выдаліць свой уліковы запіс, але вы не можаце атрымаць доступ да большасці функцый, пакуль ваш уліковы запіс не будзе зацверджаны. Калі ваша заяўка будзе адхілена, вашы даныя будуць выдалены, таму ад вас не спатрэбіцца ніякіх дадатковых дзеянняў. Калі гэта былі не вы, ігнаруйце гэты ліст
|
||||||
|
@ -149,6 +149,7 @@ af:
|
|||||||
write:blocks: blokkeer rekeninge en domeine
|
write:blocks: blokkeer rekeninge en domeine
|
||||||
write:bookmarks: laat ’n boekmerk by plasings
|
write:bookmarks: laat ’n boekmerk by plasings
|
||||||
write:conversations: doof en wis gesprekke uit
|
write:conversations: doof en wis gesprekke uit
|
||||||
|
write:favourites: gunsteling plasings
|
||||||
write:filters: skep filters
|
write:filters: skep filters
|
||||||
write:follows: volg mense
|
write:follows: volg mense
|
||||||
write:lists: skep lyste
|
write:lists: skep lyste
|
||||||
|
@ -1368,6 +1368,7 @@ es-AR:
|
|||||||
'86400': 1 día
|
'86400': 1 día
|
||||||
expires_in_prompt: Nunca
|
expires_in_prompt: Nunca
|
||||||
generate: Generar enlace de invitación
|
generate: Generar enlace de invitación
|
||||||
|
invalid: Esta invitación no es válida
|
||||||
invited_by: 'Fuiste invitado por:'
|
invited_by: 'Fuiste invitado por:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 uso
|
one: 1 uso
|
||||||
|
@ -1368,6 +1368,7 @@ es-MX:
|
|||||||
'86400': 1 día
|
'86400': 1 día
|
||||||
expires_in_prompt: Nunca
|
expires_in_prompt: Nunca
|
||||||
generate: Generar
|
generate: Generar
|
||||||
|
invalid: Esta invitación no es válida
|
||||||
invited_by: 'Fuiste invitado por:'
|
invited_by: 'Fuiste invitado por:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 uso
|
one: 1 uso
|
||||||
|
@ -1368,6 +1368,7 @@ es:
|
|||||||
'86400': 1 día
|
'86400': 1 día
|
||||||
expires_in_prompt: Nunca
|
expires_in_prompt: Nunca
|
||||||
generate: Generar
|
generate: Generar
|
||||||
|
invalid: Esta invitación no es válida
|
||||||
invited_by: 'Fuiste invitado por:'
|
invited_by: 'Fuiste invitado por:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 uso
|
one: 1 uso
|
||||||
|
@ -1363,6 +1363,7 @@ eu:
|
|||||||
'86400': Egun 1
|
'86400': Egun 1
|
||||||
expires_in_prompt: Inoiz ez
|
expires_in_prompt: Inoiz ez
|
||||||
generate: Sortu
|
generate: Sortu
|
||||||
|
invalid: Gonbidapen hau ez da baliozkoa
|
||||||
invited_by: 'Honek gonbidatu zaitu:'
|
invited_by: 'Honek gonbidatu zaitu:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: Erabilera 1
|
one: Erabilera 1
|
||||||
|
@ -1157,6 +1157,7 @@ fa:
|
|||||||
'86400': ۱ روز
|
'86400': ۱ روز
|
||||||
expires_in_prompt: هیچ وقت
|
expires_in_prompt: هیچ وقت
|
||||||
generate: ساختن
|
generate: ساختن
|
||||||
|
invalid: این دعوتنامه معتبر نیست
|
||||||
invited_by: 'دعوتکنندهٔ شما:'
|
invited_by: 'دعوتکنندهٔ شما:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: ۱ بار
|
one: ۱ بار
|
||||||
|
@ -1368,6 +1368,7 @@ fo:
|
|||||||
'86400': 1 dag
|
'86400': 1 dag
|
||||||
expires_in_prompt: Ongantíð
|
expires_in_prompt: Ongantíð
|
||||||
generate: Ger innbjóðingarleinki
|
generate: Ger innbjóðingarleinki
|
||||||
|
invalid: Henda innbjóðing er ikki gildug
|
||||||
invited_by: 'Tú var bjóðað/ur av:'
|
invited_by: 'Tú var bjóðað/ur av:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 brúk
|
one: 1 brúk
|
||||||
|
@ -1368,6 +1368,7 @@ fr-QC:
|
|||||||
'86400': 1 jour
|
'86400': 1 jour
|
||||||
expires_in_prompt: Jamais
|
expires_in_prompt: Jamais
|
||||||
generate: Générer un lien d'invitation
|
generate: Générer un lien d'invitation
|
||||||
|
invalid: Cette invitation n’est pas valide
|
||||||
invited_by: 'Vous avez été invité·e par :'
|
invited_by: 'Vous avez été invité·e par :'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 utilisation
|
one: 1 utilisation
|
||||||
|
@ -1368,6 +1368,7 @@ fr:
|
|||||||
'86400': 1 jour
|
'86400': 1 jour
|
||||||
expires_in_prompt: Jamais
|
expires_in_prompt: Jamais
|
||||||
generate: Générer un lien d'invitation
|
generate: Générer un lien d'invitation
|
||||||
|
invalid: Cette invitation n’est pas valide
|
||||||
invited_by: 'Vous avez été invité·e par :'
|
invited_by: 'Vous avez été invité·e par :'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 utilisation
|
one: 1 utilisation
|
||||||
|
@ -1368,6 +1368,7 @@ fy:
|
|||||||
'86400': 1 dei
|
'86400': 1 dei
|
||||||
expires_in_prompt: Nea
|
expires_in_prompt: Nea
|
||||||
generate: Utnûgingskeppeling generearje
|
generate: Utnûgingskeppeling generearje
|
||||||
|
invalid: Dizze útnûging is net jildich
|
||||||
invited_by: 'Jo binne útnûge troch:'
|
invited_by: 'Jo binne útnûge troch:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 kear
|
one: 1 kear
|
||||||
|
@ -1368,6 +1368,7 @@ gl:
|
|||||||
'86400': 1 día
|
'86400': 1 día
|
||||||
expires_in_prompt: Nunca
|
expires_in_prompt: Nunca
|
||||||
generate: Xerar
|
generate: Xerar
|
||||||
|
invalid: Este convite non é válido
|
||||||
invited_by: 'Convidoute:'
|
invited_by: 'Convidoute:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 uso
|
one: 1 uso
|
||||||
|
@ -113,8 +113,8 @@ he:
|
|||||||
previous_strikes_description_html:
|
previous_strikes_description_html:
|
||||||
many: לחשבון הזה יש <strong>%{count}</strong> פסילות.
|
many: לחשבון הזה יש <strong>%{count}</strong> פסילות.
|
||||||
one: לחשבון הזה פסילה <strong>אחת</strong>.
|
one: לחשבון הזה פסילה <strong>אחת</strong>.
|
||||||
other: לחשבון הזה <strong>%{count}</strong> פסילות.
|
other: לחשבון הזה יש <strong>%{count}</strong> פסילות.
|
||||||
two: לחשבון הזה <strong>%{count}</strong> פסילות.
|
two: לחשבון הזה יש <strong>שתי</strong> פסילות.
|
||||||
promote: להעלות בדרגה
|
promote: להעלות בדרגה
|
||||||
protocol: פרטיכל
|
protocol: פרטיכל
|
||||||
public: פומבי
|
public: פומבי
|
||||||
@ -1418,6 +1418,7 @@ he:
|
|||||||
'86400': יום אחד
|
'86400': יום אחד
|
||||||
expires_in_prompt: לעולם לא
|
expires_in_prompt: לעולם לא
|
||||||
generate: יצירת קישור להזמנה
|
generate: יצירת קישור להזמנה
|
||||||
|
invalid: הזמנה זו אינה תקפה
|
||||||
invited_by: הוזמנת ע"י
|
invited_by: הוזמנת ע"י
|
||||||
max_uses:
|
max_uses:
|
||||||
many: "%{count} שימושים"
|
many: "%{count} שימושים"
|
||||||
|
@ -1368,6 +1368,7 @@ hu:
|
|||||||
'86400': 1 nap
|
'86400': 1 nap
|
||||||
expires_in_prompt: Soha
|
expires_in_prompt: Soha
|
||||||
generate: Generálás
|
generate: Generálás
|
||||||
|
invalid: Ez a meghívó nem érvényes
|
||||||
invited_by: 'Téged meghívott:'
|
invited_by: 'Téged meghívott:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 használat
|
one: 1 használat
|
||||||
|
@ -1372,6 +1372,7 @@ is:
|
|||||||
'86400': 1 dagur
|
'86400': 1 dagur
|
||||||
expires_in_prompt: Aldrei
|
expires_in_prompt: Aldrei
|
||||||
generate: Útbúa boðstengil
|
generate: Útbúa boðstengil
|
||||||
|
invalid: Þetta boð er ekki gilt
|
||||||
invited_by: 'Þér var boðið af:'
|
invited_by: 'Þér var boðið af:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 afnot
|
one: 1 afnot
|
||||||
|
@ -1370,6 +1370,7 @@ it:
|
|||||||
'86400': 1 giorno
|
'86400': 1 giorno
|
||||||
expires_in_prompt: Mai
|
expires_in_prompt: Mai
|
||||||
generate: Genera
|
generate: Genera
|
||||||
|
invalid: Questo invito non è valido
|
||||||
invited_by: 'Sei stato invitato da:'
|
invited_by: 'Sei stato invitato da:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: un uso
|
one: un uso
|
||||||
|
@ -1345,6 +1345,7 @@ ko:
|
|||||||
'86400': 1 일
|
'86400': 1 일
|
||||||
expires_in_prompt: 영원히
|
expires_in_prompt: 영원히
|
||||||
generate: 초대 링크 생성하기
|
generate: 초대 링크 생성하기
|
||||||
|
invalid: 이 초대는 올바르지 않습니다
|
||||||
invited_by: '당신을 초대한 사람:'
|
invited_by: '당신을 초대한 사람:'
|
||||||
max_uses:
|
max_uses:
|
||||||
other: "%{count}회"
|
other: "%{count}회"
|
||||||
|
@ -383,6 +383,7 @@ lt:
|
|||||||
'86400': 1 dienos
|
'86400': 1 dienos
|
||||||
expires_in_prompt: Niekada
|
expires_in_prompt: Niekada
|
||||||
generate: Generuoti
|
generate: Generuoti
|
||||||
|
invalid: Šis kvietimas negalioja.
|
||||||
invited_by: 'Jus pakvietė:'
|
invited_by: 'Jus pakvietė:'
|
||||||
max_uses:
|
max_uses:
|
||||||
few: "%{count} panaudojimai"
|
few: "%{count} panaudojimai"
|
||||||
|
@ -1368,6 +1368,7 @@ nl:
|
|||||||
'86400': 1 dag
|
'86400': 1 dag
|
||||||
expires_in_prompt: Nooit
|
expires_in_prompt: Nooit
|
||||||
generate: Uitnodigingslink genereren
|
generate: Uitnodigingslink genereren
|
||||||
|
invalid: Deze uitnodiging is niet geldig
|
||||||
invited_by: 'Jij bent uitgenodigd door:'
|
invited_by: 'Jij bent uitgenodigd door:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 keer
|
one: 1 keer
|
||||||
|
@ -1368,6 +1368,7 @@ nn:
|
|||||||
'86400': 1 dag
|
'86400': 1 dag
|
||||||
expires_in_prompt: Aldri
|
expires_in_prompt: Aldri
|
||||||
generate: Lag innbydingslenkje
|
generate: Lag innbydingslenkje
|
||||||
|
invalid: Denne invitasjonen er ikkje gyldig
|
||||||
invited_by: 'Du vart innboden av:'
|
invited_by: 'Du vart innboden av:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 bruk
|
one: 1 bruk
|
||||||
|
@ -1368,6 +1368,7 @@
|
|||||||
'86400': 1 dag
|
'86400': 1 dag
|
||||||
expires_in_prompt: Aldri
|
expires_in_prompt: Aldri
|
||||||
generate: Generer
|
generate: Generer
|
||||||
|
invalid: Denne invitasjonen er ikke gyldig
|
||||||
invited_by: 'Du ble invitert av:'
|
invited_by: 'Du ble invitert av:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 bruk
|
one: 1 bruk
|
||||||
|
@ -1418,6 +1418,7 @@ pl:
|
|||||||
'86400': dobie
|
'86400': dobie
|
||||||
expires_in_prompt: Nigdy
|
expires_in_prompt: Nigdy
|
||||||
generate: Wygeneruj
|
generate: Wygeneruj
|
||||||
|
invalid: Niepoprawne zaproszenie
|
||||||
invited_by: 'Zostałeś(-aś) zaproszony(-a) przez:'
|
invited_by: 'Zostałeś(-aś) zaproszony(-a) przez:'
|
||||||
max_uses:
|
max_uses:
|
||||||
few: "%{count} użycia"
|
few: "%{count} użycia"
|
||||||
|
@ -1368,6 +1368,7 @@ pt-BR:
|
|||||||
'86400': 1 dia
|
'86400': 1 dia
|
||||||
expires_in_prompt: Nunca
|
expires_in_prompt: Nunca
|
||||||
generate: Gerar convite
|
generate: Gerar convite
|
||||||
|
invalid: Este convite não é válido
|
||||||
invited_by: 'Você recebeu convite de:'
|
invited_by: 'Você recebeu convite de:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 uso
|
one: 1 uso
|
||||||
|
@ -1368,6 +1368,7 @@ pt-PT:
|
|||||||
'86400': 1 dia
|
'86400': 1 dia
|
||||||
expires_in_prompt: Nunca
|
expires_in_prompt: Nunca
|
||||||
generate: Gerar hiperligação de convite
|
generate: Gerar hiperligação de convite
|
||||||
|
invalid: Este convite não é válido
|
||||||
invited_by: 'Foi convidado por:'
|
invited_by: 'Foi convidado por:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 uso
|
one: 1 uso
|
||||||
|
@ -53,7 +53,7 @@ be:
|
|||||||
password: Не менш за 8 сімвалаў
|
password: Не менш за 8 сімвалаў
|
||||||
phrase: Параўнанне адбудзецца нягледзячы на рэгістр тэксту і папярэджанні аб змесціве допісу
|
phrase: Параўнанне адбудзецца нягледзячы на рэгістр тэксту і папярэджанні аб змесціве допісу
|
||||||
scopes: Якімі API праграм будзе дазволена карыстацца. Калі вы абярэце найвышэйшы ўзровень, не трэба абіраць асобныя.
|
scopes: Якімі API праграм будзе дазволена карыстацца. Калі вы абярэце найвышэйшы ўзровень, не трэба абіраць асобныя.
|
||||||
setting_aggregate_reblogs: Не паказваць новыя пашырэнні для допісаў, якія нядаўна пашырылі(уплывае выключна на будучыя пашырэнні)
|
setting_aggregate_reblogs: Не паказваць новыя пашырэнні для допісаў, якія пашырылі нядаўна (закранае толькі нядаўнія пашырэнні)
|
||||||
setting_always_send_emails: Звычайна лісты з апавяшчэннямі не будуць дасылацца, калі вы актыўна карыстаецеся Mastodon
|
setting_always_send_emails: Звычайна лісты з апавяшчэннямі не будуць дасылацца, калі вы актыўна карыстаецеся Mastodon
|
||||||
setting_default_sensitive: Далікатныя медыя прадвызначана схаваныя. Іх можна адкрыць адзіным клікам
|
setting_default_sensitive: Далікатныя медыя прадвызначана схаваныя. Іх можна адкрыць адзіным клікам
|
||||||
setting_display_media_default: Хаваць медыя пазначаныя як далікатныя
|
setting_display_media_default: Хаваць медыя пазначаныя як далікатныя
|
||||||
|
@ -592,6 +592,8 @@ sk:
|
|||||||
title: Ohľadom
|
title: Ohľadom
|
||||||
appearance:
|
appearance:
|
||||||
title: Vzhľad
|
title: Vzhľad
|
||||||
|
content_retention:
|
||||||
|
title: Ponechanie obsahu
|
||||||
discovery:
|
discovery:
|
||||||
follow_recommendations: Odporúčania pre nasledovanie
|
follow_recommendations: Odporúčania pre nasledovanie
|
||||||
profile_directory: Katalóg profilov
|
profile_directory: Katalóg profilov
|
||||||
@ -616,6 +618,7 @@ sk:
|
|||||||
delete: Vymaž nahratý súbor
|
delete: Vymaž nahratý súbor
|
||||||
destroyed_msg: Nahratie bolo zo stránky úspešne vymazané!
|
destroyed_msg: Nahratie bolo zo stránky úspešne vymazané!
|
||||||
software_updates:
|
software_updates:
|
||||||
|
critical_update: Kritické — prosím aktualizuj rýchlo
|
||||||
documentation_link: Zisti viac
|
documentation_link: Zisti viac
|
||||||
title: Dostupné aktualizácie
|
title: Dostupné aktualizácie
|
||||||
types:
|
types:
|
||||||
@ -646,6 +649,10 @@ sk:
|
|||||||
appeal_approved: Namietnuté
|
appeal_approved: Namietnuté
|
||||||
appeal_rejected: Námietka zamietnutá
|
appeal_rejected: Námietka zamietnutá
|
||||||
system_checks:
|
system_checks:
|
||||||
|
elasticsearch_preset:
|
||||||
|
action: Pozri dokumentáciu
|
||||||
|
elasticsearch_preset_single_node:
|
||||||
|
action: Pozri dokumentáciu
|
||||||
rules_check:
|
rules_check:
|
||||||
action: Spravuj serverové pravidlá
|
action: Spravuj serverové pravidlá
|
||||||
message_html: Neurčil/a si žiadne serverové pravidlá.
|
message_html: Neurčil/a si žiadne serverové pravidlá.
|
||||||
@ -925,6 +932,7 @@ sk:
|
|||||||
'86400': 1 deň
|
'86400': 1 deň
|
||||||
expires_in_prompt: Nikdy
|
expires_in_prompt: Nikdy
|
||||||
generate: Vygeneruj
|
generate: Vygeneruj
|
||||||
|
invalid: Táto pozvánka je neplatná
|
||||||
invited_by: 'Bol/a si pozvaný/á užívateľom:'
|
invited_by: 'Bol/a si pozvaný/á užívateľom:'
|
||||||
max_uses:
|
max_uses:
|
||||||
few: "%{count} využití"
|
few: "%{count} využití"
|
||||||
|
@ -1418,6 +1418,7 @@ sl:
|
|||||||
'86400': 1 dan
|
'86400': 1 dan
|
||||||
expires_in_prompt: Nikoli
|
expires_in_prompt: Nikoli
|
||||||
generate: Ustvari
|
generate: Ustvari
|
||||||
|
invalid: To povabilo ni veljavno
|
||||||
invited_by: 'Povabil/a vas je:'
|
invited_by: 'Povabil/a vas je:'
|
||||||
max_uses:
|
max_uses:
|
||||||
few: "%{count} uporabe"
|
few: "%{count} uporabe"
|
||||||
|
@ -1362,6 +1362,7 @@ sq:
|
|||||||
'86400': 1 ditë
|
'86400': 1 ditë
|
||||||
expires_in_prompt: Kurrë
|
expires_in_prompt: Kurrë
|
||||||
generate: Prodho lidhje ftese
|
generate: Prodho lidhje ftese
|
||||||
|
invalid: Kjo ftesë s’është e vlefshme
|
||||||
invited_by: 'Qetë ftuar nga:'
|
invited_by: 'Qetë ftuar nga:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 përdorim
|
one: 1 përdorim
|
||||||
|
@ -1393,6 +1393,7 @@ sr-Latn:
|
|||||||
'86400': 1 dan
|
'86400': 1 dan
|
||||||
expires_in_prompt: Nikad
|
expires_in_prompt: Nikad
|
||||||
generate: Generiši
|
generate: Generiši
|
||||||
|
invalid: Ova pozivnica nije važeća
|
||||||
invited_by: 'Pozvao Vas je:'
|
invited_by: 'Pozvao Vas je:'
|
||||||
max_uses:
|
max_uses:
|
||||||
few: "%{count} korišćenja"
|
few: "%{count} korišćenja"
|
||||||
|
@ -1393,6 +1393,7 @@ sr:
|
|||||||
'86400': 1 дан
|
'86400': 1 дан
|
||||||
expires_in_prompt: Никад
|
expires_in_prompt: Никад
|
||||||
generate: Генериши
|
generate: Генериши
|
||||||
|
invalid: Ова позивница није важећа
|
||||||
invited_by: 'Позвао Вас је:'
|
invited_by: 'Позвао Вас је:'
|
||||||
max_uses:
|
max_uses:
|
||||||
few: "%{count} коришћења"
|
few: "%{count} коришћења"
|
||||||
|
@ -1368,6 +1368,7 @@ sv:
|
|||||||
'86400': 1 dag
|
'86400': 1 dag
|
||||||
expires_in_prompt: Aldrig
|
expires_in_prompt: Aldrig
|
||||||
generate: Skapa
|
generate: Skapa
|
||||||
|
invalid: Ogiltig inbjudan
|
||||||
invited_by: 'Du blev inbjuden av:'
|
invited_by: 'Du blev inbjuden av:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 användning
|
one: 1 användning
|
||||||
|
@ -1343,6 +1343,7 @@ th:
|
|||||||
'86400': 1 วัน
|
'86400': 1 วัน
|
||||||
expires_in_prompt: ไม่เลย
|
expires_in_prompt: ไม่เลย
|
||||||
generate: สร้างลิงก์เชิญ
|
generate: สร้างลิงก์เชิญ
|
||||||
|
invalid: คำเชิญนี้ไม่ถูกต้อง
|
||||||
invited_by: 'คุณได้รับเชิญโดย:'
|
invited_by: 'คุณได้รับเชิญโดย:'
|
||||||
max_uses:
|
max_uses:
|
||||||
other: "%{count} การใช้งาน"
|
other: "%{count} การใช้งาน"
|
||||||
|
@ -1368,6 +1368,7 @@ tr:
|
|||||||
'86400': 1 gün
|
'86400': 1 gün
|
||||||
expires_in_prompt: Asla
|
expires_in_prompt: Asla
|
||||||
generate: Davet bağlantısı oluştur
|
generate: Davet bağlantısı oluştur
|
||||||
|
invalid: Bu davet geçerli değil
|
||||||
invited_by: 'Davet edildiniz:'
|
invited_by: 'Davet edildiniz:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 kullanım
|
one: 1 kullanım
|
||||||
|
@ -1418,6 +1418,7 @@ uk:
|
|||||||
'86400': 1 день
|
'86400': 1 день
|
||||||
expires_in_prompt: Ніколи
|
expires_in_prompt: Ніколи
|
||||||
generate: Згенерувати
|
generate: Згенерувати
|
||||||
|
invalid: Це запрошення не дійсне
|
||||||
invited_by: 'Вас запросив:'
|
invited_by: 'Вас запросив:'
|
||||||
max_uses:
|
max_uses:
|
||||||
few: "%{count} використання"
|
few: "%{count} використання"
|
||||||
|
@ -1343,6 +1343,7 @@ zh-CN:
|
|||||||
'86400': 1 天后
|
'86400': 1 天后
|
||||||
expires_in_prompt: 永不过期
|
expires_in_prompt: 永不过期
|
||||||
generate: 生成邀请链接
|
generate: 生成邀请链接
|
||||||
|
invalid: 此邀请无效
|
||||||
invited_by: 你的邀请人是:
|
invited_by: 你的邀请人是:
|
||||||
max_uses:
|
max_uses:
|
||||||
other: "%{count} 次"
|
other: "%{count} 次"
|
||||||
|
@ -1343,6 +1343,7 @@ zh-HK:
|
|||||||
'86400': 1 天後
|
'86400': 1 天後
|
||||||
expires_in_prompt: 永不過期
|
expires_in_prompt: 永不過期
|
||||||
generate: 生成邀請連結
|
generate: 生成邀請連結
|
||||||
|
invalid: 此邀請無效
|
||||||
invited_by: 你的邀請人是:
|
invited_by: 你的邀請人是:
|
||||||
max_uses:
|
max_uses:
|
||||||
other: "%{count} 次"
|
other: "%{count} 次"
|
||||||
|
@ -1345,6 +1345,7 @@ zh-TW:
|
|||||||
'86400': 1 天後
|
'86400': 1 天後
|
||||||
expires_in_prompt: 永不過期
|
expires_in_prompt: 永不過期
|
||||||
generate: 建立邀請連結
|
generate: 建立邀請連結
|
||||||
|
invalid: 此邀請是無效的
|
||||||
invited_by: 您的邀請人是:
|
invited_by: 您的邀請人是:
|
||||||
max_uses:
|
max_uses:
|
||||||
other: "%{count} 則"
|
other: "%{count} 則"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
test: /\.svg$/,
|
test: /\.svg$/,
|
||||||
include: /node_modules\/@material-symbols/,
|
include: [/node_modules\/@material-symbols/, /svg-icons/],
|
||||||
issuer: /\.[jt]sx?$/,
|
issuer: /\.[jt]sx?$/,
|
||||||
use: [
|
use: [
|
||||||
{
|
{
|
||||||
|
@ -179,7 +179,7 @@
|
|||||||
"@types/react-dom": "^18.2.4",
|
"@types/react-dom": "^18.2.4",
|
||||||
"@types/react-helmet": "^6.1.6",
|
"@types/react-helmet": "^6.1.6",
|
||||||
"@types/react-immutable-proptypes": "^2.1.0",
|
"@types/react-immutable-proptypes": "^2.1.0",
|
||||||
"@types/react-motion": "^0.0.36",
|
"@types/react-motion": "^0.0.37",
|
||||||
"@types/react-overlays": "^3.1.0",
|
"@types/react-overlays": "^3.1.0",
|
||||||
"@types/react-router": "^5.1.20",
|
"@types/react-router": "^5.1.20",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
@ -203,7 +203,7 @@
|
|||||||
"eslint-plugin-formatjs": "^4.10.1",
|
"eslint-plugin-formatjs": "^4.10.1",
|
||||||
"eslint-plugin-import": "~2.29.0",
|
"eslint-plugin-import": "~2.29.0",
|
||||||
"eslint-plugin-jsdoc": "^46.1.0",
|
"eslint-plugin-jsdoc": "^46.1.0",
|
||||||
"eslint-plugin-jsx-a11y": "~6.7.1",
|
"eslint-plugin-jsx-a11y": "~6.8.0",
|
||||||
"eslint-plugin-prettier": "^5.0.0",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
"eslint-plugin-promise": "~6.1.1",
|
"eslint-plugin-promise": "~6.1.1",
|
||||||
"eslint-plugin-react": "~7.33.0",
|
"eslint-plugin-react": "~7.33.0",
|
||||||
@ -245,5 +245,5 @@
|
|||||||
"*.{js,jsx,ts,tsx}": "eslint --fix",
|
"*.{js,jsx,ts,tsx}": "eslint --fix",
|
||||||
"*.{css,scss}": "stylelint --fix"
|
"*.{css,scss}": "stylelint --fix"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.0.1"
|
"packageManager": "yarn@4.0.2"
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ RSpec.describe ActivityPub::InboxesController do
|
|||||||
|
|
||||||
before do
|
before do
|
||||||
allow(ActivityPub::FollowersSynchronizationWorker).to receive(:perform_async).and_return(nil)
|
allow(ActivityPub::FollowersSynchronizationWorker).to receive(:perform_async).and_return(nil)
|
||||||
allow_any_instance_of(Account).to receive(:local_followers_hash).and_return('somehash')
|
allow(remote_account).to receive(:local_followers_hash).and_return('somehash')
|
||||||
|
|
||||||
request.headers['Collection-Synchronization'] = synchronization_header
|
request.headers['Collection-Synchronization'] = synchronization_header
|
||||||
post :create, body: '{}'
|
post :create, body: '{}'
|
||||||
|
@ -20,8 +20,7 @@ RSpec.describe Admin::AccountsController do
|
|||||||
it 'filters with parameters' do
|
it 'filters with parameters' do
|
||||||
account_filter = instance_double(AccountFilter, results: Account.all)
|
account_filter = instance_double(AccountFilter, results: Account.all)
|
||||||
allow(AccountFilter).to receive(:new).and_return(account_filter)
|
allow(AccountFilter).to receive(:new).and_return(account_filter)
|
||||||
|
params = {
|
||||||
get :index, params: {
|
|
||||||
origin: 'local',
|
origin: 'local',
|
||||||
by_domain: 'domain',
|
by_domain: 'domain',
|
||||||
status: 'active',
|
status: 'active',
|
||||||
@ -31,17 +30,9 @@ RSpec.describe Admin::AccountsController do
|
|||||||
ip: '0.0.0.42',
|
ip: '0.0.0.42',
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(AccountFilter).to have_received(:new) do |params|
|
get :index, params: params
|
||||||
h = params.to_h
|
|
||||||
|
|
||||||
expect(h[:origin]).to eq 'local'
|
expect(AccountFilter).to have_received(:new).with(hash_including(params))
|
||||||
expect(h[:by_domain]).to eq 'domain'
|
|
||||||
expect(h[:status]).to eq 'active'
|
|
||||||
expect(h[:username]).to eq 'username'
|
|
||||||
expect(h[:display_name]).to eq 'display name'
|
|
||||||
expect(h[:email]).to eq 'local-part@domain'
|
|
||||||
expect(h[:ip]).to eq '0.0.0.42'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'paginates accounts' do
|
it 'paginates accounts' do
|
||||||
@ -236,7 +227,8 @@ RSpec.describe Admin::AccountsController do
|
|||||||
let(:account) { Fabricate(:account, domain: 'example.com') }
|
let(:account) { Fabricate(:account, domain: 'example.com') }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(ResolveAccountService).to receive(:call)
|
service = instance_double(ResolveAccountService, call: nil)
|
||||||
|
allow(ResolveAccountService).to receive(:new).and_return(service)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when user is admin' do
|
context 'when user is admin' do
|
||||||
|
@ -13,12 +13,20 @@ describe Admin::ResetsController do
|
|||||||
|
|
||||||
describe 'POST #create' do
|
describe 'POST #create' do
|
||||||
it 'redirects to admin accounts page' do
|
it 'redirects to admin accounts page' do
|
||||||
expect_any_instance_of(User).to receive(:send_reset_password_instructions) do |value|
|
expect do
|
||||||
expect(value.account_id).to eq account.id
|
|
||||||
end
|
|
||||||
|
|
||||||
post :create, params: { account_id: account.id }
|
post :create, params: { account_id: account.id }
|
||||||
|
end.to change(Devise.mailer.deliveries, :size).by(2)
|
||||||
|
|
||||||
|
expect(Devise.mailer.deliveries).to have_attributes(
|
||||||
|
first: have_attributes(
|
||||||
|
to: include(account.user.email),
|
||||||
|
subject: I18n.t('devise.mailer.password_change.subject')
|
||||||
|
),
|
||||||
|
last: have_attributes(
|
||||||
|
to: include(account.user.email),
|
||||||
|
subject: I18n.t('devise.mailer.reset_password_instructions.subject')
|
||||||
|
)
|
||||||
|
)
|
||||||
expect(response).to redirect_to(admin_account_path(account.id))
|
expect(response).to redirect_to(admin_account_path(account.id))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -126,7 +126,7 @@ RSpec.describe Auth::SessionsController do
|
|||||||
let!(:previous_login) { Fabricate(:login_activity, user: user, ip: previous_ip) }
|
let!(:previous_login) { Fabricate(:login_activity, user: user, ip: previous_ip) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return(current_ip)
|
allow(controller.request).to receive(:remote_ip).and_return(current_ip)
|
||||||
user.update(current_sign_in_at: 1.month.ago)
|
user.update(current_sign_in_at: 1.month.ago)
|
||||||
post :create, params: { user: { email: user.email, password: user.password } }
|
post :create, params: { user: { email: user.email, password: user.password } }
|
||||||
end
|
end
|
||||||
@ -279,7 +279,9 @@ RSpec.describe Auth::SessionsController do
|
|||||||
|
|
||||||
context 'when the server has an decryption error' do
|
context 'when the server has an decryption error' do
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(User).to receive(:validate_and_consume_otp!).and_raise(OpenSSL::Cipher::CipherError)
|
allow(user).to receive(:validate_and_consume_otp!).with(user.current_otp).and_raise(OpenSSL::Cipher::CipherError)
|
||||||
|
allow(User).to receive(:find_by).with(id: user.id).and_return(user)
|
||||||
|
|
||||||
post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
|
post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
|
|||||||
it 'renders page with success' do
|
it 'renders page with success' do
|
||||||
prepare_user_otp_generation
|
prepare_user_otp_generation
|
||||||
prepare_user_otp_consumption
|
prepare_user_otp_consumption
|
||||||
|
allow(controller).to receive(:current_user).and_return(user)
|
||||||
|
|
||||||
expect do
|
expect do
|
||||||
post :create,
|
post :create,
|
||||||
@ -75,30 +76,28 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def prepare_user_otp_generation
|
def prepare_user_otp_generation
|
||||||
expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value|
|
allow(user)
|
||||||
expect(value).to eq user
|
.to receive(:generate_otp_backup_codes!)
|
||||||
otp_backup_codes
|
.and_return(otp_backup_codes)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def prepare_user_otp_consumption
|
def prepare_user_otp_consumption
|
||||||
expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, code, options|
|
options = { otp_secret: 'thisisasecretforthespecofnewview' }
|
||||||
expect(value).to eq user
|
allow(user)
|
||||||
expect(code).to eq '123456'
|
.to receive(:validate_and_consume_otp!)
|
||||||
expect(options).to eq({ otp_secret: 'thisisasecretforthespecofnewview' })
|
.with('123456', options)
|
||||||
true
|
.and_return(true)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'when creation fails' do
|
describe 'when creation fails' do
|
||||||
subject do
|
subject do
|
||||||
expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, code, options|
|
options = { otp_secret: 'thisisasecretforthespecofnewview' }
|
||||||
expect(value).to eq user
|
allow(user)
|
||||||
expect(code).to eq '123456'
|
.to receive(:validate_and_consume_otp!)
|
||||||
expect(options).to eq({ otp_secret: 'thisisasecretforthespecofnewview' })
|
.with('123456', options)
|
||||||
false
|
.and_return(false)
|
||||||
end
|
allow(controller).to receive(:current_user).and_return(user)
|
||||||
|
|
||||||
expect do
|
expect do
|
||||||
post :create,
|
post :create,
|
||||||
|
@ -9,10 +9,8 @@ describe Settings::TwoFactorAuthentication::RecoveryCodesController do
|
|||||||
it 'updates the codes and shows them on a view when signed in' do
|
it 'updates the codes and shows them on a view when signed in' do
|
||||||
user = Fabricate(:user)
|
user = Fabricate(:user)
|
||||||
otp_backup_codes = user.generate_otp_backup_codes!
|
otp_backup_codes = user.generate_otp_backup_codes!
|
||||||
expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value|
|
allow(user).to receive(:generate_otp_backup_codes!).and_return(otp_backup_codes)
|
||||||
expect(value).to eq user
|
allow(controller).to receive(:current_user).and_return(user)
|
||||||
otp_backup_codes
|
|
||||||
end
|
|
||||||
|
|
||||||
sign_in user, scope: :user
|
sign_in user, scope: :user
|
||||||
post :create, session: { challenge_passed_at: Time.now.utc }
|
post :create, session: { challenge_passed_at: Time.now.utc }
|
||||||
|
@ -64,8 +64,11 @@ describe Request do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'closes underlying connection' do
|
it 'closes underlying connection' do
|
||||||
expect_any_instance_of(HTTP::Client).to receive(:close)
|
allow(subject.send(:http_client)).to receive(:close)
|
||||||
|
|
||||||
expect { |block| subject.perform(&block) }.to yield_control
|
expect { |block| subject.perform(&block) }.to yield_control
|
||||||
|
|
||||||
|
expect(subject.send(:http_client)).to have_received(:close)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns response which implements body_with_limit' do
|
it 'returns response which implements body_with_limit' do
|
||||||
|
@ -23,7 +23,8 @@ describe StatusFilter do
|
|||||||
|
|
||||||
context 'when status policy does not allow show' do
|
context 'when status policy does not allow show' do
|
||||||
it 'filters the status' do
|
it 'filters the status' do
|
||||||
allow_any_instance_of(StatusPolicy).to receive(:show?).and_return(false)
|
policy = instance_double(StatusPolicy, show?: false)
|
||||||
|
allow(StatusPolicy).to receive(:new).and_return(policy)
|
||||||
|
|
||||||
expect(filter).to be_filtered
|
expect(filter).to be_filtered
|
||||||
end
|
end
|
||||||
@ -74,7 +75,8 @@ describe StatusFilter do
|
|||||||
|
|
||||||
context 'when status policy does not allow show' do
|
context 'when status policy does not allow show' do
|
||||||
it 'filters the status' do
|
it 'filters the status' do
|
||||||
allow_any_instance_of(StatusPolicy).to receive(:show?).and_return(false)
|
policy = instance_double(StatusPolicy, show?: false)
|
||||||
|
allow(StatusPolicy).to receive(:new).and_return(policy)
|
||||||
|
|
||||||
expect(filter).to be_filtered
|
expect(filter).to be_filtered
|
||||||
end
|
end
|
||||||
|
@ -209,9 +209,13 @@ RSpec.describe Account do
|
|||||||
expect(account.refresh!).to be_nil
|
expect(account.refresh!).to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'calls not ResolveAccountService#call' do
|
it 'does not call ResolveAccountService#call' do
|
||||||
expect_any_instance_of(ResolveAccountService).to_not receive(:call).with(acct)
|
service = instance_double(ResolveAccountService, call: nil)
|
||||||
|
allow(ResolveAccountService).to receive(:new).and_return(service)
|
||||||
|
|
||||||
account.refresh!
|
account.refresh!
|
||||||
|
|
||||||
|
expect(service).to_not have_received(:call).with(acct)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -219,8 +223,12 @@ RSpec.describe Account do
|
|||||||
let(:domain) { 'example.com' }
|
let(:domain) { 'example.com' }
|
||||||
|
|
||||||
it 'calls ResolveAccountService#call' do
|
it 'calls ResolveAccountService#call' do
|
||||||
expect_any_instance_of(ResolveAccountService).to receive(:call).with(acct).once
|
service = instance_double(ResolveAccountService, call: nil)
|
||||||
|
allow(ResolveAccountService).to receive(:new).and_return(service)
|
||||||
|
|
||||||
account.refresh!
|
account.refresh!
|
||||||
|
|
||||||
|
expect(service).to have_received(:call).with(acct).once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -52,7 +52,8 @@ RSpec.describe Setting do
|
|||||||
before do
|
before do
|
||||||
allow(RailsSettings::Settings).to receive(:object).with(key).and_return(object)
|
allow(RailsSettings::Settings).to receive(:object).with(key).and_return(object)
|
||||||
allow(described_class).to receive(:default_settings).and_return(default_settings)
|
allow(described_class).to receive(:default_settings).and_return(default_settings)
|
||||||
allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records)
|
settings_double = instance_double(Settings::ScopedSettings, thing_scoped: records)
|
||||||
|
allow(Settings::ScopedSettings).to receive(:new).and_return(settings_double)
|
||||||
Rails.cache.delete(cache_key)
|
Rails.cache.delete(cache_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -128,7 +129,8 @@ RSpec.describe Setting do
|
|||||||
|
|
||||||
describe '.all_as_records' do
|
describe '.all_as_records' do
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records)
|
settings_double = instance_double(Settings::ScopedSettings, thing_scoped: records)
|
||||||
|
allow(Settings::ScopedSettings).to receive(:new).and_return(settings_double)
|
||||||
allow(described_class).to receive(:default_settings).and_return(default_settings)
|
allow(described_class).to receive(:default_settings).and_return(default_settings)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,6 +5,37 @@ require 'rails_helper'
|
|||||||
RSpec.describe Webhook do
|
RSpec.describe Webhook do
|
||||||
let(:webhook) { Fabricate(:webhook) }
|
let(:webhook) { Fabricate(:webhook) }
|
||||||
|
|
||||||
|
describe 'Validations' do
|
||||||
|
it 'requires presence of events' do
|
||||||
|
record = described_class.new(events: nil)
|
||||||
|
record.valid?
|
||||||
|
|
||||||
|
expect(record).to model_have_error_on_field(:events)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'requires non-empty events value' do
|
||||||
|
record = described_class.new(events: [])
|
||||||
|
record.valid?
|
||||||
|
|
||||||
|
expect(record).to model_have_error_on_field(:events)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'requires valid events value from EVENTS' do
|
||||||
|
record = described_class.new(events: ['account.invalid'])
|
||||||
|
record.valid?
|
||||||
|
|
||||||
|
expect(record).to model_have_error_on_field(:events)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Normalizations' do
|
||||||
|
it 'cleans up events values' do
|
||||||
|
record = described_class.new(events: ['account.approved', 'account.created ', ''])
|
||||||
|
|
||||||
|
expect(record.events).to eq(%w(account.approved account.created))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#rotate_secret!' do
|
describe '#rotate_secret!' do
|
||||||
it 'changes the secret' do
|
it 'changes the secret' do
|
||||||
previous_value = webhook.secret
|
previous_value = webhook.secret
|
||||||
|
@ -102,17 +102,25 @@ describe 'GET /api/v1/accounts/relationships' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns JSON with correct data on cached requests too' do
|
it 'returns JSON with correct data on previously cached requests' do
|
||||||
subject
|
# Initial request including multiple accounts in params
|
||||||
subject
|
get '/api/v1/accounts/relationships', headers: headers, params: { id: [simon.id, lewis.id] }
|
||||||
|
expect(body_as_json.size).to eq(2)
|
||||||
|
|
||||||
|
# Subsequent request with different id, should override cache from first request
|
||||||
|
get '/api/v1/accounts/relationships', headers: headers, params: { id: [simon.id] }
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
|
|
||||||
json = body_as_json
|
expect(body_as_json)
|
||||||
|
.to be_an(Enumerable)
|
||||||
expect(json).to be_a Enumerable
|
.and have_attributes(
|
||||||
expect(json.first[:following]).to be true
|
size: 1,
|
||||||
expect(json.first[:showing_reblogs]).to be true
|
first: hash_including(
|
||||||
|
following: true,
|
||||||
|
showing_reblogs: true
|
||||||
|
)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns JSON with correct data after change too' do
|
it 'returns JSON with correct data after change too' do
|
||||||
|
43
spec/requests/api/v1/csp_spec.rb
Normal file
43
spec/requests/api/v1/csp_spec.rb
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe 'API namespace minimal Content-Security-Policy' do
|
||||||
|
before { stub_tests_controller }
|
||||||
|
|
||||||
|
after { Rails.application.reload_routes! }
|
||||||
|
|
||||||
|
it 'returns the correct CSP headers' do
|
||||||
|
get '/api/v1/tests'
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.headers['Content-Security-Policy']).to eq(minimal_csp_headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def stub_tests_controller
|
||||||
|
stub_const('Api::V1::TestsController', api_tests_controller)
|
||||||
|
|
||||||
|
Rails.application.routes.draw do
|
||||||
|
get '/api/v1/tests', to: 'api/v1/tests#index'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def api_tests_controller
|
||||||
|
Class.new(Api::BaseController) do
|
||||||
|
def index
|
||||||
|
head 200
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def user_signed_in? = false
|
||||||
|
def current_user = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def minimal_csp_headers
|
||||||
|
"default-src 'none'; frame-ancestors 'none'; form-action 'none'"
|
||||||
|
end
|
||||||
|
end
|
@ -76,7 +76,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
|
|||||||
let(:forwarder) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/other_account') }
|
let(:forwarder) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/other_account') }
|
||||||
|
|
||||||
it 'does not process payload if no signature exists' do
|
it 'does not process payload if no signature exists' do
|
||||||
allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil)
|
signature_double = instance_double(ActivityPub::LinkedDataSignature, verify_actor!: nil)
|
||||||
|
allow(ActivityPub::LinkedDataSignature).to receive(:new).and_return(signature_double)
|
||||||
allow(ActivityPub::Activity).to receive(:factory)
|
allow(ActivityPub::Activity).to receive(:factory)
|
||||||
|
|
||||||
subject.call(json, forwarder)
|
subject.call(json, forwarder)
|
||||||
@ -87,7 +88,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
|
|||||||
it 'processes payload with actor if valid signature exists' do
|
it 'processes payload with actor if valid signature exists' do
|
||||||
payload['signature'] = { 'type' => 'RsaSignature2017' }
|
payload['signature'] = { 'type' => 'RsaSignature2017' }
|
||||||
|
|
||||||
allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(actor)
|
signature_double = instance_double(ActivityPub::LinkedDataSignature, verify_actor!: actor)
|
||||||
|
allow(ActivityPub::LinkedDataSignature).to receive(:new).and_return(signature_double)
|
||||||
allow(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor, instance_of(Hash))
|
allow(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor, instance_of(Hash))
|
||||||
|
|
||||||
subject.call(json, forwarder)
|
subject.call(json, forwarder)
|
||||||
@ -98,7 +100,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
|
|||||||
it 'does not process payload if invalid signature exists' do
|
it 'does not process payload if invalid signature exists' do
|
||||||
payload['signature'] = { 'type' => 'RsaSignature2017' }
|
payload['signature'] = { 'type' => 'RsaSignature2017' }
|
||||||
|
|
||||||
allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil)
|
signature_double = instance_double(ActivityPub::LinkedDataSignature, verify_actor!: nil)
|
||||||
|
allow(ActivityPub::LinkedDataSignature).to receive(:new).and_return(signature_double)
|
||||||
allow(ActivityPub::Activity).to receive(:factory)
|
allow(ActivityPub::Activity).to receive(:factory)
|
||||||
|
|
||||||
subject.call(json, forwarder)
|
subject.call(json, forwarder)
|
||||||
|
@ -11,7 +11,8 @@ describe ActivityPub::DeliveryWorker do
|
|||||||
let(:payload) { 'test' }
|
let(:payload) { 'test' }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(Account).to receive(:remote_followers_hash).with('https://example.com/api').and_return('somehash')
|
allow(sender).to receive(:remote_followers_hash).with('https://example.com/api').and_return('somehash')
|
||||||
|
allow(Account).to receive(:find).with(sender.id).and_return(sender)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'perform' do
|
describe 'perform' do
|
||||||
|
@ -23,8 +23,8 @@ describe Web::PushNotificationWorker do
|
|||||||
|
|
||||||
describe 'perform' do
|
describe 'perform' do
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(subscription.class).to receive(:contact_email).and_return(contact_email)
|
allow(subscription).to receive_messages(contact_email: contact_email, vapid_key: vapid_key)
|
||||||
allow_any_instance_of(subscription.class).to receive(:vapid_key).and_return(vapid_key)
|
allow(Web::PushSubscription).to receive(:find).with(subscription.id).and_return(subscription)
|
||||||
allow(Webpush::Encryption).to receive(:encrypt).and_return(payload)
|
allow(Webpush::Encryption).to receive(:encrypt).and_return(payload)
|
||||||
allow(JWT).to receive(:encode).and_return('jwt.encoded.payload')
|
allow(JWT).to receive(:encode).and_return('jwt.encoded.payload')
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user