Merge remote-tracking branch 'parent/main' into upstream-20231116
This commit is contained in:
commit
0704829a9b
80 changed files with 1483 additions and 1117 deletions
3
.watchmanconfig
Normal file
3
.watchmanconfig
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"ignore_dirs": ["node_modules/", "public/"]
|
||||||
|
}
|
121
Gemfile.lock
121
Gemfile.lock
|
@ -39,50 +39,51 @@ GIT
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (7.1.1)
|
actioncable (7.1.2)
|
||||||
actionpack (= 7.1.1)
|
actionpack (= 7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
actionmailbox (7.1.1)
|
actionmailbox (7.1.2)
|
||||||
actionpack (= 7.1.1)
|
actionpack (= 7.1.2)
|
||||||
activejob (= 7.1.1)
|
activejob (= 7.1.2)
|
||||||
activerecord (= 7.1.1)
|
activerecord (= 7.1.2)
|
||||||
activestorage (= 7.1.1)
|
activestorage (= 7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
net-imap
|
net-imap
|
||||||
net-pop
|
net-pop
|
||||||
net-smtp
|
net-smtp
|
||||||
actionmailer (7.1.1)
|
actionmailer (7.1.2)
|
||||||
actionpack (= 7.1.1)
|
actionpack (= 7.1.2)
|
||||||
actionview (= 7.1.1)
|
actionview (= 7.1.2)
|
||||||
activejob (= 7.1.1)
|
activejob (= 7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
net-imap
|
net-imap
|
||||||
net-pop
|
net-pop
|
||||||
net-smtp
|
net-smtp
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
actionpack (7.1.1)
|
actionpack (7.1.2)
|
||||||
actionview (= 7.1.1)
|
actionview (= 7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
|
racc
|
||||||
rack (>= 2.2.4)
|
rack (>= 2.2.4)
|
||||||
rack-session (>= 1.0.1)
|
rack-session (>= 1.0.1)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
actiontext (7.1.1)
|
actiontext (7.1.2)
|
||||||
actionpack (= 7.1.1)
|
actionpack (= 7.1.2)
|
||||||
activerecord (= 7.1.1)
|
activerecord (= 7.1.2)
|
||||||
activestorage (= 7.1.1)
|
activestorage (= 7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
globalid (>= 0.6.0)
|
globalid (>= 0.6.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (7.1.1)
|
actionview (7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.11)
|
erubi (~> 1.11)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
|
@ -92,22 +93,22 @@ GEM
|
||||||
activemodel (>= 4.1)
|
activemodel (>= 4.1)
|
||||||
case_transform (>= 0.2)
|
case_transform (>= 0.2)
|
||||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||||
activejob (7.1.1)
|
activejob (7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (7.1.1)
|
activemodel (7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
activerecord (7.1.1)
|
activerecord (7.1.2)
|
||||||
activemodel (= 7.1.1)
|
activemodel (= 7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activestorage (7.1.1)
|
activestorage (7.1.2)
|
||||||
actionpack (= 7.1.1)
|
actionpack (= 7.1.2)
|
||||||
activejob (= 7.1.1)
|
activejob (= 7.1.2)
|
||||||
activerecord (= 7.1.1)
|
activerecord (= 7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
activesupport (7.1.1)
|
activesupport (7.1.2)
|
||||||
base64
|
base64
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
|
@ -218,7 +219,7 @@ GEM
|
||||||
activerecord (>= 5.a)
|
activerecord (>= 5.a)
|
||||||
database_cleaner-core (~> 2.0.0)
|
database_cleaner-core (~> 2.0.0)
|
||||||
database_cleaner-core (2.0.1)
|
database_cleaner-core (2.0.1)
|
||||||
date (3.3.3)
|
date (3.3.4)
|
||||||
debug_inspector (1.1.0)
|
debug_inspector (1.1.0)
|
||||||
devise (4.9.3)
|
devise (4.9.3)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
|
@ -369,7 +370,7 @@ GEM
|
||||||
terminal-table (>= 1.5.1)
|
terminal-table (>= 1.5.1)
|
||||||
idn-ruby (0.1.5)
|
idn-ruby (0.1.5)
|
||||||
io-console (0.6.0)
|
io-console (0.6.0)
|
||||||
irb (1.8.1)
|
irb (1.8.3)
|
||||||
rdoc
|
rdoc
|
||||||
reline (>= 0.3.8)
|
reline (>= 0.3.8)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
|
@ -462,13 +463,13 @@ GEM
|
||||||
uri
|
uri
|
||||||
net-http-persistent (4.0.2)
|
net-http-persistent (4.0.2)
|
||||||
connection_pool (~> 2.2)
|
connection_pool (~> 2.2)
|
||||||
net-imap (0.4.1)
|
net-imap (0.4.4)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-ldap (0.18.0)
|
net-ldap (0.18.0)
|
||||||
net-pop (0.1.2)
|
net-pop (0.1.2)
|
||||||
net-protocol
|
net-protocol
|
||||||
net-protocol (0.2.1)
|
net-protocol (0.2.2)
|
||||||
timeout
|
timeout
|
||||||
net-smtp (0.4.0)
|
net-smtp (0.4.0)
|
||||||
net-protocol
|
net-protocol
|
||||||
|
@ -526,7 +527,7 @@ GEM
|
||||||
net-smtp
|
net-smtp
|
||||||
premailer (~> 1.7, >= 1.7.9)
|
premailer (~> 1.7, >= 1.7.9)
|
||||||
private_address_check (0.5.0)
|
private_address_check (0.5.0)
|
||||||
psych (5.1.1)
|
psych (5.1.1.1)
|
||||||
stringio
|
stringio
|
||||||
public_suffix (5.0.3)
|
public_suffix (5.0.3)
|
||||||
puma (6.4.0)
|
puma (6.4.0)
|
||||||
|
@ -557,20 +558,20 @@ GEM
|
||||||
rackup (1.0.0)
|
rackup (1.0.0)
|
||||||
rack (< 3)
|
rack (< 3)
|
||||||
webrick
|
webrick
|
||||||
rails (7.1.1)
|
rails (7.1.2)
|
||||||
actioncable (= 7.1.1)
|
actioncable (= 7.1.2)
|
||||||
actionmailbox (= 7.1.1)
|
actionmailbox (= 7.1.2)
|
||||||
actionmailer (= 7.1.1)
|
actionmailer (= 7.1.2)
|
||||||
actionpack (= 7.1.1)
|
actionpack (= 7.1.2)
|
||||||
actiontext (= 7.1.1)
|
actiontext (= 7.1.2)
|
||||||
actionview (= 7.1.1)
|
actionview (= 7.1.2)
|
||||||
activejob (= 7.1.1)
|
activejob (= 7.1.2)
|
||||||
activemodel (= 7.1.1)
|
activemodel (= 7.1.2)
|
||||||
activerecord (= 7.1.1)
|
activerecord (= 7.1.2)
|
||||||
activestorage (= 7.1.1)
|
activestorage (= 7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 7.1.1)
|
railties (= 7.1.2)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
actionview (>= 5.0.1.rc1)
|
actionview (>= 5.0.1.rc1)
|
||||||
|
@ -585,9 +586,9 @@ GEM
|
||||||
rails-i18n (7.0.8)
|
rails-i18n (7.0.8)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
railties (>= 6.0.0, < 8)
|
railties (>= 6.0.0, < 8)
|
||||||
railties (7.1.1)
|
railties (7.1.2)
|
||||||
actionpack (= 7.1.1)
|
actionpack (= 7.1.2)
|
||||||
activesupport (= 7.1.1)
|
activesupport (= 7.1.2)
|
||||||
irb
|
irb
|
||||||
rackup (>= 1.0.0)
|
rackup (>= 1.0.0)
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
|
@ -739,7 +740,7 @@ GEM
|
||||||
statsd-ruby (1.5.0)
|
statsd-ruby (1.5.0)
|
||||||
stoplight (3.0.2)
|
stoplight (3.0.2)
|
||||||
redlock (~> 1.0)
|
redlock (~> 1.0)
|
||||||
stringio (3.0.8)
|
stringio (3.0.9)
|
||||||
strong_migrations (1.6.4)
|
strong_migrations (1.6.4)
|
||||||
activerecord (>= 5.2)
|
activerecord (>= 5.2)
|
||||||
swd (1.3.0)
|
swd (1.3.0)
|
||||||
|
@ -755,7 +756,7 @@ GEM
|
||||||
test-prof (1.2.3)
|
test-prof (1.2.3)
|
||||||
thor (1.3.0)
|
thor (1.3.0)
|
||||||
tilt (2.3.0)
|
tilt (2.3.0)
|
||||||
timeout (0.4.0)
|
timeout (0.4.1)
|
||||||
tpm-key_attestation (0.12.0)
|
tpm-key_attestation (0.12.0)
|
||||||
bindata (~> 2.4)
|
bindata (~> 2.4)
|
||||||
openssl (> 2.0)
|
openssl (> 2.0)
|
||||||
|
|
|
@ -144,7 +144,7 @@ class PublicStatusesIndex < Chewy::Index
|
||||||
index_scope ::Status.unscoped
|
index_scope ::Status.unscoped
|
||||||
.kept
|
.kept
|
||||||
.indexable
|
.indexable
|
||||||
.includes(:media_attachments, :preloadable_poll, :preview_cards, :tags, :account)
|
.includes(:media_attachments, :preloadable_poll, :tags, :account, preview_cards_status: :preview_card)
|
||||||
|
|
||||||
root date_detection: false do
|
root date_detection: false do
|
||||||
field(:id, type: 'long')
|
field(:id, type: 'long')
|
||||||
|
|
|
@ -147,7 +147,6 @@ class StatusesIndex < Chewy::Index
|
||||||
index_scope ::Status.unscoped.kept.without_reblogs.includes(
|
index_scope ::Status.unscoped.kept.without_reblogs.includes(
|
||||||
:account,
|
:account,
|
||||||
:media_attachments,
|
:media_attachments,
|
||||||
:preview_cards,
|
|
||||||
:local_mentioned,
|
:local_mentioned,
|
||||||
:local_favorited,
|
:local_favorited,
|
||||||
:local_reblogged,
|
:local_reblogged,
|
||||||
|
@ -155,6 +154,7 @@ class StatusesIndex < Chewy::Index
|
||||||
:local_emoji_reacted,
|
:local_emoji_reacted,
|
||||||
:tags,
|
:tags,
|
||||||
:local_referenced,
|
:local_referenced,
|
||||||
|
preview_cards_status: :preview_card,
|
||||||
preloadable_poll: :local_voters
|
preloadable_poll: :local_voters
|
||||||
),
|
),
|
||||||
delete_if: lambda { |status|
|
delete_if: lambda { |status|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::AccountsController < Api::BaseController
|
class Api::V1::AccountsController < Api::BaseController
|
||||||
|
include RegistrationHelper
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:create, :follow, :unfollow, :remove_from_followers, :block, :unblock, :mute, :unmute]
|
before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:create, :follow, :unfollow, :remove_from_followers, :block, :unblock, :mute, :unmute]
|
||||||
before_action -> { doorkeeper_authorize! :follow, :write, :'write:follows' }, only: [:follow, :unfollow, :remove_from_followers]
|
before_action -> { doorkeeper_authorize! :follow, :write, :'write:follows' }, only: [:follow, :unfollow, :remove_from_followers]
|
||||||
before_action -> { doorkeeper_authorize! :follow, :write, :'write:mutes' }, only: [:mute, :unmute]
|
before_action -> { doorkeeper_authorize! :follow, :write, :'write:mutes' }, only: [:mute, :unmute]
|
||||||
|
@ -90,18 +92,14 @@ class Api::V1::AccountsController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_params
|
def account_params
|
||||||
params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone)
|
params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone, :invite_code)
|
||||||
|
end
|
||||||
|
|
||||||
|
def invite
|
||||||
|
Invite.find_by(code: params[:invite_code]) if params[:invite_code].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_enabled_registrations
|
def check_enabled_registrations
|
||||||
forbidden if single_user_mode? || omniauth_only? || !allowed_registrations?
|
forbidden unless allowed_registration?(request.remote_ip, invite)
|
||||||
end
|
|
||||||
|
|
||||||
def allowed_registrations?
|
|
||||||
Setting.registrations_mode != 'none'
|
|
||||||
end
|
|
||||||
|
|
||||||
def omniauth_only?
|
|
||||||
ENV['OMNIAUTH_ONLY'] == 'true'
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,10 +41,10 @@ class Api::V1::ConversationsController < Api::BaseController
|
||||||
account: :account_stat,
|
account: :account_stat,
|
||||||
last_status: [
|
last_status: [
|
||||||
:media_attachments,
|
:media_attachments,
|
||||||
:preview_cards,
|
|
||||||
:status_stat,
|
:status_stat,
|
||||||
:tags,
|
:tags,
|
||||||
{
|
{
|
||||||
|
preview_cards_status: :preview_card,
|
||||||
active_mentions: [account: :account_stat],
|
active_mentions: [account: :account_stat],
|
||||||
account: :account_stat,
|
account: :account_stat,
|
||||||
},
|
},
|
||||||
|
|
30
app/controllers/api/v1/invites_controller.rb
Normal file
30
app/controllers/api/v1/invites_controller.rb
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::InvitesController < Api::BaseController
|
||||||
|
include RegistrationHelper
|
||||||
|
|
||||||
|
skip_before_action :require_authenticated_user!
|
||||||
|
skip_around_action :set_locale
|
||||||
|
|
||||||
|
before_action :set_invite
|
||||||
|
before_action :check_enabled_registrations!
|
||||||
|
|
||||||
|
# Override `current_user` to avoid reading session cookies
|
||||||
|
def current_user; end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render json: { invite_code: params[:invite_code], instance_api_url: api_v2_instance_url }, status: 200
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_invite
|
||||||
|
@invite = Invite.find_by!(code: params[:invite_code])
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_enabled_registrations!
|
||||||
|
return render json: { error: I18n.t('invites.invalid') }, status: 401 unless @invite.valid_for_use?
|
||||||
|
|
||||||
|
raise Mastodon::NotPermittedError unless allowed_registration?(request.remote_ip, @invite)
|
||||||
|
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
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Auth::RegistrationsController < Devise::RegistrationsController
|
class Auth::RegistrationsController < Devise::RegistrationsController
|
||||||
|
include RegistrationHelper
|
||||||
include RegistrationSpamConcern
|
include RegistrationSpamConcern
|
||||||
|
|
||||||
layout :determine_layout
|
layout :determine_layout
|
||||||
|
@ -82,19 +83,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_enabled_registrations
|
def check_enabled_registrations
|
||||||
redirect_to root_path if single_user_mode? || omniauth_only? || !allowed_registrations? || ip_blocked?
|
redirect_to root_path unless allowed_registration?(request.remote_ip, @invite)
|
||||||
end
|
|
||||||
|
|
||||||
def allowed_registrations?
|
|
||||||
Setting.registrations_mode != 'none' || @invite&.valid_for_use?
|
|
||||||
end
|
|
||||||
|
|
||||||
def omniauth_only?
|
|
||||||
ENV['OMNIAUTH_ONLY'] == 'true'
|
|
||||||
end
|
|
||||||
|
|
||||||
def ip_blocked?
|
|
||||||
IpBlock.where(severity: :sign_up_block).where('ip >>= ?', request.remote_ip.to_s).exists?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def invite_code
|
def invite_code
|
||||||
|
|
21
app/helpers/registration_helper.rb
Normal file
21
app/helpers/registration_helper.rb
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module RegistrationHelper
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
def allowed_registration?(remote_ip, invite)
|
||||||
|
!Rails.configuration.x.single_user_mode && !omniauth_only? && (registrations_open? || invite&.valid_for_use?) && !ip_blocked?(remote_ip)
|
||||||
|
end
|
||||||
|
|
||||||
|
def registrations_open?
|
||||||
|
Setting.registrations_mode != 'none'
|
||||||
|
end
|
||||||
|
|
||||||
|
def omniauth_only?
|
||||||
|
ENV['OMNIAUTH_ONLY'] == 'true'
|
||||||
|
end
|
||||||
|
|
||||||
|
def ip_blocked?(remote_ip)
|
||||||
|
IpBlock.where(severity: :sign_up_block).exists?(['ip >>= ?', remote_ip.to_s])
|
||||||
|
end
|
||||||
|
end
|
|
@ -20,6 +20,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';
|
||||||
|
|
||||||
|
@ -426,6 +428,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;
|
||||||
|
@ -438,15 +441,20 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
|
|
||||||
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility_ex') === 'private';
|
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility_ex') === '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 && (
|
||||||
|
@ -472,7 +480,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} />
|
||||||
{emojiPickerDropdown}
|
{emojiPickerDropdown}
|
||||||
|
|
|
@ -19,6 +19,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';
|
||||||
|
|
||||||
|
@ -337,6 +339,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;
|
||||||
|
@ -347,15 +350,20 @@ class ActionBar extends PureComponent {
|
||||||
|
|
||||||
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility_ex') === 'private';
|
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility_ex') === '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 emojiReactionAvailableServer = !isHideItem('emoji_reaction_unavailable_server') || status.get('emoji_reaction_available_server');
|
const emojiReactionAvailableServer = !isHideItem('emoji_reaction_unavailable_server') || status.get('emoji_reaction_available_server');
|
||||||
|
@ -375,7 +383,7 @@ class ActionBar extends PureComponent {
|
||||||
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>
|
||||||
{emojiPickerDropdown}
|
{emojiPickerDropdown}
|
||||||
|
|
|
@ -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": "Профіль недаступны",
|
||||||
|
|
|
@ -222,6 +222,7 @@
|
||||||
"emoji_button.search_results": "Otsitulemused",
|
"emoji_button.search_results": "Otsitulemused",
|
||||||
"emoji_button.symbols": "Sümbolid",
|
"emoji_button.symbols": "Sümbolid",
|
||||||
"emoji_button.travel": "Reisimine & kohad",
|
"emoji_button.travel": "Reisimine & kohad",
|
||||||
|
"empty_column.account_hides_collections": "See kasutaja otsustas mitte teha seda infot saadavaks",
|
||||||
"empty_column.account_suspended": "Konto kustutatud",
|
"empty_column.account_suspended": "Konto kustutatud",
|
||||||
"empty_column.account_timeline": "Siin postitusi ei ole!",
|
"empty_column.account_timeline": "Siin postitusi ei ole!",
|
||||||
"empty_column.account_unavailable": "Profiil pole saadaval",
|
"empty_column.account_unavailable": "Profiil pole saadaval",
|
||||||
|
|
|
@ -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": "نمایهٔ موجود نیست",
|
||||||
|
@ -358,13 +359,13 @@
|
||||||
"keyboard_shortcuts.profile": "گشودن نمایهٔ نویسنده",
|
"keyboard_shortcuts.profile": "گشودن نمایهٔ نویسنده",
|
||||||
"keyboard_shortcuts.reply": "پاسخ به فرسته",
|
"keyboard_shortcuts.reply": "پاسخ به فرسته",
|
||||||
"keyboard_shortcuts.requests": "گشودن سیاههٔ درخواستهای پیگیری",
|
"keyboard_shortcuts.requests": "گشودن سیاههٔ درخواستهای پیگیری",
|
||||||
"keyboard_shortcuts.search": "تمرکز روی جستوجو",
|
"keyboard_shortcuts.search": "تمرکز روی نوار جستوجو",
|
||||||
"keyboard_shortcuts.spoilers": "نمایش/نهفتن زمینهٔ هشدار محتوا",
|
"keyboard_shortcuts.spoilers": "نمایش/نهفتن زمینهٔ هشدار محتوا",
|
||||||
"keyboard_shortcuts.start": "گشودن ستون «آغاز کنید»",
|
"keyboard_shortcuts.start": "گشودن ستون «آغاز کنید»",
|
||||||
"keyboard_shortcuts.toggle_hidden": "نمایش/نهفتن نوشتهٔ پشت هشدار محتوا",
|
"keyboard_shortcuts.toggle_hidden": "نمایش/نهفتن نوشتهٔ پشت هشدار محتوا",
|
||||||
"keyboard_shortcuts.toggle_sensitivity": "نمایش/نهفتن رسانه",
|
"keyboard_shortcuts.toggle_sensitivity": "نمایش/نهفتن رسانه",
|
||||||
"keyboard_shortcuts.toot": "شروع یک فرستهٔ جدید",
|
"keyboard_shortcuts.toot": "شروع یک فرستهٔ جدید",
|
||||||
"keyboard_shortcuts.unfocus": "برداشتن تمرکز از نوشتن/جستوجو",
|
"keyboard_shortcuts.unfocus": "برداشتن تمرکز از ناحیهٔ نوشتن یا جستوجو",
|
||||||
"keyboard_shortcuts.up": "بالا بردن در سیاهه",
|
"keyboard_shortcuts.up": "بالا بردن در سیاهه",
|
||||||
"lightbox.close": "بستن",
|
"lightbox.close": "بستن",
|
||||||
"lightbox.compress": "فشردهسازی جعبهٔ نمایش تصویر",
|
"lightbox.compress": "فشردهسازی جعبهٔ نمایش تصویر",
|
||||||
|
|
|
@ -222,6 +222,7 @@
|
||||||
"emoji_button.search_results": "Hakutulokset",
|
"emoji_button.search_results": "Hakutulokset",
|
||||||
"emoji_button.symbols": "Symbolit",
|
"emoji_button.symbols": "Symbolit",
|
||||||
"emoji_button.travel": "Matkailu ja paikat",
|
"emoji_button.travel": "Matkailu ja paikat",
|
||||||
|
"empty_column.account_hides_collections": "Käyttäjä on päättänyt olla julkaisematta näitä tietoja",
|
||||||
"empty_column.account_suspended": "Tili jäädytetty",
|
"empty_column.account_suspended": "Tili jäädytetty",
|
||||||
"empty_column.account_timeline": "Ei viestejä täällä.",
|
"empty_column.account_timeline": "Ei viestejä täällä.",
|
||||||
"empty_column.account_unavailable": "Profiilia ei löydy",
|
"empty_column.account_unavailable": "Profiilia ei löydy",
|
||||||
|
|
|
@ -222,6 +222,7 @@
|
||||||
"emoji_button.search_results": "Leitiúrslit",
|
"emoji_button.search_results": "Leitiúrslit",
|
||||||
"emoji_button.symbols": "Ímyndir",
|
"emoji_button.symbols": "Ímyndir",
|
||||||
"emoji_button.travel": "Ferðing og støð",
|
"emoji_button.travel": "Ferðing og støð",
|
||||||
|
"empty_column.account_hides_collections": "Hesin brúkarin hevur valt, at hesar upplýsingarnar ikki skulu vera tøkar",
|
||||||
"empty_column.account_suspended": "Kontan gjørd óvirkin",
|
"empty_column.account_suspended": "Kontan gjørd óvirkin",
|
||||||
"empty_column.account_timeline": "Einki uppslag her!",
|
"empty_column.account_timeline": "Einki uppslag her!",
|
||||||
"empty_column.account_unavailable": "Vangin er ikki tøkur",
|
"empty_column.account_unavailable": "Vangin er ikki tøkur",
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
{
|
{
|
||||||
"account.add_or_remove_from_list": "Tinye ma ọ bụ Wepu na ndepụta",
|
"account.add_or_remove_from_list": "Tinye ma ọ bụ Wepu na ndepụta",
|
||||||
"account.badges.bot": "Bot",
|
"account.badges.bot": "Bot",
|
||||||
|
"account.badges.group": "Otù",
|
||||||
"account.cancel_follow_request": "Withdraw follow request",
|
"account.cancel_follow_request": "Withdraw follow request",
|
||||||
"account.follow": "Soro",
|
"account.follow": "Soro",
|
||||||
|
"account.followers": "Ndị na-eso",
|
||||||
|
"account.following": "Na-eso",
|
||||||
"account.follows_you": "Na-eso gị",
|
"account.follows_you": "Na-eso gị",
|
||||||
"account.mute": "Mee ogbi @{name}",
|
"account.mute": "Mee ogbi @{name}",
|
||||||
"account.unfollow": "Kwụsị iso",
|
"account.unfollow": "Kwụsị iso",
|
||||||
|
@ -11,16 +14,20 @@
|
||||||
"audio.hide": "Zoo ụda",
|
"audio.hide": "Zoo ụda",
|
||||||
"bundle_column_error.retry": "Nwaa ọzọ",
|
"bundle_column_error.retry": "Nwaa ọzọ",
|
||||||
"bundle_column_error.routing.title": "404",
|
"bundle_column_error.routing.title": "404",
|
||||||
|
"bundle_modal_error.close": "Mechie",
|
||||||
"bundle_modal_error.retry": "Nwaa ọzọ",
|
"bundle_modal_error.retry": "Nwaa ọzọ",
|
||||||
"column.about": "Maka",
|
"column.about": "Maka",
|
||||||
"column.blocks": "Ojiarụ egbochiri",
|
"column.blocks": "Ojiarụ egbochiri",
|
||||||
"column.bookmarks": "Ebenrụtụakā",
|
"column.bookmarks": "Ebenrụtụakā",
|
||||||
"column.home": "Be",
|
"column.home": "Be",
|
||||||
|
"column.lists": "Ndepụta",
|
||||||
"column.pins": "Pinned post",
|
"column.pins": "Pinned post",
|
||||||
|
"column_header.pin": "Gbado na profaịlụ gị",
|
||||||
"column_subheading.settings": "Mwube",
|
"column_subheading.settings": "Mwube",
|
||||||
"community.column_settings.media_only": "Media only",
|
"community.column_settings.media_only": "Media only",
|
||||||
"compose.language.change": "Gbanwee asụsụ",
|
"compose.language.change": "Gbanwee asụsụ",
|
||||||
"compose.language.search": "Chọọ asụsụ...",
|
"compose.language.search": "Chọọ asụsụ...",
|
||||||
|
"compose.published.open": "Mepe",
|
||||||
"compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.",
|
"compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.",
|
||||||
"compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.",
|
"compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.",
|
||||||
"compose_form.placeholder": "What is on your mind?",
|
"compose_form.placeholder": "What is on your mind?",
|
||||||
|
@ -32,7 +39,10 @@
|
||||||
"confirmations.delete.message": "Are you sure you want to delete this status?",
|
"confirmations.delete.message": "Are you sure you want to delete this status?",
|
||||||
"confirmations.delete_list.confirm": "Hichapụ",
|
"confirmations.delete_list.confirm": "Hichapụ",
|
||||||
"confirmations.domain_block.confirm": "Hide entire domain",
|
"confirmations.domain_block.confirm": "Hide entire domain",
|
||||||
|
"confirmations.edit.confirm": "Dezie",
|
||||||
|
"confirmations.mute.confirm": "Mee ogbi",
|
||||||
"confirmations.reply.confirm": "Zaa",
|
"confirmations.reply.confirm": "Zaa",
|
||||||
|
"confirmations.unfollow.confirm": "Kwụsị iso",
|
||||||
"conversation.delete": "Hichapụ nkata",
|
"conversation.delete": "Hichapụ nkata",
|
||||||
"dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.",
|
"dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.",
|
||||||
"dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.",
|
"dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.",
|
||||||
|
@ -76,6 +86,7 @@
|
||||||
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
|
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
|
||||||
"keyboard_shortcuts.up": "to move up in the list",
|
"keyboard_shortcuts.up": "to move up in the list",
|
||||||
"lists.delete": "Hichapụ ndepụta",
|
"lists.delete": "Hichapụ ndepụta",
|
||||||
|
"lists.edit": "Dezie ndepụta",
|
||||||
"lists.subheading": "Ndepụta gị",
|
"lists.subheading": "Ndepụta gị",
|
||||||
"loading_indicator.label": "Na-adọnye...",
|
"loading_indicator.label": "Na-adọnye...",
|
||||||
"navigation_bar.about": "Maka",
|
"navigation_bar.about": "Maka",
|
||||||
|
@ -100,20 +111,27 @@
|
||||||
"privacy.change": "Adjust status privacy",
|
"privacy.change": "Adjust status privacy",
|
||||||
"privacy.direct.short": "Direct",
|
"privacy.direct.short": "Direct",
|
||||||
"privacy.private.short": "Followers-only",
|
"privacy.private.short": "Followers-only",
|
||||||
|
"relative_time.full.just_now": "kịta",
|
||||||
"relative_time.just_now": "kịta",
|
"relative_time.just_now": "kịta",
|
||||||
"relative_time.today": "taa",
|
"relative_time.today": "taa",
|
||||||
"reply_indicator.cancel": "Kagbuo",
|
"reply_indicator.cancel": "Kagbuo",
|
||||||
"report.categories.other": "Ọzọ",
|
"report.categories.other": "Ọzọ",
|
||||||
|
"report.categories.spam": "Nzipụ Ozièlètrọniìk Nkeāchọghị",
|
||||||
|
"report.mute": "Mee ogbi",
|
||||||
"report.placeholder": "Type or paste additional comments",
|
"report.placeholder": "Type or paste additional comments",
|
||||||
"report.submit": "Submit report",
|
"report.submit": "Submit report",
|
||||||
"report.target": "Report {target}",
|
"report.target": "Report {target}",
|
||||||
"report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached",
|
"report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached",
|
||||||
|
"report_notification.categories.other": "Ọzọ",
|
||||||
|
"search.placeholder": "Chọọ",
|
||||||
"server_banner.active_users": "ojiarụ dị ìrè",
|
"server_banner.active_users": "ojiarụ dị ìrè",
|
||||||
|
"server_banner.learn_more": "Mụtakwuo",
|
||||||
"sign_in_banner.sign_in": "Sign in",
|
"sign_in_banner.sign_in": "Sign in",
|
||||||
"status.admin_status": "Open this status in the moderation interface",
|
"status.admin_status": "Open this status in the moderation interface",
|
||||||
"status.bookmark": "Kee ebenrụtụakā",
|
"status.bookmark": "Kee ebenrụtụakā",
|
||||||
"status.copy": "Copy link to status",
|
"status.copy": "Copy link to status",
|
||||||
"status.delete": "Hichapụ",
|
"status.delete": "Hichapụ",
|
||||||
|
"status.edit": "Dezie",
|
||||||
"status.edited_x_times": "Edited {count, plural, one {# time} other {# times}}",
|
"status.edited_x_times": "Edited {count, plural, one {# time} other {# times}}",
|
||||||
"status.open": "Expand this status",
|
"status.open": "Expand this status",
|
||||||
"status.remove_bookmark": "Wepu ebenrụtụakā",
|
"status.remove_bookmark": "Wepu ebenrụtụakā",
|
||||||
|
|
|
@ -706,8 +706,8 @@
|
||||||
"search.no_recent_searches": "検索履歴はありません",
|
"search.no_recent_searches": "検索履歴はありません",
|
||||||
"search.placeholder": "検索",
|
"search.placeholder": "検索",
|
||||||
"search.quick_action.account_search": "{x}に該当するプロフィール",
|
"search.quick_action.account_search": "{x}に該当するプロフィール",
|
||||||
"search.quick_action.go_to_account": "{x}のプロフィールを見る",
|
"search.quick_action.go_to_account": "プロフィール {x} を見る",
|
||||||
"search.quick_action.go_to_hashtag": "{x}に該当するハッシュタグ",
|
"search.quick_action.go_to_hashtag": "ハッシュタグ {x} を見る",
|
||||||
"search.quick_action.open_url": "MastodonでURLを開く",
|
"search.quick_action.open_url": "MastodonでURLを開く",
|
||||||
"search.quick_action.status_search": "{x}に該当する投稿",
|
"search.quick_action.status_search": "{x}に該当する投稿",
|
||||||
"search.search_or_paste": "検索またはURLを入力",
|
"search.search_or_paste": "検索またはURLを入力",
|
||||||
|
|
|
@ -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": "프로필 사용 불가",
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
"account.add_or_remove_from_list": "Pridėti arba ištrinti iš sąrašų",
|
"account.add_or_remove_from_list": "Pridėti arba ištrinti iš sąrašų",
|
||||||
"account.badges.bot": "Automatizuotas",
|
"account.badges.bot": "Automatizuotas",
|
||||||
"account.badges.group": "Grupė",
|
"account.badges.group": "Grupė",
|
||||||
"account.block": "Užblokuoti @{name}",
|
"account.block": "Blokuoti @{name}",
|
||||||
"account.block_domain": "Blokuoti domeną {domain}",
|
"account.block_domain": "Blokuoti domeną {domain}",
|
||||||
"account.block_short": "Blokuoti",
|
"account.block_short": "Blokuoti",
|
||||||
"account.blocked": "Užblokuota",
|
"account.blocked": "Užblokuota",
|
||||||
|
@ -25,11 +25,20 @@
|
||||||
"account.disable_notifications": "Nustoti man pranešti, kai @{name} paskelbia",
|
"account.disable_notifications": "Nustoti man pranešti, kai @{name} paskelbia",
|
||||||
"account.domain_blocked": "Užblokuotas domenas",
|
"account.domain_blocked": "Užblokuotas domenas",
|
||||||
"account.edit_profile": "Redaguoti profilį",
|
"account.edit_profile": "Redaguoti profilį",
|
||||||
|
"account.enable_notifications": "Pranešti man, kai @{name} paskelbia",
|
||||||
|
"account.featured_tags.last_status_at": "Paskutinį kartą paskelbta {date}",
|
||||||
|
"account.featured_tags.last_status_never": "Nėra įrašų",
|
||||||
"account.follow": "Sekti",
|
"account.follow": "Sekti",
|
||||||
"account.follows_you": "Seka jus",
|
"account.followers": "Sekėjai",
|
||||||
|
"account.followers.empty": "Šio naudotojo dar niekas neseka.",
|
||||||
|
"account.followers_counter": "{count, plural, one {{counter} sekėjas (-a)} few {{counter} sekėjai} many {{counter} sekėjo} other {{counter} sekėjų}}",
|
||||||
|
"account.following": "Seka",
|
||||||
|
"account.follows.empty": "Šis naudotojas (-a) dar nieko neseka.",
|
||||||
|
"account.follows_you": "Seka tave",
|
||||||
"account.go_to_profile": "Eiti į profilį",
|
"account.go_to_profile": "Eiti į profilį",
|
||||||
"account.in_memoriam": "Atminimui.",
|
"account.in_memoriam": "Atminimui.",
|
||||||
"account.joined_short": "Prisijungė",
|
"account.joined_short": "Prisijungė",
|
||||||
|
"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.mute": "Užtildyti @{name}",
|
"account.mute": "Užtildyti @{name}",
|
||||||
|
|
|
@ -222,6 +222,7 @@
|
||||||
"emoji_button.search_results": "Søkeresultat",
|
"emoji_button.search_results": "Søkeresultat",
|
||||||
"emoji_button.symbols": "Symboler",
|
"emoji_button.symbols": "Symboler",
|
||||||
"emoji_button.travel": "Reise & steder",
|
"emoji_button.travel": "Reise & steder",
|
||||||
|
"empty_column.account_hides_collections": "Denne brukeren har valgt å ikke gjøre denne informasjonen tilgjengelig",
|
||||||
"empty_column.account_suspended": "Kontoen er suspendert",
|
"empty_column.account_suspended": "Kontoen er suspendert",
|
||||||
"empty_column.account_timeline": "Ingen innlegg her!",
|
"empty_column.account_timeline": "Ingen innlegg her!",
|
||||||
"empty_column.account_unavailable": "Profilen er utilgjengelig",
|
"empty_column.account_unavailable": "Profilen er utilgjengelig",
|
||||||
|
|
|
@ -222,6 +222,7 @@
|
||||||
"emoji_button.search_results": "Resultado da pesquisa",
|
"emoji_button.search_results": "Resultado da pesquisa",
|
||||||
"emoji_button.symbols": "Símbolos",
|
"emoji_button.symbols": "Símbolos",
|
||||||
"emoji_button.travel": "Viagem e Lugares",
|
"emoji_button.travel": "Viagem e Lugares",
|
||||||
|
"empty_column.account_hides_collections": "A pessoa optou por não disponibilizar esta informação",
|
||||||
"empty_column.account_suspended": "Conta suspensa",
|
"empty_column.account_suspended": "Conta suspensa",
|
||||||
"empty_column.account_timeline": "Nada aqui.",
|
"empty_column.account_timeline": "Nada aqui.",
|
||||||
"empty_column.account_unavailable": "Perfil indisponível",
|
"empty_column.account_unavailable": "Perfil indisponível",
|
||||||
|
|
|
@ -222,6 +222,7 @@
|
||||||
"emoji_button.search_results": "Resultados da pesquisa",
|
"emoji_button.search_results": "Resultados da pesquisa",
|
||||||
"emoji_button.symbols": "Símbolos",
|
"emoji_button.symbols": "Símbolos",
|
||||||
"emoji_button.travel": "Viagens & Lugares",
|
"emoji_button.travel": "Viagens & Lugares",
|
||||||
|
"empty_column.account_hides_collections": "Este utilizador escolheu não disponibilizar esta informação",
|
||||||
"empty_column.account_suspended": "Conta suspensa",
|
"empty_column.account_suspended": "Conta suspensa",
|
||||||
"empty_column.account_timeline": "Sem publicações por aqui!",
|
"empty_column.account_timeline": "Sem publicações por aqui!",
|
||||||
"empty_column.account_unavailable": "Perfil indisponível",
|
"empty_column.account_unavailable": "Perfil indisponível",
|
||||||
|
|
|
@ -222,6 +222,7 @@
|
||||||
"emoji_button.search_results": "Kết quả tìm kiếm",
|
"emoji_button.search_results": "Kết quả tìm kiếm",
|
||||||
"emoji_button.symbols": "Biểu tượng",
|
"emoji_button.symbols": "Biểu tượng",
|
||||||
"emoji_button.travel": "Du lịch",
|
"emoji_button.travel": "Du lịch",
|
||||||
|
"empty_column.account_hides_collections": "Người này đã chọn ẩn thông tin",
|
||||||
"empty_column.account_suspended": "Tài khoản vô hiệu hóa",
|
"empty_column.account_suspended": "Tài khoản vô hiệu hóa",
|
||||||
"empty_column.account_timeline": "Chưa có tút nào!",
|
"empty_column.account_timeline": "Chưa có tút nào!",
|
||||||
"empty_column.account_unavailable": "Tài khoản bị đình chỉ",
|
"empty_column.account_unavailable": "Tài khoản bị đình chỉ",
|
||||||
|
|
|
@ -5508,6 +5508,7 @@ a.status-card {
|
||||||
|
|
||||||
.modal-root__modal {
|
.modal-root__modal {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
|
user-select: text;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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 |
|
@ -77,7 +77,7 @@ class Admin::StatusBatchAction
|
||||||
|
|
||||||
# Can't use a transaction here because UpdateStatusService queues
|
# Can't use a transaction here because UpdateStatusService queues
|
||||||
# Sidekiq jobs
|
# Sidekiq jobs
|
||||||
statuses.includes(:media_attachments, :preview_cards).find_each do |status|
|
statuses.includes(:media_attachments, preview_cards_status: :preview_card).find_each do |status|
|
||||||
next if status.discarded? || !(status.with_media? || status.with_preview_card?)
|
next if status.discarded? || !(status.with_media? || status.with_preview_card?)
|
||||||
|
|
||||||
authorize([:admin, status], :update?)
|
authorize([:admin, status], :update?)
|
||||||
|
|
|
@ -77,7 +77,7 @@ module StatusSearchConcern
|
||||||
properties << 'media' if with_media?
|
properties << 'media' if with_media?
|
||||||
properties << 'poll' if with_poll?
|
properties << 'poll' if with_poll?
|
||||||
properties << 'link' if with_preview_card?
|
properties << 'link' if with_preview_card?
|
||||||
properties << 'embed' if preview_cards.any?(&:video?)
|
properties << 'embed' if preview_card&.video?
|
||||||
properties << 'sensitive' if sensitive?
|
properties << 'sensitive' if sensitive?
|
||||||
properties << 'reply' if reply?
|
properties << 'reply' if reply?
|
||||||
properties << 'reference' if with_status_reference?
|
properties << 'reference' if with_status_reference?
|
||||||
|
|
|
@ -50,7 +50,9 @@ class PreviewCard < ApplicationRecord
|
||||||
enum type: { link: 0, photo: 1, video: 2, rich: 3 }
|
enum type: { link: 0, photo: 1, video: 2, rich: 3 }
|
||||||
enum link_type: { unknown: 0, article: 1 }
|
enum link_type: { unknown: 0, article: 1 }
|
||||||
|
|
||||||
has_and_belongs_to_many :statuses
|
has_many :preview_cards_statuses, dependent: :delete_all, inverse_of: :preview_card
|
||||||
|
has_many :statuses, through: :preview_cards_statuses
|
||||||
|
|
||||||
has_one :trend, class_name: 'PreviewCardTrend', inverse_of: :preview_card, dependent: :destroy
|
has_one :trend, class_name: 'PreviewCardTrend', inverse_of: :preview_card, dependent: :destroy
|
||||||
|
|
||||||
has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false
|
has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false
|
||||||
|
@ -64,6 +66,9 @@ class PreviewCard < ApplicationRecord
|
||||||
|
|
||||||
before_save :extract_dimensions, if: :link?
|
before_save :extract_dimensions, if: :link?
|
||||||
|
|
||||||
|
# This can be set by the status when retrieving the preview card using the join model
|
||||||
|
attr_accessor :original_url
|
||||||
|
|
||||||
def appropriate_for_trends?
|
def appropriate_for_trends?
|
||||||
link? && article? && title.present? && description.present? && image.present? && provider_name.present?
|
link? && article? && title.present? && description.present? && image.present? && provider_name.present?
|
||||||
end
|
end
|
||||||
|
|
18
app/models/preview_cards_status.rb
Normal file
18
app/models/preview_cards_status.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: preview_cards_statuses
|
||||||
|
#
|
||||||
|
# preview_card_id :bigint(8) not null
|
||||||
|
# status_id :bigint(8) not null
|
||||||
|
# url :string
|
||||||
|
#
|
||||||
|
class PreviewCardsStatus < ApplicationRecord
|
||||||
|
# Composite primary keys are not properly supported in Rails. However,
|
||||||
|
# we shouldn't need this anyway...
|
||||||
|
self.primary_key = nil
|
||||||
|
|
||||||
|
belongs_to :preview_card
|
||||||
|
belongs_to :status
|
||||||
|
end
|
|
@ -103,8 +103,8 @@ class Status < ApplicationRecord
|
||||||
has_many :local_referenced, -> { merge(Account.local) }, through: :referenced_by_statuses, source: :account
|
has_many :local_referenced, -> { merge(Account.local) }, through: :referenced_by_statuses, source: :account
|
||||||
|
|
||||||
has_and_belongs_to_many :tags
|
has_and_belongs_to_many :tags
|
||||||
has_and_belongs_to_many :preview_cards
|
|
||||||
|
|
||||||
|
has_one :preview_cards_status, inverse_of: :status # Because of a composite primary key, the dependent option cannot be used
|
||||||
has_one :notification, as: :activity, dependent: :destroy
|
has_one :notification, as: :activity, dependent: :destroy
|
||||||
has_one :status_stat, inverse_of: :status
|
has_one :status_stat, inverse_of: :status
|
||||||
has_one :poll, inverse_of: :status, dependent: :destroy
|
has_one :poll, inverse_of: :status, dependent: :destroy
|
||||||
|
@ -172,28 +172,29 @@ class Status < ApplicationRecord
|
||||||
# The `prepend: true` option below ensures this runs before
|
# The `prepend: true` option below ensures this runs before
|
||||||
# the `dependent: destroy` callbacks remove relevant records
|
# the `dependent: destroy` callbacks remove relevant records
|
||||||
before_destroy :unlink_from_conversations!, prepend: true
|
before_destroy :unlink_from_conversations!, prepend: true
|
||||||
|
before_destroy :reset_preview_card!
|
||||||
|
|
||||||
cache_associated :application,
|
cache_associated :application,
|
||||||
:media_attachments,
|
:media_attachments,
|
||||||
:conversation,
|
:conversation,
|
||||||
:status_stat,
|
:status_stat,
|
||||||
:tags,
|
:tags,
|
||||||
:preview_cards,
|
|
||||||
:preloadable_poll,
|
:preloadable_poll,
|
||||||
:reference_objects,
|
:reference_objects,
|
||||||
:scheduled_expiration_status,
|
:scheduled_expiration_status,
|
||||||
|
preview_cards_status: [:preview_card],
|
||||||
account: [:account_stat, user: :role],
|
account: [:account_stat, user: :role],
|
||||||
active_mentions: { account: :account_stat },
|
active_mentions: { account: :account_stat },
|
||||||
reblog: [
|
reblog: [
|
||||||
:application,
|
:application,
|
||||||
:tags,
|
:tags,
|
||||||
:preview_cards,
|
|
||||||
:media_attachments,
|
:media_attachments,
|
||||||
:conversation,
|
:conversation,
|
||||||
:status_stat,
|
:status_stat,
|
||||||
:preloadable_poll,
|
:preloadable_poll,
|
||||||
:reference_objects,
|
:reference_objects,
|
||||||
:scheduled_expiration_status,
|
:scheduled_expiration_status,
|
||||||
|
preview_cards_status: [:preview_card],
|
||||||
account: [:account_stat, user: :role],
|
account: [:account_stat, user: :role],
|
||||||
active_mentions: { account: :account_stat },
|
active_mentions: { account: :account_stat },
|
||||||
],
|
],
|
||||||
|
@ -207,6 +208,7 @@ class Status < ApplicationRecord
|
||||||
:preloadable_poll,
|
:preloadable_poll,
|
||||||
:reference_objects,
|
:reference_objects,
|
||||||
:scheduled_expiration_status,
|
:scheduled_expiration_status,
|
||||||
|
preview_cards_status: [:preview_card],
|
||||||
account: [:account_stat, user: :role],
|
account: [:account_stat, user: :role],
|
||||||
active_mentions: { account: :account_stat },
|
active_mentions: { account: :account_stat },
|
||||||
],
|
],
|
||||||
|
@ -277,7 +279,11 @@ class Status < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def preview_card
|
def preview_card
|
||||||
preview_cards.first
|
preview_cards_status&.preview_card&.tap { |x| x.original_url = preview_cards_status.url }
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_preview_card!
|
||||||
|
PreviewCardsStatus.where(status_id: id).delete_all
|
||||||
end
|
end
|
||||||
|
|
||||||
def hidden?
|
def hidden?
|
||||||
|
@ -300,7 +306,7 @@ class Status < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_preview_card?
|
def with_preview_card?
|
||||||
preview_cards.any?
|
preview_cards_status.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_poll?
|
def with_poll?
|
||||||
|
|
|
@ -54,9 +54,7 @@ class Trends::Links < Trends::Base
|
||||||
!(original_status.account.silenced? || status.account.silenced?) &&
|
!(original_status.account.silenced? || status.account.silenced?) &&
|
||||||
!(original_status.spoiler_text? || original_status.sensitive?)
|
!(original_status.spoiler_text? || original_status.sensitive?)
|
||||||
|
|
||||||
original_status.preview_cards.each do |preview_card|
|
add(original_status.preview_card, status.account_id, at_time) if original_status.preview_card&.appropriate_for_trends?
|
||||||
add(preview_card, status.account_id, at_time) if preview_card.appropriate_for_trends?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def add(preview_card, account_id, at_time = Time.now.utc)
|
def add(preview_card, account_id, at_time = Time.now.utc)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -8,6 +8,10 @@ class REST::PreviewCardSerializer < ActiveModel::Serializer
|
||||||
:provider_url, :html, :width, :height,
|
:provider_url, :html, :width, :height,
|
||||||
:image, :image_description, :embed_url, :blurhash, :published_at
|
:image, :image_description, :embed_url, :blurhash, :published_at
|
||||||
|
|
||||||
|
def url
|
||||||
|
object.original_url.presence || object.url
|
||||||
|
end
|
||||||
|
|
||||||
def image
|
def image
|
||||||
object.image? ? full_asset_url(object.image.url(:original)) : nil
|
object.image? ? full_asset_url(object.image.url(:original)) : nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -200,7 +200,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!
|
||||||
|
|
|
@ -318,7 +318,7 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_preview_card!
|
def reset_preview_card!
|
||||||
@status.preview_cards.clear
|
@status.reset_preview_card!
|
||||||
LinkCrawlWorker.perform_in(rand(1..59).seconds, @status.id)
|
LinkCrawlWorker.perform_in(rand(1..59).seconds, @status.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AppSignUpService < BaseService
|
class AppSignUpService < BaseService
|
||||||
|
include RegistrationHelper
|
||||||
|
|
||||||
def call(app, remote_ip, params)
|
def call(app, remote_ip, params)
|
||||||
@app = app
|
@app = app
|
||||||
@remote_ip = remote_ip
|
@remote_ip = remote_ip
|
||||||
@params = params
|
@params = params
|
||||||
|
|
||||||
raise Mastodon::NotPermittedError unless allowed_registrations?
|
raise Mastodon::NotPermittedError unless allowed_registration?(remote_ip, invite)
|
||||||
|
|
||||||
ApplicationRecord.transaction do
|
ApplicationRecord.transaction do
|
||||||
create_user!
|
create_user!
|
||||||
|
@ -34,8 +36,12 @@ class AppSignUpService < BaseService
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def invite
|
||||||
|
Invite.find_by(code: @params[:invite_code]) if @params[:invite_code].present?
|
||||||
|
end
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
@params.slice(:email, :password, :agreement, :locale, :time_zone)
|
@params.slice(:email, :password, :agreement, :locale, :time_zone, :invite_code)
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_params
|
def account_params
|
||||||
|
@ -45,24 +51,4 @@ class AppSignUpService < BaseService
|
||||||
def invite_request_params
|
def invite_request_params
|
||||||
{ text: @params[:reason] }
|
{ text: @params[:reason] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def allowed_registrations?
|
|
||||||
registrations_open? && !single_user_mode? && !omniauth_only? && !ip_blocked?
|
|
||||||
end
|
|
||||||
|
|
||||||
def registrations_open?
|
|
||||||
Setting.registrations_mode != 'none'
|
|
||||||
end
|
|
||||||
|
|
||||||
def single_user_mode?
|
|
||||||
Rails.configuration.x.single_user_mode
|
|
||||||
end
|
|
||||||
|
|
||||||
def omniauth_only?
|
|
||||||
ENV['OMNIAUTH_ONLY'] == 'true'
|
|
||||||
end
|
|
||||||
|
|
||||||
def ip_blocked?
|
|
||||||
IpBlock.where(severity: :sign_up_block).where('ip >>= ?', @remote_ip.to_s).exists?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,7 @@ class FetchLinkCardService < BaseService
|
||||||
@status = status
|
@status = status
|
||||||
@original_url = parse_urls
|
@original_url = parse_urls
|
||||||
|
|
||||||
return if @original_url.nil? || @status.preview_cards.any? || !@status.account.link_preview?
|
return if @original_url.nil? || @status.with_preview_card? || !@status.account.link_preview?
|
||||||
|
|
||||||
@url = @original_url.to_s
|
@url = @original_url.to_s
|
||||||
|
|
||||||
|
@ -63,9 +63,9 @@ class FetchLinkCardService < BaseService
|
||||||
|
|
||||||
def attach_card
|
def attach_card
|
||||||
with_redis_lock("attach_card:#{@status.id}") do
|
with_redis_lock("attach_card:#{@status.id}") do
|
||||||
return if @status.preview_cards.any?
|
return if @status.with_preview_card?
|
||||||
|
|
||||||
@status.preview_cards << @card
|
PreviewCardsStatus.create(status: @status, preview_card: @card, url: @original_url)
|
||||||
Rails.cache.delete(@status)
|
Rails.cache.delete(@status)
|
||||||
Trends.links.register(@status)
|
Trends.links.register(@status)
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,11 +40,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)
|
||||||
|
|
|
@ -167,7 +167,7 @@ class UpdateStatusService < BaseService
|
||||||
def reset_preview_card!
|
def reset_preview_card!
|
||||||
return unless @status.text_previously_changed?
|
return unless @status.text_previously_changed?
|
||||||
|
|
||||||
@status.preview_cards.clear
|
@status.reset_preview_card!
|
||||||
LinkCrawlWorker.perform_async(@status.id)
|
LinkCrawlWorker.perform_async(@status.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,143 @@
|
||||||
---
|
---
|
||||||
lt:
|
lt:
|
||||||
|
activerecord:
|
||||||
|
attributes:
|
||||||
|
doorkeeper/application:
|
||||||
|
name: Programėlės pavadinimas
|
||||||
|
redirect_uri: Peradresavimo URI
|
||||||
|
scopes: Aprėptys
|
||||||
|
website: Programėlės svetainė
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
doorkeeper/application:
|
||||||
|
attributes:
|
||||||
|
redirect_uri:
|
||||||
|
fragment_present: negali turėti fragmento.
|
||||||
|
invalid_uri: turi būti tinkamas URI.
|
||||||
|
relative_uri: turi būti absoliutus URI.
|
||||||
|
secured_uri: turi būti HTTPS/SSL URI.
|
||||||
doorkeeper:
|
doorkeeper:
|
||||||
|
applications:
|
||||||
|
buttons:
|
||||||
|
authorize: Įgalinti
|
||||||
|
cancel: Atšaukti
|
||||||
|
destroy: Sunaikinti
|
||||||
|
edit: Redaguoti
|
||||||
|
submit: Pateikti
|
||||||
|
confirmations:
|
||||||
|
destroy: Ar esi įsitikinęs (-usi)?
|
||||||
|
edit:
|
||||||
|
title: Redaguoti programėlę
|
||||||
|
form:
|
||||||
|
error: Ups! Patikrink, ar formoje nėra galimų klaidų.
|
||||||
|
help:
|
||||||
|
native_redirect_uri: Naudoti %{native_redirect_uri} vietiniams bandymams
|
||||||
|
redirect_uri: Naudoti po vieną eilutę kiekvienam URI
|
||||||
|
scopes: Atskirk aprėptis tarpais. Palik tuščią, jei nori naudoti numatytąsias aprėtis.
|
||||||
|
index:
|
||||||
|
application: Programėlė
|
||||||
|
callback_url: Atgalinis URL
|
||||||
|
delete: Ištrinti
|
||||||
|
empty: Neturi jokių programėlių.
|
||||||
|
name: Pavadinimas
|
||||||
|
new: Nauja programėlė
|
||||||
|
scopes: Aprėptys
|
||||||
|
show: Rodyti
|
||||||
|
title: Tavo programėlės
|
||||||
|
new:
|
||||||
|
title: Nauja programėlė
|
||||||
|
show:
|
||||||
|
actions: Veiksmai
|
||||||
|
application_id: Kliento raktas
|
||||||
|
callback_urls: Atgalinių URL adresų
|
||||||
|
scopes: Aprėptys
|
||||||
|
secret: Kliento paslaptis
|
||||||
|
title: 'Programėlė: %{name}'
|
||||||
authorizations:
|
authorizations:
|
||||||
|
buttons:
|
||||||
|
authorize: Įgalinti
|
||||||
|
deny: Atmesti
|
||||||
error:
|
error:
|
||||||
title: Įvyko klaida.
|
title: Įvyko klaida.
|
||||||
new:
|
new:
|
||||||
prompt_html: "%{client_name} norėtų gauti leidimą prieigos prie tavo paskyros. Tai trečiosios šalies programėlė. <strong>Jei ja nepasitiki, neturėtum jai leisti.</strong>"
|
prompt_html: "%{client_name} norėtų gauti leidimą prieigos prie tavo paskyros. Tai trečiosios šalies programėlė. <strong>Jei ja nepasitiki, neturėtum jai leisti.</strong>"
|
||||||
|
review_permissions: Peržiūrėti leidimus
|
||||||
|
title: Reikalingas įgaliojimas
|
||||||
|
show:
|
||||||
|
title: Nukopijuok šį įgaliojimo kodą ir įklijuok jį į programėlę.
|
||||||
authorized_applications:
|
authorized_applications:
|
||||||
|
buttons:
|
||||||
|
revoke: Naikinti
|
||||||
|
confirmations:
|
||||||
|
revoke: Ar esi įsitikinęs (-usi)?
|
||||||
index:
|
index:
|
||||||
title: Tavo leidžiamos programėlės
|
authorized_at: Įgaliota %{date}
|
||||||
|
description_html: Tai programėlės, kurios gali pasiekti tavo paskyrą naudojant API. Jei čia yra programėlių, kurių neatpažįsti, arba jei programėlė elgiasi netinkamai, gali panaikinti jos prieigą.
|
||||||
|
last_used_at: Paskutinį kartą naudota %{date}
|
||||||
|
never_used: Niekada nenaudotas
|
||||||
|
scopes: Leidimai
|
||||||
|
superapp: Vidinis
|
||||||
|
title: Tavo įgaliotos programėlės
|
||||||
|
errors:
|
||||||
|
messages:
|
||||||
|
access_denied: Išteklių savininkas (-ė) arba įgaliojimų serveris atmetė užklausą.
|
||||||
|
credential_flow_not_configured: Išteklių savininko slaptažodžio kredencialų srautas nepavyko, nes Doorkeeper.configure.resource_owner_from_credentials nėra nesukonfigūruotas.
|
||||||
|
invalid_client: Kliento tapatybės nustatymas nepavyko dėl nežinomo kliento, neįtraukto kliento tapatybės nustatymo arba nepalaikomo tapatybės nustatymo metodo.
|
||||||
|
invalid_grant: Pateiktas įgaliojimas yra netinkamas, pasibaigęs, panaikintas, neatitinka įgaliojimo užklausoje naudoto nukreipimo URI arba buvo išduotas kitam klientui.
|
||||||
|
invalid_redirect_uri: Nukreipimo uri įtrauktas yra netinkamas.
|
||||||
|
invalid_request:
|
||||||
|
missing_param: 'Trūksta privalomo parametro: %{value}.'
|
||||||
|
request_not_authorized: Užklausą reikia įgalioti. Reikalingo parametro užklausai įgalioti trūksta arba jis netinkamas.
|
||||||
|
unknown: Užklausoje trūksta privalomo parametro, turi nepalaikomą parametro reikšmę arba yra kitaip netinkamai suformuota.
|
||||||
|
invalid_resource_owner: Pateikti išteklių savininko įgaliojimai yra netinkami arba išteklių savininko negalima surasti.
|
||||||
|
invalid_scope: Užklausos aprėptis yra netinkama, nežinoma arba netinkamai suformuota.
|
||||||
|
invalid_token:
|
||||||
|
expired: Baigėsi prieigos rakto galiojimas.
|
||||||
|
revoked: Prieigos raktas buvo panaikintas.
|
||||||
|
unknown: Prieigos raktas yra netinkamas.
|
||||||
|
resource_owner_authenticator_not_configured: Išteklių savininko suradimas nepavyko dėl to, kad Doorkeeper.configure.resource_owner_authenticator nėra sukonfigūruotas.
|
||||||
|
server_error: Įgaliojimų serveris susidūrė su netikėta sąlyga, dėl kurios negalėjo užpildyti užklausos.
|
||||||
|
temporarily_unavailable: Įgaliojimų serveris šiuo metu negali apdoroti užklausos dėl laikinos serverio perkrovos arba techninės priežiūros.
|
||||||
|
unauthorized_client: Klientas nėra įgaliotas atlikti šią užklausą šiuo metodu.
|
||||||
|
unsupported_grant_type: Įgaliojimų suteikimo tipas nepalaikomas įgaliojimų serveryje.
|
||||||
|
unsupported_response_type: Įgaliojimų serveris nepalaiko šio atsako tipo.
|
||||||
|
flash:
|
||||||
|
applications:
|
||||||
|
create:
|
||||||
|
notice: Programėlė sukurta.
|
||||||
|
destroy:
|
||||||
|
notice: Programėlė ištrinta.
|
||||||
|
update:
|
||||||
|
notice: Programėlė atnaujinta.
|
||||||
|
authorized_applications:
|
||||||
|
destroy:
|
||||||
|
notice: Programėlė panaikinta.
|
||||||
grouped_scopes:
|
grouped_scopes:
|
||||||
|
access:
|
||||||
|
read: Tik skaitymo prieiga
|
||||||
|
read/write: Skaitymo ir rašymo prieiga
|
||||||
|
write: Tik rašymo prieiga
|
||||||
title:
|
title:
|
||||||
|
accounts: Paskyros
|
||||||
|
admin/accounts: Paskyrų administravimas
|
||||||
|
admin/all: Visi administraciniai funkcijos
|
||||||
|
admin/reports: Ataskaitų administravimas
|
||||||
|
all: Pilna prieiga prie tavo Mastodon paskyros
|
||||||
blocks: Blokavimai
|
blocks: Blokavimai
|
||||||
|
bookmarks: Žymės
|
||||||
|
conversations: Pokalbiai
|
||||||
|
crypto: Galo iki galo užšifravimas
|
||||||
|
favourites: Mėgstami
|
||||||
|
filters: Filtrai
|
||||||
follow: Sekimai, nutildymai ir blokavimai
|
follow: Sekimai, nutildymai ir blokavimai
|
||||||
|
follows: Sekimai
|
||||||
|
lists: Sąrašai
|
||||||
|
media: Medijos priedai
|
||||||
|
mutes: Užtildymai
|
||||||
|
notifications: Pranešimai
|
||||||
|
push: Stumdomieji pranešimai
|
||||||
|
reports: Ataskaitos
|
||||||
|
search: Paieška
|
||||||
statuses: Įrašai
|
statuses: Įrašai
|
||||||
layouts:
|
layouts:
|
||||||
admin:
|
admin:
|
||||||
|
@ -37,6 +162,7 @@ lt:
|
||||||
admin:write:domain_blocks: atlikti prižiūrėjimo veiksmus su domenų blokavimais
|
admin:write:domain_blocks: atlikti prižiūrėjimo veiksmus su domenų blokavimais
|
||||||
admin:write:email_domain_blocks: atlikti prižiūrėjimo veiksmus su el. laiško domenų blokavimais
|
admin:write:email_domain_blocks: atlikti prižiūrėjimo veiksmus su el. laiško domenų blokavimais
|
||||||
admin:write:ip_blocks: atlikti prižiūrėjimo veiksmus su IP blokavimais
|
admin:write:ip_blocks: atlikti prižiūrėjimo veiksmus su IP blokavimais
|
||||||
|
admin:write:reports: atlikti paskyrų prižiūrėjimo veiksmus atsakaitams
|
||||||
crypto: naudoti galo iki galo šifravimą
|
crypto: naudoti galo iki galo šifravimą
|
||||||
follow: modifikuoti paskyros santykius
|
follow: modifikuoti paskyros santykius
|
||||||
push: gauti tavo stumiamuosius pranešimus
|
push: gauti tavo stumiamuosius pranešimus
|
||||||
|
|
|
@ -1559,6 +1559,7 @@ en:
|
||||||
'86400': 1 day
|
'86400': 1 day
|
||||||
expires_in_prompt: Never
|
expires_in_prompt: Never
|
||||||
generate: Generate invite link
|
generate: Generate invite link
|
||||||
|
invalid: This invite is not valid
|
||||||
invited_by: 'You were invited by:'
|
invited_by: 'You were invited by:'
|
||||||
max_uses:
|
max_uses:
|
||||||
one: 1 use
|
one: 1 use
|
||||||
|
|
|
@ -131,7 +131,7 @@ fa:
|
||||||
reset_password: بازنشانی گذرواژه
|
reset_password: بازنشانی گذرواژه
|
||||||
resubscribe: اشتراک دوباره
|
resubscribe: اشتراک دوباره
|
||||||
role: نقش
|
role: نقش
|
||||||
search: جستجو
|
search: جستوجو
|
||||||
search_same_email_domain: دیگر کاربران با دامنهٔ رایانامهٔ یکسان
|
search_same_email_domain: دیگر کاربران با دامنهٔ رایانامهٔ یکسان
|
||||||
search_same_ip: دیگر کاربران با IP یکسان
|
search_same_ip: دیگر کاربران با IP یکسان
|
||||||
security: امنیت
|
security: امنیت
|
||||||
|
@ -386,6 +386,10 @@ fa:
|
||||||
confirm_suspension:
|
confirm_suspension:
|
||||||
cancel: لغو
|
cancel: لغو
|
||||||
confirm: تعلیق
|
confirm: تعلیق
|
||||||
|
permanent_action: برگرداندن تعلیق هیچ داده یا ارتباطی را برنخواهد گرداند.
|
||||||
|
preamble_html: در حال تعلیق <strong>%{domain}</strong> و همهٔ زیردامنههایش هستید.
|
||||||
|
remove_all_data: این کار همهٔ دادههای نمایه، محتوا و رسانههای حسابهای این دامنه را از کارسازتان برمیدارد.
|
||||||
|
stop_communication: کارسازتان دیگر با این کارسازها ارتباط برقرار نخواهد کرد.
|
||||||
title: تأیید انسداد دامنه برای %{domain}
|
title: تأیید انسداد دامنه برای %{domain}
|
||||||
created_msg: مسدودسازی دامنه در حال پردازش است
|
created_msg: مسدودسازی دامنه در حال پردازش است
|
||||||
destroyed_msg: انسداد دامنه واگردانده شد
|
destroyed_msg: انسداد دامنه واگردانده شد
|
||||||
|
@ -1219,7 +1223,7 @@ fa:
|
||||||
followers: این کار همهٔ پیگیران شما را از حساب فعلی به حساب تازه منتقل خواهد کرد
|
followers: این کار همهٔ پیگیران شما را از حساب فعلی به حساب تازه منتقل خواهد کرد
|
||||||
only_redirect_html: شما همچنین میتوانید حساب خود را <a href="%{path}">به یک حساب دیگر اشاره دهید</a>.
|
only_redirect_html: شما همچنین میتوانید حساب خود را <a href="%{path}">به یک حساب دیگر اشاره دهید</a>.
|
||||||
other_data: هیچ دادهٔ دیگری خودبهخود منتقل نخواهد شد
|
other_data: هیچ دادهٔ دیگری خودبهخود منتقل نخواهد شد
|
||||||
redirect: نمایهٔ حساب فعلی شما به حساب تازه اشاره خواهد کرد و خودش در نتیجهٔ جستجوها ظاهر نخواهد شد
|
redirect: نمایهٔ حساب کنونیتان به حساب تازه اشاره خواهد کرد و از جستوجوها حذف خواهد شد
|
||||||
moderation:
|
moderation:
|
||||||
title: مدیریت کاربران
|
title: مدیریت کاربران
|
||||||
move_handler:
|
move_handler:
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
|
---
|
||||||
ig:
|
ig:
|
||||||
|
filters:
|
||||||
|
contexts:
|
||||||
|
home: Ụlọ na ndepụta
|
||||||
|
|
|
@ -1227,7 +1227,7 @@ ja:
|
||||||
title: セキュリティチェック
|
title: セキュリティチェック
|
||||||
cloudflare_with_registering: 登録時にCloudflareの画面が表示されます。登録できないときは管理者へご連絡ください
|
cloudflare_with_registering: 登録時にCloudflareの画面が表示されます。登録できないときは管理者へご連絡ください
|
||||||
confirmations:
|
confirmations:
|
||||||
awaiting_review: メールアドレスは確認済みです。%{domain} のモデレーターによりアカウント登録の審査が完了すると、メールでお知らせします。
|
awaiting_review: メールアドレスが確認できました。%{domain} のスタッフが登録審査を行います。承認されたらメールでお知らせします!
|
||||||
awaiting_review_title: 登録の審査待ちです
|
awaiting_review_title: 登録の審査待ちです
|
||||||
clicking_this_link: このリンクを押す
|
clicking_this_link: このリンクを押す
|
||||||
login_link: ログイン
|
login_link: ログイン
|
||||||
|
|
|
@ -1689,8 +1689,8 @@ ko:
|
||||||
keep_polls_hint: 설문을 삭제하지 않았음
|
keep_polls_hint: 설문을 삭제하지 않았음
|
||||||
keep_self_bookmark: 북마크한 게시물 유지
|
keep_self_bookmark: 북마크한 게시물 유지
|
||||||
keep_self_bookmark_hint: 북마크한 본인의 게시물을 삭제하지 않습니다
|
keep_self_bookmark_hint: 북마크한 본인의 게시물을 삭제하지 않습니다
|
||||||
keep_self_fav: 마음에 들어한 게시물 유지
|
keep_self_fav: 내가 좋아요한 게시물 유지
|
||||||
keep_self_fav_hint: 내 스스로 마음에 들어한 본인의 게시물을 삭제하지 않습니다
|
keep_self_fav_hint: 스스로 좋아요를 누른 본인의 게시물을 삭제하지 않습니다
|
||||||
min_age:
|
min_age:
|
||||||
'1209600': 2 주
|
'1209600': 2 주
|
||||||
'15778476': 6 개월
|
'15778476': 6 개월
|
||||||
|
|
|
@ -1041,6 +1041,14 @@ nn:
|
||||||
hint_html: Berre ein ting til! Vi må bekrefte at du er et menneske (så vi kan halde spam ute!). Løys CAPTCHA-en nedanfor og klikk "Fortsett".
|
hint_html: Berre ein ting til! Vi må bekrefte at du er et menneske (så vi kan halde spam ute!). Løys CAPTCHA-en nedanfor og klikk "Fortsett".
|
||||||
title: Sikkerheitssjekk
|
title: Sikkerheitssjekk
|
||||||
confirmations:
|
confirmations:
|
||||||
|
awaiting_review: Din e-post adresse er bekreftet! %{domain} ansatte gjennomgår nå registreringen din. Du vil motta en e-post hvis de godkjenner din konto!
|
||||||
|
awaiting_review_title: Din registrering blir vurdert
|
||||||
|
clicking_this_link: klikke på denne lenken
|
||||||
|
login_link: logg inn
|
||||||
|
proceed_to_login_html: Du kan nå fortsette til %{login_link}.
|
||||||
|
redirect_to_app_html: Du burde bli omdirigert til <strong>%{app_name}</strong> -appen. Hvis det ikke skjedde, kan du prøve %{clicking_this_link} eller manuelt gå tilbake til appen.
|
||||||
|
registration_complete: Registreringen på %{domain} er nå fullført!
|
||||||
|
welcome_title: Velkommen, %{name}!
|
||||||
wrong_email_hint: Viss epostadressa er feil, kan du endra ho i kontoinnstillingane.
|
wrong_email_hint: Viss epostadressa er feil, kan du endra ho i kontoinnstillingane.
|
||||||
delete_account: Slett konto
|
delete_account: Slett konto
|
||||||
delete_account_html: Om du vil sletta kontoen din, kan du <a href="%{path}">gå hit</a>. Du vert spurd etter stadfesting.
|
delete_account_html: Om du vil sletta kontoen din, kan du <a href="%{path}">gå hit</a>. Du vert spurd etter stadfesting.
|
||||||
|
|
|
@ -772,6 +772,11 @@
|
||||||
approved: Godkjenning kreves for påmelding
|
approved: Godkjenning kreves for påmelding
|
||||||
none: Ingen kan melde seg inn
|
none: Ingen kan melde seg inn
|
||||||
open: Hvem som helst kan melde seg inn
|
open: Hvem som helst kan melde seg inn
|
||||||
|
security:
|
||||||
|
authorized_fetch: Krev autentisering fra fødererte servere
|
||||||
|
authorized_fetch_hint: Krav om godkjenning fra fødererte servere muliggjør strengere håndhevelse av blokker på både brukernivå og servernivå. Dette går imidlertid på bekostning av en ytelsesstraff, reduserer rekkevidden til svarene dine og kan introdusere kompatibilitetsproblemer med enkelte fødererte tjenester. I tillegg vil dette ikke hindre dedikerte aktører i å hente dine offentlige innlegg og kontoer.
|
||||||
|
authorized_fetch_overridden_hint: Du kan for øyeblikket ikke endre denne innstillingen fordi den overstyres av en miljøvariabel.
|
||||||
|
federation_authentication: Håndheving av føderasjonsautentisering
|
||||||
title: Serverinnstillinger
|
title: Serverinnstillinger
|
||||||
site_uploads:
|
site_uploads:
|
||||||
delete: Slett den opplastede filen
|
delete: Slett den opplastede filen
|
||||||
|
@ -1036,6 +1041,14 @@
|
||||||
hint_html: Bare en ting til! Vi må bekrefte at du er et menneske (dette er slik at vi kan holde spam ute!). Løs CAPTCHA nedenfor og klikk "Fortsett".
|
hint_html: Bare en ting til! Vi må bekrefte at du er et menneske (dette er slik at vi kan holde spam ute!). Løs CAPTCHA nedenfor og klikk "Fortsett".
|
||||||
title: Sikkerhetskontroll
|
title: Sikkerhetskontroll
|
||||||
confirmations:
|
confirmations:
|
||||||
|
awaiting_review: Din e-post adresse er bekreftet! %{domain} ansatte gjennomgår nå registreringen din. Du vil motta en e-post hvis de godkjenner din konto!
|
||||||
|
awaiting_review_title: Din registrering blir vurdert
|
||||||
|
clicking_this_link: klikke på denne lenken
|
||||||
|
login_link: logg inn
|
||||||
|
proceed_to_login_html: Du kan nå fortsette til %{login_link}.
|
||||||
|
redirect_to_app_html: Du burde bli omdirigert til <strong>%{app_name}</strong> -appen. Hvis det ikke skjedde, kan du prøve %{clicking_this_link} eller manuelt gå tilbake til appen.
|
||||||
|
registration_complete: Registreringen på %{domain} er nå fullført!
|
||||||
|
welcome_title: Velkommen, %{name}!
|
||||||
wrong_email_hint: Hvis e-postadressen ikke er riktig, kan du endre den i kontoinnstillingene.
|
wrong_email_hint: Hvis e-postadressen ikke er riktig, kan du endre den i kontoinnstillingene.
|
||||||
delete_account: Slett konto
|
delete_account: Slett konto
|
||||||
delete_account_html: Hvis du ønsker å slette kontoen din, kan du <a href="%{path}">gå hit</a>. Du vil bli spurt om bekreftelse.
|
delete_account_html: Hvis du ønsker å slette kontoen din, kan du <a href="%{path}">gå hit</a>. Du vil bli spurt om bekreftelse.
|
||||||
|
@ -1739,6 +1752,10 @@
|
||||||
month: "%b %Y"
|
month: "%b %Y"
|
||||||
time: "%H:%M"
|
time: "%H:%M"
|
||||||
with_time_zone: "%-d. %b %Y, %H:%M %Z"
|
with_time_zone: "%-d. %b %Y, %H:%M %Z"
|
||||||
|
translation:
|
||||||
|
errors:
|
||||||
|
quota_exceeded: Den serveromfattende brukskvoten for oversettelsestjenesten er overskredet.
|
||||||
|
too_many_requests: Det har nylig vært for mange forespørsler til oversettelsestjenesten.
|
||||||
two_factor_authentication:
|
two_factor_authentication:
|
||||||
add: Legg til
|
add: Legg til
|
||||||
disable: Skru av
|
disable: Skru av
|
||||||
|
|
|
@ -5,7 +5,7 @@ he:
|
||||||
account:
|
account:
|
||||||
discoverable: הפוסטים והפרופיל שלך עשויים להיות מוצגים או מומלצים באזורים שונים באתר וייתכן שהפרופיל שלך יוצע למשתמשים אחרים.
|
discoverable: הפוסטים והפרופיל שלך עשויים להיות מוצגים או מומלצים באזורים שונים באתר וייתכן שהפרופיל שלך יוצע למשתמשים אחרים.
|
||||||
display_name: שמך המלא או שם הכיף שלך.
|
display_name: שמך המלא או שם הכיף שלך.
|
||||||
fields: עמוד הבית שלך, כינויי גוף, גיל, וכל מידע אחר לפי העדפתך האישית.
|
fields: עמוד הבית שלך, לשון הפנייה, גיל, וכל מידע אחר לפי העדפתך האישית.
|
||||||
indexable: ההודעות הפומביות שלך עשויות להופיע בתוצאות חיפוש במסטודון. אחרים שהדהדו, חיבבו או ענו להודעות האלו יוכלו למצוא אותן בחיפוש בכל מקרה.
|
indexable: ההודעות הפומביות שלך עשויות להופיע בתוצאות חיפוש במסטודון. אחרים שהדהדו, חיבבו או ענו להודעות האלו יוכלו למצוא אותן בחיפוש בכל מקרה.
|
||||||
note: 'ניתן לאזכר @אחרים או #תגיות.'
|
note: 'ניתן לאזכר @אחרים או #תגיות.'
|
||||||
show_collections: אנשים יוכלו לדפדף בין העוקבים והנעקבים שלך. אנשים שאת.ה עוקב.ת אחריהם יראו את המעקב אחריהם כרגיל.
|
show_collections: אנשים יוכלו לדפדף בין העוקבים והנעקבים שלך. אנשים שאת.ה עוקב.ת אחריהם יראו את המעקב אחריהם כרגיל.
|
||||||
|
|
|
@ -323,6 +323,7 @@
|
||||||
url: Endepunkt lenke
|
url: Endepunkt lenke
|
||||||
'no': Nei
|
'no': Nei
|
||||||
not_recommended: Ikke anbefalt
|
not_recommended: Ikke anbefalt
|
||||||
|
overridden: Overstyrt
|
||||||
recommended: Anbefalt
|
recommended: Anbefalt
|
||||||
required:
|
required:
|
||||||
mark: "*"
|
mark: "*"
|
||||||
|
|
|
@ -88,6 +88,8 @@ Rails.application.routes.draw do
|
||||||
resource :outbox, only: [:show], module: :activitypub
|
resource :outbox, only: [:show], module: :activitypub
|
||||||
end
|
end
|
||||||
|
|
||||||
|
get '/invite/:invite_code', constraints: ->(req) { req.format == :json }, to: 'api/v1/invites#show'
|
||||||
|
|
||||||
devise_scope :user do
|
devise_scope :user do
|
||||||
get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite
|
get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite
|
||||||
|
|
||||||
|
|
|
@ -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: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddURLToPreviewCardsStatuses < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
add_column :preview_cards_statuses, :url, :string
|
||||||
|
end
|
||||||
|
end
|
43
db/schema.rb
43
db/schema.rb
|
@ -50,15 +50,6 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.index ["account_id", "domain"], name: "index_account_domain_blocks_on_account_id_and_domain", unique: true
|
t.index ["account_id", "domain"], name: "index_account_domain_blocks_on_account_id_and_domain", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "account_groups", force: :cascade do |t|
|
|
||||||
t.bigint "account_id", null: false
|
|
||||||
t.bigint "group_account_id", null: false
|
|
||||||
t.datetime "created_at", null: false
|
|
||||||
t.datetime "updated_at", null: false
|
|
||||||
t.index ["account_id"], name: "index_account_groups_on_account_id"
|
|
||||||
t.index ["group_account_id"], name: "index_account_groups_on_group_account_id"
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table "account_migrations", force: :cascade do |t|
|
create_table "account_migrations", force: :cascade do |t|
|
||||||
t.bigint "account_id"
|
t.bigint "account_id"
|
||||||
t.string "acct", default: "", null: false
|
t.string "acct", default: "", null: false
|
||||||
|
@ -165,11 +156,11 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.string "url"
|
t.string "url"
|
||||||
t.string "avatar_file_name"
|
t.string "avatar_file_name"
|
||||||
t.string "avatar_content_type"
|
t.string "avatar_content_type"
|
||||||
t.integer "avatar_file_size"
|
t.bigint "avatar_file_size"
|
||||||
t.datetime "avatar_updated_at", precision: nil
|
t.datetime "avatar_updated_at", precision: nil
|
||||||
t.string "header_file_name"
|
t.string "header_file_name"
|
||||||
t.string "header_content_type"
|
t.string "header_content_type"
|
||||||
t.integer "header_file_size"
|
t.bigint "header_file_size"
|
||||||
t.datetime "header_updated_at", precision: nil
|
t.datetime "header_updated_at", precision: nil
|
||||||
t.string "avatar_remote_url"
|
t.string "avatar_remote_url"
|
||||||
t.boolean "locked", default: false, null: false
|
t.boolean "locked", default: false, null: false
|
||||||
|
@ -193,8 +184,8 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.integer "avatar_storage_schema_version"
|
t.integer "avatar_storage_schema_version"
|
||||||
t.integer "header_storage_schema_version"
|
t.integer "header_storage_schema_version"
|
||||||
t.string "devices_url"
|
t.string "devices_url"
|
||||||
t.integer "suspension_origin"
|
|
||||||
t.datetime "sensitized_at", precision: nil
|
t.datetime "sensitized_at", precision: nil
|
||||||
|
t.integer "suspension_origin"
|
||||||
t.boolean "trendable"
|
t.boolean "trendable"
|
||||||
t.datetime "reviewed_at", precision: nil
|
t.datetime "reviewed_at", precision: nil
|
||||||
t.datetime "requested_review_at", precision: nil
|
t.datetime "requested_review_at", precision: nil
|
||||||
|
@ -332,6 +323,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.index ["ignore_reblog"], name: "index_antennas_on_ignore_reblog"
|
t.index ["ignore_reblog"], name: "index_antennas_on_ignore_reblog"
|
||||||
t.index ["list_id"], name: "index_antennas_on_list_id"
|
t.index ["list_id"], name: "index_antennas_on_list_id"
|
||||||
t.index ["stl"], name: "index_antennas_on_stl"
|
t.index ["stl"], name: "index_antennas_on_stl"
|
||||||
|
t.index ["with_media_only"], name: "index_antennas_on_with_media_only"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "appeals", force: :cascade do |t|
|
create_table "appeals", force: :cascade do |t|
|
||||||
|
@ -490,7 +482,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.string "domain"
|
t.string "domain"
|
||||||
t.string "image_file_name"
|
t.string "image_file_name"
|
||||||
t.string "image_content_type"
|
t.string "image_content_type"
|
||||||
t.integer "image_file_size"
|
t.bigint "image_file_size"
|
||||||
t.datetime "image_updated_at", precision: nil
|
t.datetime "image_updated_at", precision: nil
|
||||||
t.datetime "created_at", precision: nil, null: false
|
t.datetime "created_at", precision: nil, null: false
|
||||||
t.datetime "updated_at", precision: nil, null: false
|
t.datetime "updated_at", precision: nil, null: false
|
||||||
|
@ -710,7 +702,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.datetime "updated_at", precision: nil, null: false
|
t.datetime "updated_at", precision: nil, null: false
|
||||||
t.string "data_file_name"
|
t.string "data_file_name"
|
||||||
t.string "data_content_type"
|
t.string "data_content_type"
|
||||||
t.integer "data_file_size"
|
t.bigint "data_file_size"
|
||||||
t.datetime "data_updated_at", precision: nil
|
t.datetime "data_updated_at", precision: nil
|
||||||
t.bigint "account_id", null: false
|
t.bigint "account_id", null: false
|
||||||
t.boolean "overwrite", default: false, null: false
|
t.boolean "overwrite", default: false, null: false
|
||||||
|
@ -741,12 +733,12 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "ip_blocks", force: :cascade do |t|
|
create_table "ip_blocks", force: :cascade do |t|
|
||||||
t.datetime "created_at", precision: nil, null: false
|
|
||||||
t.datetime "updated_at", precision: nil, null: false
|
|
||||||
t.datetime "expires_at", precision: nil
|
|
||||||
t.inet "ip", default: "0.0.0.0", null: false
|
t.inet "ip", default: "0.0.0.0", null: false
|
||||||
t.integer "severity", default: 0, null: false
|
t.integer "severity", default: 0, null: false
|
||||||
|
t.datetime "expires_at", precision: nil
|
||||||
t.text "comment", default: "", null: false
|
t.text "comment", default: "", null: false
|
||||||
|
t.datetime "created_at", precision: nil, null: false
|
||||||
|
t.datetime "updated_at", precision: nil, null: false
|
||||||
t.index ["ip"], name: "index_ip_blocks_on_ip", unique: true
|
t.index ["ip"], name: "index_ip_blocks_on_ip", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -808,7 +800,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.bigint "status_id"
|
t.bigint "status_id"
|
||||||
t.string "file_file_name"
|
t.string "file_file_name"
|
||||||
t.string "file_content_type"
|
t.string "file_content_type"
|
||||||
t.integer "file_file_size"
|
t.bigint "file_file_size"
|
||||||
t.datetime "file_updated_at", precision: nil
|
t.datetime "file_updated_at", precision: nil
|
||||||
t.string "remote_url", default: "", null: false
|
t.string "remote_url", default: "", null: false
|
||||||
t.datetime "created_at", precision: nil, null: false
|
t.datetime "created_at", precision: nil, null: false
|
||||||
|
@ -824,8 +816,8 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.integer "file_storage_schema_version"
|
t.integer "file_storage_schema_version"
|
||||||
t.string "thumbnail_file_name"
|
t.string "thumbnail_file_name"
|
||||||
t.string "thumbnail_content_type"
|
t.string "thumbnail_content_type"
|
||||||
t.integer "thumbnail_file_size"
|
t.bigint "thumbnail_file_size"
|
||||||
t.datetime "thumbnail_updated_at", precision: nil
|
t.datetime "thumbnail_updated_at"
|
||||||
t.string "thumbnail_remote_url"
|
t.string "thumbnail_remote_url"
|
||||||
t.index ["account_id", "status_id"], name: "index_media_attachments_on_account_id_and_status_id", order: { status_id: :desc }
|
t.index ["account_id", "status_id"], name: "index_media_attachments_on_account_id_and_status_id", order: { status_id: :desc }
|
||||||
t.index ["scheduled_status_id"], name: "index_media_attachments_on_scheduled_status_id", where: "(scheduled_status_id IS NOT NULL)"
|
t.index ["scheduled_status_id"], name: "index_media_attachments_on_scheduled_status_id", where: "(scheduled_status_id IS NOT NULL)"
|
||||||
|
@ -992,7 +984,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.string "description", default: "", null: false
|
t.string "description", default: "", null: false
|
||||||
t.string "image_file_name"
|
t.string "image_file_name"
|
||||||
t.string "image_content_type"
|
t.string "image_content_type"
|
||||||
t.integer "image_file_size"
|
t.bigint "image_file_size"
|
||||||
t.datetime "image_updated_at", precision: nil
|
t.datetime "image_updated_at", precision: nil
|
||||||
t.integer "type", default: 0, null: false
|
t.integer "type", default: 0, null: false
|
||||||
t.text "html", default: "", null: false
|
t.text "html", default: "", null: false
|
||||||
|
@ -1020,6 +1012,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
create_table "preview_cards_statuses", primary_key: ["status_id", "preview_card_id"], force: :cascade do |t|
|
create_table "preview_cards_statuses", primary_key: ["status_id", "preview_card_id"], force: :cascade do |t|
|
||||||
t.bigint "preview_card_id", null: false
|
t.bigint "preview_card_id", null: false
|
||||||
t.bigint "status_id", null: false
|
t.bigint "status_id", null: false
|
||||||
|
t.string "url"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "relays", force: :cascade do |t|
|
create_table "relays", force: :cascade do |t|
|
||||||
|
@ -1115,7 +1108,7 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.string "var", default: "", null: false
|
t.string "var", default: "", null: false
|
||||||
t.string "file_file_name"
|
t.string "file_file_name"
|
||||||
t.string "file_content_type"
|
t.string "file_content_type"
|
||||||
t.integer "file_file_size"
|
t.bigint "file_file_size"
|
||||||
t.datetime "file_updated_at", precision: nil
|
t.datetime "file_updated_at", precision: nil
|
||||||
t.json "meta"
|
t.json "meta"
|
||||||
t.datetime "created_at", precision: nil, null: false
|
t.datetime "created_at", precision: nil, null: false
|
||||||
|
@ -1161,8 +1154,8 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
create_table "status_pins", force: :cascade do |t|
|
create_table "status_pins", force: :cascade do |t|
|
||||||
t.bigint "account_id", null: false
|
t.bigint "account_id", null: false
|
||||||
t.bigint "status_id", null: false
|
t.bigint "status_id", null: false
|
||||||
t.datetime "created_at", precision: nil, default: -> { "now()" }, null: false
|
t.datetime "created_at", precision: nil, default: -> { "CURRENT_TIMESTAMP" }, null: false
|
||||||
t.datetime "updated_at", precision: nil, default: -> { "now()" }, null: false
|
t.datetime "updated_at", precision: nil, default: -> { "CURRENT_TIMESTAMP" }, null: false
|
||||||
t.index ["account_id", "status_id"], name: "index_status_pins_on_account_id_and_status_id", unique: true
|
t.index ["account_id", "status_id"], name: "index_status_pins_on_account_id_and_status_id", unique: true
|
||||||
t.index ["status_id"], name: "index_status_pins_on_status_id"
|
t.index ["status_id"], name: "index_status_pins_on_status_id"
|
||||||
end
|
end
|
||||||
|
@ -1187,7 +1180,6 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
t.datetime "updated_at", precision: nil, null: false
|
t.datetime "updated_at", precision: nil, null: false
|
||||||
t.string "emoji_reactions"
|
t.string "emoji_reactions"
|
||||||
t.integer "emoji_reactions_count", default: 0, null: false
|
t.integer "emoji_reactions_count", default: 0, null: false
|
||||||
t.integer "test", default: 0, null: false
|
|
||||||
t.integer "emoji_reaction_accounts_count", default: 0, null: false
|
t.integer "emoji_reaction_accounts_count", default: 0, null: false
|
||||||
t.integer "status_referred_by_count", default: 0, null: false
|
t.integer "status_referred_by_count", default: 0, null: false
|
||||||
t.index ["status_id"], name: "index_status_stats_on_status_id", unique: true
|
t.index ["status_id"], name: "index_status_stats_on_status_id", unique: true
|
||||||
|
@ -1412,7 +1404,6 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_05_225839) do
|
||||||
add_foreign_key "account_conversations", "conversations", on_delete: :cascade
|
add_foreign_key "account_conversations", "conversations", on_delete: :cascade
|
||||||
add_foreign_key "account_deletion_requests", "accounts", on_delete: :cascade
|
add_foreign_key "account_deletion_requests", "accounts", on_delete: :cascade
|
||||||
add_foreign_key "account_domain_blocks", "accounts", name: "fk_206c6029bd", on_delete: :cascade
|
add_foreign_key "account_domain_blocks", "accounts", name: "fk_206c6029bd", on_delete: :cascade
|
||||||
add_foreign_key "account_groups", "accounts", on_delete: :cascade
|
|
||||||
add_foreign_key "account_migrations", "accounts", column: "target_account_id", on_delete: :nullify
|
add_foreign_key "account_migrations", "accounts", column: "target_account_id", on_delete: :nullify
|
||||||
add_foreign_key "account_migrations", "accounts", on_delete: :cascade
|
add_foreign_key "account_migrations", "accounts", on_delete: :cascade
|
||||||
add_foreign_key "account_moderation_notes", "accounts"
|
add_foreign_key "account_moderation_notes", "accounts"
|
||||||
|
|
|
@ -19,7 +19,7 @@ const config = {
|
||||||
// Those packages are ESM, so we need them to be processed by Babel
|
// Those packages are ESM, so we need them to be processed by Babel
|
||||||
transformIgnorePatterns: ['/node_modules/(?!(redent|strip-indent)/)'],
|
transformIgnorePatterns: ['/node_modules/(?!(redent|strip-indent)/)'],
|
||||||
coverageDirectory: '<rootDir>/coverage',
|
coverageDirectory: '<rootDir>/coverage',
|
||||||
moduleDirectories: ['<rootDir>/node_modules', '<rootDir>/app/javascript'],
|
moduleDirectories: ['node_modules', '<rootDir>/app/javascript'],
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'\\.svg$': '<rootDir>/app/javascript/__mocks__/svg.js',
|
'\\.svg$': '<rootDir>/app/javascript/__mocks__/svg.js',
|
||||||
},
|
},
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace :tests do
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
unless Status.find(12).preview_cards.pluck(:url) == ['https://joinmastodon.org/']
|
unless PreviewCard.where(id: PreviewCardsStatus.where(status_id: 12).select(:preview_card_id)).pluck(:url) == ['https://joinmastodon.org/']
|
||||||
puts 'Preview cards not deduplicated as expected'
|
puts 'Preview cards not deduplicated as expected'
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
|
|
|
@ -181,7 +181,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",
|
||||||
|
@ -205,7 +205,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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -2,14 +2,44 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Api::V1::Trends::LinksController do
|
RSpec.describe Api::V1::Trends::LinksController do
|
||||||
render_views
|
render_views
|
||||||
|
|
||||||
describe 'GET #index' do
|
describe 'GET #index' do
|
||||||
|
around do |example|
|
||||||
|
previous = Setting.trends
|
||||||
|
example.run
|
||||||
|
Setting.trends = previous
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when trends are disabled' do
|
||||||
|
before { Setting.trends = false }
|
||||||
|
|
||||||
it 'returns http success' do
|
it 'returns http success' do
|
||||||
get :index
|
get :index
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when trends are enabled' do
|
||||||
|
before { Setting.trends = true }
|
||||||
|
|
||||||
|
it 'returns http success' do
|
||||||
|
prepare_trends
|
||||||
|
stub_const('Api::V1::Trends::LinksController::DEFAULT_LINKS_LIMIT', 2)
|
||||||
|
get :index
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.headers).to include('Link')
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_trends
|
||||||
|
Fabricate.times(3, :preview_card, trendable: true, language: 'en').each do |link|
|
||||||
|
2.times { |i| Trends.links.add(link, i) }
|
||||||
|
end
|
||||||
|
Trends::Links.new(threshold: 1).refresh
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,14 +2,44 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe Api::V1::Trends::StatusesController do
|
RSpec.describe Api::V1::Trends::StatusesController do
|
||||||
render_views
|
render_views
|
||||||
|
|
||||||
describe 'GET #index' do
|
describe 'GET #index' do
|
||||||
|
around do |example|
|
||||||
|
previous = Setting.trends
|
||||||
|
example.run
|
||||||
|
Setting.trends = previous
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when trends are disabled' do
|
||||||
|
before { Setting.trends = false }
|
||||||
|
|
||||||
it 'returns http success' do
|
it 'returns http success' do
|
||||||
get :index
|
get :index
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when trends are enabled' do
|
||||||
|
before { Setting.trends = true }
|
||||||
|
|
||||||
|
it 'returns http success' do
|
||||||
|
prepare_trends
|
||||||
|
stub_const('Api::BaseController::DEFAULT_STATUSES_LIMIT', 2)
|
||||||
|
get :index
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.headers).to include('Link')
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_trends
|
||||||
|
Fabricate.times(3, :status, trendable: true, language: 'en').each do |status|
|
||||||
|
2.times { |i| Trends.statuses.add(status, i) }
|
||||||
|
end
|
||||||
|
Trends::Statuses.new(threshold: 1, decay_threshold: -1).refresh
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,16 +6,41 @@ RSpec.describe Api::V1::Trends::TagsController do
|
||||||
render_views
|
render_views
|
||||||
|
|
||||||
describe 'GET #index' do
|
describe 'GET #index' do
|
||||||
before do
|
around do |example|
|
||||||
Fabricate.times(10, :tag).each do |tag|
|
previous = Setting.trends
|
||||||
10.times { |i| Trends.tags.add(tag, i) }
|
example.run
|
||||||
|
Setting.trends = previous
|
||||||
end
|
end
|
||||||
|
|
||||||
get :index
|
context 'when trends are disabled' do
|
||||||
end
|
before { Setting.trends = false }
|
||||||
|
|
||||||
it 'returns http success' do
|
it 'returns http success' do
|
||||||
|
get :index
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.headers).to_not include('Link')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when trends are enabled' do
|
||||||
|
before { Setting.trends = true }
|
||||||
|
|
||||||
|
it 'returns http success' do
|
||||||
|
prepare_trends
|
||||||
|
stub_const('Api::V1::Trends::TagsController::DEFAULT_TAGS_LIMIT', 2)
|
||||||
|
get :index
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.headers).to include('Link')
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_trends
|
||||||
|
Fabricate.times(3, :tag, trendable: true).each do |tag|
|
||||||
|
2.times { |i| Trends.tags.add(tag, i) }
|
||||||
|
end
|
||||||
|
Trends::Tags.new(threshold: 1).refresh
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -49,10 +49,12 @@ describe MediaComponentHelper do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'render_card_component' do
|
describe 'render_card_component' do
|
||||||
let(:status) { Fabricate(:status, preview_cards: [Fabricate(:preview_card)]) }
|
let(:status) { Fabricate(:status) }
|
||||||
let(:result) { helper.render_card_component(status) }
|
let(:result) { helper.render_card_component(status) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
PreviewCardsStatus.create(status: status, preview_card: Fabricate(:preview_card))
|
||||||
|
|
||||||
without_partial_double_verification do
|
without_partial_double_verification do
|
||||||
allow(helper).to receive(:current_account).and_return(status.account)
|
allow(helper).to receive(:current_account).and_return(status.account)
|
||||||
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
|
||||||
|
|
27
spec/requests/invite_spec.rb
Normal file
27
spec/requests/invite_spec.rb
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe 'invites' do
|
||||||
|
let(:invite) { Fabricate(:invite) }
|
||||||
|
|
||||||
|
context 'when requesting a JSON document' do
|
||||||
|
it 'returns a JSON document with expected attributes' do
|
||||||
|
get "/invite/#{invite.code}", headers: { 'Accept' => 'application/activity+json' }
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.media_type).to eq 'application/json'
|
||||||
|
|
||||||
|
expect(body_as_json[:invite_code]).to eq invite.code
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when not requesting a JSON document' do
|
||||||
|
it 'returns an HTML page' do
|
||||||
|
get "/invite/#{invite.code}"
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.media_type).to eq 'text/html'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,40 +10,65 @@ RSpec.describe AppSignUpService, type: :service do
|
||||||
let(:remote_ip) { IPAddr.new('198.0.2.1') }
|
let(:remote_ip) { IPAddr.new('198.0.2.1') }
|
||||||
|
|
||||||
describe '#call' do
|
describe '#call' do
|
||||||
it 'returns nil when registrations are closed' do
|
let(:params) { good_params }
|
||||||
|
|
||||||
|
shared_examples 'successful registration' do
|
||||||
|
it 'creates an unconfirmed user with access token and the app\'s scope', :aggregate_failures do
|
||||||
|
access_token = subject.call(app, remote_ip, params)
|
||||||
|
expect(access_token).to_not be_nil
|
||||||
|
expect(access_token.scopes.to_s).to eq 'read write'
|
||||||
|
|
||||||
|
user = User.find_by(id: access_token.resource_owner_id)
|
||||||
|
expect(user).to_not be_nil
|
||||||
|
expect(user.confirmed?).to be false
|
||||||
|
|
||||||
|
expect(user.account).to_not be_nil
|
||||||
|
expect(user.invite_request).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when registrations are closed' do
|
||||||
|
around do |example|
|
||||||
tmp = Setting.registrations_mode
|
tmp = Setting.registrations_mode
|
||||||
Setting.registrations_mode = 'none'
|
Setting.registrations_mode = 'none'
|
||||||
expect { subject.call(app, remote_ip, good_params) }.to raise_error Mastodon::NotPermittedError
|
|
||||||
|
example.run
|
||||||
|
|
||||||
Setting.registrations_mode = tmp
|
Setting.registrations_mode = tmp
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'raises an error', :aggregate_failures do
|
||||||
|
expect { subject.call(app, remote_ip, good_params) }.to raise_error Mastodon::NotPermittedError
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using a valid invite' do
|
||||||
|
let(:params) { good_params.merge({ invite_code: invite.code }) }
|
||||||
|
let(:invite) { Fabricate(:invite) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
invite.user.approve!
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'successful registration'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using an invalid invite' do
|
||||||
|
let(:params) { good_params.merge({ invite_code: invite.code }) }
|
||||||
|
let(:invite) { Fabricate(:invite, uses: 1, max_uses: 1) }
|
||||||
|
|
||||||
|
it 'raises an error', :aggregate_failures do
|
||||||
|
expect { subject.call(app, remote_ip, params) }.to raise_error Mastodon::NotPermittedError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it 'raises an error when params are missing' do
|
it 'raises an error when params are missing' do
|
||||||
expect { subject.call(app, remote_ip, {}) }.to raise_error ActiveRecord::RecordInvalid
|
expect { subject.call(app, remote_ip, {}) }.to raise_error ActiveRecord::RecordInvalid
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates an unconfirmed user with access token' do
|
it_behaves_like 'successful registration'
|
||||||
access_token = subject.call(app, remote_ip, good_params)
|
|
||||||
expect(access_token).to_not be_nil
|
|
||||||
user = User.find_by(id: access_token.resource_owner_id)
|
|
||||||
expect(user).to_not be_nil
|
|
||||||
expect(user.confirmed?).to be false
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates access token with the app\'s scopes' do
|
|
||||||
access_token = subject.call(app, remote_ip, good_params)
|
|
||||||
expect(access_token).to_not be_nil
|
|
||||||
expect(access_token.scopes.to_s).to eq 'read write'
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates an account' do
|
|
||||||
access_token = subject.call(app, remote_ip, good_params)
|
|
||||||
expect(access_token).to_not be_nil
|
|
||||||
user = User.find_by(id: access_token.resource_owner_id)
|
|
||||||
expect(user).to_not be_nil
|
|
||||||
expect(user.account).to_not be_nil
|
|
||||||
expect(user.invite_request).to be_nil
|
|
||||||
end
|
|
||||||
|
|
||||||
|
context 'when given an invite request text' do
|
||||||
it 'creates an account with invite request text' do
|
it 'creates an account with invite request text' do
|
||||||
access_token = subject.call(app, remote_ip, good_params.merge(reason: 'Foo bar'))
|
access_token = subject.call(app, remote_ip, good_params.merge(reason: 'Foo bar'))
|
||||||
expect(access_token).to_not be_nil
|
expect(access_token).to_not be_nil
|
||||||
|
@ -52,4 +77,5 @@ RSpec.describe AppSignUpService, type: :service do
|
||||||
expect(user.invite_request&.text).to eq 'Foo bar'
|
expect(user.invite_request&.text).to eq 'Foo bar'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -121,7 +121,7 @@ RSpec.describe FetchLinkCardService, type: :service do
|
||||||
let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis') }
|
let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis') }
|
||||||
|
|
||||||
it 'decodes the HTML' do
|
it 'decodes the HTML' do
|
||||||
expect(status.preview_cards.first.title).to eq('SJISのページ')
|
expect(status.preview_card.title).to eq('SJISのページ')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ RSpec.describe FetchLinkCardService, type: :service do
|
||||||
let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis_with_wrong_charset') }
|
let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis_with_wrong_charset') }
|
||||||
|
|
||||||
it 'decodes the HTML despite the wrong charset header' do
|
it 'decodes the HTML despite the wrong charset header' do
|
||||||
expect(status.preview_cards.first.title).to eq('SJISのページ')
|
expect(status.preview_card.title).to eq('SJISのページ')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ RSpec.describe FetchLinkCardService, type: :service do
|
||||||
let(:status) { Fabricate(:status, text: 'Check out http://example.com/koi8-r') }
|
let(:status) { Fabricate(:status, text: 'Check out http://example.com/koi8-r') }
|
||||||
|
|
||||||
it 'decodes the HTML' do
|
it 'decodes the HTML' do
|
||||||
expect(status.preview_cards.first.title).to eq('Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.')
|
expect(status.preview_card.title).to eq('Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ RSpec.describe FetchLinkCardService, type: :service do
|
||||||
let(:status) { Fabricate(:status, text: 'Check out http://example.com/windows-1251') }
|
let(:status) { Fabricate(:status, text: 'Check out http://example.com/windows-1251') }
|
||||||
|
|
||||||
it 'decodes the HTML' do
|
it 'decodes the HTML' do
|
||||||
expect(status.preview_cards.first.title).to eq('сэмпл текст')
|
expect(status.preview_card.title).to eq('сэмпл текст')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -253,11 +253,21 @@ RSpec.describe FetchLinkCardService, type: :service do
|
||||||
expect(status.preview_card.title).to eq 'Hello world'
|
expect(status.preview_card.title).to eq 'Hello world'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with URL but author is not allow preview card' do
|
||||||
|
let(:account) { Fabricate(:user, settings: { link_preview: false }).account }
|
||||||
|
let(:status) { Fabricate(:status, text: 'http://example.com/html', account: account) }
|
||||||
|
|
||||||
|
it 'not create preview card' do
|
||||||
|
expect(status.preview_card).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a remote status' do
|
context 'with a remote status' do
|
||||||
|
let(:account) { Fabricate(:account, domain: 'example.com') }
|
||||||
let(:status) do
|
let(:status) do
|
||||||
Fabricate(:status, account: Fabricate(:account, domain: 'example.com'), text: <<-TEXT)
|
Fabricate(:status, account: account, text: <<-TEXT)
|
||||||
Habt ihr ein paar gute Links zu <a>foo</a>
|
Habt ihr ein paar gute Links zu <a>foo</a>
|
||||||
#<span class="tag"><a href="https://quitter.se/tag/wannacry" target="_blank" rel="tag noopener noreferrer" title="https://quitter.se/tag/wannacry">Wannacry</a></span> herumfliegen?
|
#<span class="tag"><a href="https://quitter.se/tag/wannacry" target="_blank" rel="tag noopener noreferrer" title="https://quitter.se/tag/wannacry">Wannacry</a></span> herumfliegen?
|
||||||
Ich will mal unter <br> <a href="http://example.com/not-found" target="_blank" rel="noopener noreferrer" title="http://example.com/not-found">http://example.com/not-found</a> was sammeln. !
|
Ich will mal unter <br> <a href="http://example.com/not-found" target="_blank" rel="noopener noreferrer" title="http://example.com/not-found">http://example.com/not-found</a> was sammeln. !
|
||||||
|
@ -272,6 +282,14 @@ RSpec.describe FetchLinkCardService, type: :service do
|
||||||
it 'ignores URLs to hashtags' do
|
it 'ignores URLs to hashtags' do
|
||||||
expect(a_request(:get, 'https://quitter.se/tag/wannacry')).to_not have_been_made
|
expect(a_request(:get, 'https://quitter.se/tag/wannacry')).to_not have_been_made
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with URL but author is not allow preview card' do
|
||||||
|
let(:account) { Fabricate(:account, domain: 'example.com', settings: { link_preview: false }) }
|
||||||
|
|
||||||
|
it 'not create link preview' do
|
||||||
|
expect(status.preview_card).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a remote status of reference' do
|
context 'with a remote status of reference' do
|
||||||
|
|
|
@ -23,11 +23,11 @@ RSpec.describe UpdateStatusService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when text changes' do
|
context 'when text changes' do
|
||||||
let!(:status) { Fabricate(:status, text: 'Foo') }
|
let(:status) { Fabricate(:status, text: 'Foo') }
|
||||||
let(:preview_card) { Fabricate(:preview_card) }
|
let(:preview_card) { Fabricate(:preview_card) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
status.preview_cards << preview_card
|
PreviewCardsStatus.create(status: status, preview_card: preview_card)
|
||||||
subject.call(status, status.account_id, text: 'Bar')
|
subject.call(status, status.account_id, text: 'Bar')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -45,11 +45,11 @@ RSpec.describe UpdateStatusService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when content warning changes' do
|
context 'when content warning changes' do
|
||||||
let!(:status) { Fabricate(:status, text: 'Foo', spoiler_text: '') }
|
let(:status) { Fabricate(:status, text: 'Foo', spoiler_text: '') }
|
||||||
let(:preview_card) { Fabricate(:preview_card) }
|
let(:preview_card) { Fabricate(:preview_card) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
status.preview_cards << preview_card
|
PreviewCardsStatus.create(status: status, preview_card: preview_card)
|
||||||
subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar')
|
subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue