Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - `README.md`: Our README.md files are completely different. Discarded upstream changes. - `app/javascript/core/admin.js`: Updating rails-ujs, no real conflict, but a comment to close to changed code. Various glitch-soc-only files have been updated to match those changes, though. - `package.json`: No real conflict, just an additional dependency in glitch-soc that was too close to something updated upstream. Took upstream's changes.
This commit is contained in:
commit
9abb227250
119 changed files with 987 additions and 344 deletions
|
@ -4,7 +4,7 @@ FROM ubuntu:18.04 as build-dep
|
||||||
SHELL ["bash", "-c"]
|
SHELL ["bash", "-c"]
|
||||||
|
|
||||||
# Install Node v12 (LTS)
|
# Install Node v12 (LTS)
|
||||||
ENV NODE_VER="12.14.0"
|
ENV NODE_VER="12.16.1"
|
||||||
RUN ARCH= && \
|
RUN ARCH= && \
|
||||||
dpkgArch="$(dpkg --print-architecture)" && \
|
dpkgArch="$(dpkg --print-architecture)" && \
|
||||||
case "${dpkgArch##*-}" in \
|
case "${dpkgArch##*-}" in \
|
||||||
|
|
8
Gemfile
8
Gemfile
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
ruby '>= 2.4.0', '< 3.0.0'
|
ruby '>= 2.5.0', '< 3.0.0'
|
||||||
|
|
||||||
gem 'pkg-config', '~> 1.4'
|
gem 'pkg-config', '~> 1.4'
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.7'
|
gem 'charlock_holmes', '~> 0.7.7'
|
||||||
gem 'iso-639'
|
gem 'iso-639'
|
||||||
gem 'chewy', '~> 5.1'
|
gem 'chewy', '~> 5.1'
|
||||||
gem 'cld3', '~> 3.2.6'
|
gem 'cld3', '~> 3.3.0'
|
||||||
gem 'devise', '~> 4.7'
|
gem 'devise', '~> 4.7'
|
||||||
gem 'devise-two-factor', '~> 3.1'
|
gem 'devise-two-factor', '~> 3.1'
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
||||||
gem 'rqrcode', '~> 1.1'
|
gem 'rqrcode', '~> 1.1'
|
||||||
gem 'ruby-progressbar', '~> 1.10'
|
gem 'ruby-progressbar', '~> 1.10'
|
||||||
gem 'sanitize', '~> 5.1'
|
gem 'sanitize', '~> 5.1'
|
||||||
gem 'sidekiq', '~> 5.2'
|
gem 'sidekiq', '~> 6.0'
|
||||||
gem 'sidekiq-scheduler', '~> 3.0'
|
gem 'sidekiq-scheduler', '~> 3.0'
|
||||||
gem 'sidekiq-unique-jobs', '~> 6.0'
|
gem 'sidekiq-unique-jobs', '~> 6.0'
|
||||||
gem 'sidekiq-bulk', '~>0.2.0'
|
gem 'sidekiq-bulk', '~>0.2.0'
|
||||||
|
@ -145,7 +145,7 @@ group :development do
|
||||||
gem 'brakeman', '~> 4.7', require: false
|
gem 'brakeman', '~> 4.7', require: false
|
||||||
gem 'bundler-audit', '~> 0.6', require: false
|
gem 'bundler-audit', '~> 0.6', require: false
|
||||||
|
|
||||||
gem 'capistrano', '~> 3.11'
|
gem 'capistrano', '~> 3.12'
|
||||||
gem 'capistrano-rails', '~> 1.4'
|
gem 'capistrano-rails', '~> 1.4'
|
||||||
gem 'capistrano-rbenv', '~> 2.1'
|
gem 'capistrano-rbenv', '~> 2.1'
|
||||||
gem 'capistrano-yarn', '~> 2.0'
|
gem 'capistrano-yarn', '~> 2.0'
|
||||||
|
|
56
Gemfile.lock
56
Gemfile.lock
|
@ -128,7 +128,7 @@ GEM
|
||||||
bundler (>= 1.2.0, < 3)
|
bundler (>= 1.2.0, < 3)
|
||||||
thor (~> 0.18)
|
thor (~> 0.18)
|
||||||
byebug (11.1.1)
|
byebug (11.1.1)
|
||||||
capistrano (3.11.2)
|
capistrano (3.12.1)
|
||||||
airbrussh (>= 1.0.0)
|
airbrussh (>= 1.0.0)
|
||||||
i18n
|
i18n
|
||||||
rake (>= 10.0.0)
|
rake (>= 10.0.0)
|
||||||
|
@ -160,7 +160,7 @@ GEM
|
||||||
elasticsearch (>= 2.0.0)
|
elasticsearch (>= 2.0.0)
|
||||||
elasticsearch-dsl
|
elasticsearch-dsl
|
||||||
chunky_png (1.3.11)
|
chunky_png (1.3.11)
|
||||||
cld3 (3.2.6)
|
cld3 (3.3.0)
|
||||||
ffi (>= 1.1.0, < 1.12.0)
|
ffi (>= 1.1.0, < 1.12.0)
|
||||||
climate_control (0.2.0)
|
climate_control (0.2.0)
|
||||||
cocaine (0.5.8)
|
cocaine (0.5.8)
|
||||||
|
@ -214,7 +214,7 @@ GEM
|
||||||
encryptor (3.0.0)
|
encryptor (3.0.0)
|
||||||
equatable (0.6.1)
|
equatable (0.6.1)
|
||||||
erubi (1.9.0)
|
erubi (1.9.0)
|
||||||
et-orbi (1.1.6)
|
et-orbi (1.2.3)
|
||||||
tzinfo
|
tzinfo
|
||||||
excon (0.71.0)
|
excon (0.71.0)
|
||||||
fabrication (2.21.0)
|
fabrication (2.21.0)
|
||||||
|
@ -241,8 +241,8 @@ GEM
|
||||||
fog-json (>= 1.0)
|
fog-json (>= 1.0)
|
||||||
ipaddress (>= 0.8)
|
ipaddress (>= 0.8)
|
||||||
formatador (0.2.5)
|
formatador (0.2.5)
|
||||||
fugit (1.1.6)
|
fugit (1.3.3)
|
||||||
et-orbi (~> 1.1, >= 1.1.6)
|
et-orbi (~> 1.1, >= 1.1.8)
|
||||||
raabro (~> 1.1)
|
raabro (~> 1.1)
|
||||||
fuubar (2.5.0)
|
fuubar (2.5.0)
|
||||||
rspec-core (~> 3.0)
|
rspec-core (~> 3.0)
|
||||||
|
@ -265,8 +265,8 @@ GEM
|
||||||
railties (>= 4.0.1)
|
railties (>= 4.0.1)
|
||||||
hamster (3.0.0)
|
hamster (3.0.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
hashdiff (1.0.0)
|
hashdiff (1.0.1)
|
||||||
hashie (3.6.0)
|
hashie (4.1.0)
|
||||||
highline (2.0.3)
|
highline (2.0.3)
|
||||||
hiredis (0.6.3)
|
hiredis (0.6.3)
|
||||||
hkdf (0.3.0)
|
hkdf (0.3.0)
|
||||||
|
@ -304,9 +304,9 @@ GEM
|
||||||
jmespath (1.4.0)
|
jmespath (1.4.0)
|
||||||
json (2.3.0)
|
json (2.3.0)
|
||||||
json-canonicalization (0.2.0)
|
json-canonicalization (0.2.0)
|
||||||
json-ld (3.1.0)
|
json-ld (3.1.1)
|
||||||
htmlentities (~> 4.3)
|
htmlentities (~> 4.3)
|
||||||
json-canonicalization (~> 0.1)
|
json-canonicalization (~> 0.2)
|
||||||
link_header (~> 0.0, >= 0.0.8)
|
link_header (~> 0.0, >= 0.0.8)
|
||||||
multi_json (~> 1.14)
|
multi_json (~> 1.14)
|
||||||
rack (~> 2.0)
|
rack (~> 2.0)
|
||||||
|
@ -384,8 +384,8 @@ GEM
|
||||||
sidekiq (>= 3.5)
|
sidekiq (>= 3.5)
|
||||||
statsd-ruby (~> 1.4, >= 1.4.0)
|
statsd-ruby (~> 1.4, >= 1.4.0)
|
||||||
oj (3.10.3)
|
oj (3.10.3)
|
||||||
omniauth (1.9.0)
|
omniauth (1.9.1)
|
||||||
hashie (>= 3.4.6, < 3.7.0)
|
hashie (>= 3.4.6)
|
||||||
rack (>= 1.6.2, < 3)
|
rack (>= 1.6.2, < 3)
|
||||||
omniauth-cas (1.1.1)
|
omniauth-cas (1.1.1)
|
||||||
addressable (~> 2.3)
|
addressable (~> 2.3)
|
||||||
|
@ -445,7 +445,7 @@ GEM
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rack-cors (1.1.1)
|
rack-cors (1.1.1)
|
||||||
rack (>= 2.0.0)
|
rack (>= 2.0.0)
|
||||||
rack-protection (2.0.7)
|
rack-protection (2.0.8.1)
|
||||||
rack
|
rack
|
||||||
rack-proxy (0.6.5)
|
rack-proxy (0.6.5)
|
||||||
rack
|
rack
|
||||||
|
@ -556,32 +556,34 @@ GEM
|
||||||
ruby-progressbar (1.10.1)
|
ruby-progressbar (1.10.1)
|
||||||
ruby-saml (1.9.0)
|
ruby-saml (1.9.0)
|
||||||
nokogiri (>= 1.5.10)
|
nokogiri (>= 1.5.10)
|
||||||
rufus-scheduler (3.5.2)
|
rufus-scheduler (3.6.0)
|
||||||
fugit (~> 1.1, >= 1.1.5)
|
fugit (~> 1.1, >= 1.1.6)
|
||||||
safe_yaml (1.0.5)
|
safe_yaml (1.0.5)
|
||||||
sanitize (5.1.0)
|
sanitize (5.1.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.8.0)
|
nokogiri (>= 1.8.0)
|
||||||
nokogumbo (~> 2.0)
|
nokogumbo (~> 2.0)
|
||||||
sidekiq (5.2.7)
|
sidekiq (6.0.4)
|
||||||
connection_pool (~> 2.2, >= 2.2.2)
|
connection_pool (>= 2.2.2)
|
||||||
rack (>= 1.5.0)
|
rack (>= 2.0.0)
|
||||||
rack-protection (>= 1.5.0)
|
rack-protection (>= 2.0.0)
|
||||||
redis (>= 3.3.5, < 5)
|
redis (>= 4.1.0)
|
||||||
sidekiq-bulk (0.2.0)
|
sidekiq-bulk (0.2.0)
|
||||||
sidekiq
|
sidekiq
|
||||||
sidekiq-scheduler (3.0.0)
|
sidekiq-scheduler (3.0.1)
|
||||||
|
e2mmap
|
||||||
redis (>= 3, < 5)
|
redis (>= 3, < 5)
|
||||||
rufus-scheduler (~> 3.2)
|
rufus-scheduler (~> 3.2)
|
||||||
sidekiq (>= 3)
|
sidekiq (>= 3)
|
||||||
|
thwait
|
||||||
tilt (>= 1.4.0)
|
tilt (>= 1.4.0)
|
||||||
sidekiq-unique-jobs (6.0.18)
|
sidekiq-unique-jobs (6.0.20)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.5)
|
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||||
sidekiq (>= 4.0, < 7.0)
|
sidekiq (>= 4.0, < 7.0)
|
||||||
thor (~> 0)
|
thor (~> 0)
|
||||||
simple-navigation (4.1.0)
|
simple-navigation (4.1.0)
|
||||||
activesupport (>= 2.3.2)
|
activesupport (>= 2.3.2)
|
||||||
simple_form (5.0.1)
|
simple_form (5.0.2)
|
||||||
actionpack (>= 5.0)
|
actionpack (>= 5.0)
|
||||||
activemodel (>= 5.0)
|
activemodel (>= 5.0)
|
||||||
simplecov (0.18.2)
|
simplecov (0.18.2)
|
||||||
|
@ -595,7 +597,7 @@ GEM
|
||||||
actionpack (>= 4.0)
|
actionpack (>= 4.0)
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
sshkit (1.20.0)
|
sshkit (1.21.0)
|
||||||
net-scp (>= 1.1.2)
|
net-scp (>= 1.1.2)
|
||||||
net-ssh (>= 2.8.0)
|
net-ssh (>= 2.8.0)
|
||||||
stackprof (0.2.15)
|
stackprof (0.2.15)
|
||||||
|
@ -640,7 +642,7 @@ GEM
|
||||||
uniform_notifier (1.13.0)
|
uniform_notifier (1.13.0)
|
||||||
warden (1.2.8)
|
warden (1.2.8)
|
||||||
rack (>= 2.0.6)
|
rack (>= 2.0.6)
|
||||||
webmock (3.8.0)
|
webmock (3.8.3)
|
||||||
addressable (>= 2.3.6)
|
addressable (>= 2.3.6)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff (>= 0.4.0, < 2.0.0)
|
hashdiff (>= 0.4.0, < 2.0.0)
|
||||||
|
@ -675,14 +677,14 @@ DEPENDENCIES
|
||||||
browser
|
browser
|
||||||
bullet (~> 6.1)
|
bullet (~> 6.1)
|
||||||
bundler-audit (~> 0.6)
|
bundler-audit (~> 0.6)
|
||||||
capistrano (~> 3.11)
|
capistrano (~> 3.12)
|
||||||
capistrano-rails (~> 1.4)
|
capistrano-rails (~> 1.4)
|
||||||
capistrano-rbenv (~> 2.1)
|
capistrano-rbenv (~> 2.1)
|
||||||
capistrano-yarn (~> 2.0)
|
capistrano-yarn (~> 2.0)
|
||||||
capybara (~> 3.31)
|
capybara (~> 3.31)
|
||||||
charlock_holmes (~> 0.7.7)
|
charlock_holmes (~> 0.7.7)
|
||||||
chewy (~> 5.1)
|
chewy (~> 5.1)
|
||||||
cld3 (~> 3.2.6)
|
cld3 (~> 3.3.0)
|
||||||
climate_control (~> 0.2)
|
climate_control (~> 0.2)
|
||||||
concurrent-ruby
|
concurrent-ruby
|
||||||
connection_pool
|
connection_pool
|
||||||
|
@ -767,7 +769,7 @@ DEPENDENCIES
|
||||||
rubocop-rails (~> 2.4)
|
rubocop-rails (~> 2.4)
|
||||||
ruby-progressbar (~> 1.10)
|
ruby-progressbar (~> 1.10)
|
||||||
sanitize (~> 5.1)
|
sanitize (~> 5.1)
|
||||||
sidekiq (~> 5.2)
|
sidekiq (~> 6.0)
|
||||||
sidekiq-bulk (~> 0.2.0)
|
sidekiq-bulk (~> 0.2.0)
|
||||||
sidekiq-scheduler (~> 3.0)
|
sidekiq-scheduler (~> 3.0)
|
||||||
sidekiq-unique-jobs (~> 6.0)
|
sidekiq-unique-jobs (~> 6.0)
|
||||||
|
|
|
@ -47,6 +47,11 @@ class StatusesIndex < Chewy::Index
|
||||||
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
crutch :bookmarks do |collection|
|
||||||
|
data = ::Bookmark.where(status_id: collection.map(&:id)).where(account: Account.local).pluck(:status_id, :account_id)
|
||||||
|
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
||||||
|
end
|
||||||
|
|
||||||
root date_detection: false do
|
root date_detection: false do
|
||||||
field :id, type: 'long'
|
field :id, type: 'long'
|
||||||
field :account_id, type: 'long'
|
field :account_id, type: 'long'
|
||||||
|
|
|
@ -6,12 +6,12 @@ module Admin
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize :email_domain_block, :index?
|
authorize :email_domain_block, :index?
|
||||||
@email_domain_blocks = EmailDomainBlock.page(params[:page])
|
@email_domain_blocks = EmailDomainBlock.where(parent_id: nil).includes(:children).order(id: :desc).page(params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
authorize :email_domain_block, :create?
|
authorize :email_domain_block, :create?
|
||||||
@email_domain_block = EmailDomainBlock.new
|
@email_domain_block = EmailDomainBlock.new(domain: params[:_domain])
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
@ -21,6 +21,28 @@ module Admin
|
||||||
|
|
||||||
if @email_domain_block.save
|
if @email_domain_block.save
|
||||||
log_action :create, @email_domain_block
|
log_action :create, @email_domain_block
|
||||||
|
|
||||||
|
if @email_domain_block.with_dns_records?
|
||||||
|
hostnames = []
|
||||||
|
ips = []
|
||||||
|
|
||||||
|
Resolv::DNS.open do |dns|
|
||||||
|
dns.timeouts = 1
|
||||||
|
|
||||||
|
hostnames = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }
|
||||||
|
|
||||||
|
([@email_domain_block.domain] + hostnames).uniq.each do |hostname|
|
||||||
|
ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::A).to_a.map { |e| e.address.to_s })
|
||||||
|
ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::AAAA).to_a.map { |e| e.address.to_s })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
(hostnames + ips).each do |hostname|
|
||||||
|
another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: @email_domain_block)
|
||||||
|
log_action :create, another_email_domain_block if another_email_domain_block.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg')
|
redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg')
|
||||||
else
|
else
|
||||||
render :new
|
render :new
|
||||||
|
@ -41,7 +63,7 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_params
|
def resource_params
|
||||||
params.require(:email_domain_block).permit(:domain)
|
params.require(:email_domain_block).permit(:domain, :with_dns_records)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ module Admin
|
||||||
def index
|
def index
|
||||||
authorize :account_warning_preset, :index?
|
authorize :account_warning_preset, :index?
|
||||||
|
|
||||||
@warning_presets = AccountWarningPreset.all
|
@warning_presets = AccountWarningPreset.alphabetic
|
||||||
@warning_preset = AccountWarningPreset.new
|
@warning_preset = AccountWarningPreset.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ module Admin
|
||||||
if @warning_preset.save
|
if @warning_preset.save
|
||||||
redirect_to admin_warning_presets_path
|
redirect_to admin_warning_presets_path
|
||||||
else
|
else
|
||||||
@warning_presets = AccountWarningPreset.all
|
@warning_presets = AccountWarningPreset.alphabetic
|
||||||
render :index
|
render :index
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -52,7 +52,7 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def warning_preset_params
|
def warning_preset_params
|
||||||
params.require(:account_warning_preset).permit(:text)
|
params.require(:account_warning_preset).permit(:title, :text)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def hide_results?
|
def hide_results?
|
||||||
(@account.user_hides_network? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
|
(@account.hides_followers? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_accounts
|
def default_accounts
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def hide_results?
|
def hide_results?
|
||||||
(@account.user_hides_network? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
|
(@account.hides_following? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_accounts
|
def default_accounts
|
||||||
|
|
|
@ -3,25 +3,42 @@
|
||||||
class Api::V1::MediaController < Api::BaseController
|
class Api::V1::MediaController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:media' }
|
before_action -> { doorkeeper_authorize! :write, :'write:media' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
before_action :set_media_attachment, except: [:create]
|
||||||
|
before_action :check_processing, except: [:create]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@media = current_account.media_attachments.create!(media_params)
|
@media_attachment = current_account.media_attachments.create!(media_attachment_params)
|
||||||
render json: @media, serializer: REST::MediaAttachmentSerializer
|
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer
|
||||||
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
|
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
|
||||||
render json: file_type_error, status: 422
|
render json: file_type_error, status: 422
|
||||||
rescue Paperclip::Error
|
rescue Paperclip::Error
|
||||||
render json: processing_error, status: 500
|
render json: processing_error, status: 500
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment
|
||||||
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@media = current_account.media_attachments.where(status_id: nil).find(params[:id])
|
@media_attachment.update!(media_attachment_params)
|
||||||
@media.update!(media_params)
|
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment
|
||||||
render json: @media, serializer: REST::MediaAttachmentSerializer
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def media_params
|
def status_code_for_media_attachment
|
||||||
|
@media_attachment.not_processed? ? 206 : 200
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_media_attachment
|
||||||
|
@media_attachment = current_account.media_attachments.unattached.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_processing
|
||||||
|
render json: processing_error, status: 422 if @media_attachment.processing_failed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def media_attachment_params
|
||||||
params.permit(:file, :description, :focus)
|
params.permit(:file, :description, :focus)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
12
app/controllers/api/v2/media_controller.rb
Normal file
12
app/controllers/api/v2/media_controller.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V2::MediaController < Api::V1::MediaController
|
||||||
|
def create
|
||||||
|
@media_attachment = current_account.media_attachments.create!({ delay_processing: true }.merge(media_attachment_params))
|
||||||
|
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: 202
|
||||||
|
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
|
||||||
|
render json: file_type_error, status: 422
|
||||||
|
rescue Paperclip::Error
|
||||||
|
render json: processing_error, status: 500
|
||||||
|
end
|
||||||
|
end
|
|
@ -29,7 +29,8 @@ class FollowerAccountsController < ApplicationController
|
||||||
render json: collection_presenter,
|
render json: collection_presenter,
|
||||||
serializer: ActivityPub::CollectionSerializer,
|
serializer: ActivityPub::CollectionSerializer,
|
||||||
adapter: ActivityPub::Adapter,
|
adapter: ActivityPub::Adapter,
|
||||||
content_type: 'application/activity+json'
|
content_type: 'application/activity+json',
|
||||||
|
fields: restrict_fields_to
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -72,4 +73,12 @@ class FollowerAccountsController < ApplicationController
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def restrict_fields_to
|
||||||
|
if page_requested? || !@account.user_hides_network?
|
||||||
|
# Return all fields
|
||||||
|
else
|
||||||
|
%i(id type totalItems)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,7 +29,8 @@ class FollowingAccountsController < ApplicationController
|
||||||
render json: collection_presenter,
|
render json: collection_presenter,
|
||||||
serializer: ActivityPub::CollectionSerializer,
|
serializer: ActivityPub::CollectionSerializer,
|
||||||
adapter: ActivityPub::Adapter,
|
adapter: ActivityPub::Adapter,
|
||||||
content_type: 'application/activity+json'
|
content_type: 'application/activity+json',
|
||||||
|
fields: restrict_fields_to
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -72,4 +73,12 @@ class FollowingAccountsController < ApplicationController
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def restrict_fields_to
|
||||||
|
if page_requested? || !@account.user_hides_network?
|
||||||
|
# Return all fields
|
||||||
|
else
|
||||||
|
%i(id type totalItems)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// This file will be loaded on admin pages, regardless of theme.
|
// This file will be loaded on admin pages, regardless of theme.
|
||||||
|
|
||||||
import { delegate } from 'rails-ujs';
|
import { delegate } from '@rails/ujs';
|
||||||
import ready from '../mastodon/ready';
|
import ready from '../mastodon/ready';
|
||||||
|
|
||||||
const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]';
|
const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]';
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import createHistory from 'history/createBrowserHistory';
|
import createHistory from 'history/createBrowserHistory';
|
||||||
import ready from '../mastodon/ready';
|
import ready from '../mastodon/ready';
|
||||||
|
|
||||||
const { delegate } = require('rails-ujs');
|
const { delegate } = require('@rails/ujs');
|
||||||
const { length } = require('stringz');
|
const { length } = require('stringz');
|
||||||
|
|
||||||
delegate(document, '.webapp-btn', 'click', ({ target, button }) => {
|
delegate(document, '.webapp-btn', 'click', ({ target, button }) => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// This file will be loaded on settings pages, regardless of theme.
|
// This file will be loaded on settings pages, regardless of theme.
|
||||||
|
|
||||||
import escapeTextContentForBrowser from 'escape-html';
|
import escapeTextContentForBrowser from 'escape-html';
|
||||||
const { delegate } = require('rails-ujs');
|
const { delegate } = require('@rails/ujs');
|
||||||
import emojify from '../mastodon/features/emoji/emoji';
|
import emojify from '../mastodon/features/emoji/emoji';
|
||||||
|
|
||||||
delegate(document, '#account_display_name', 'input', ({ target }) => {
|
delegate(document, '#account_display_name', 'input', ({ target }) => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { start } from 'rails-ujs';
|
import { start } from '@rails/ujs';
|
||||||
|
|
||||||
start();
|
start();
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import loadKeyboardExtensions from 'flavours/glitch/util/load_keyboard_extension
|
||||||
function main() {
|
function main() {
|
||||||
const IntlMessageFormat = require('intl-messageformat').default;
|
const IntlMessageFormat = require('intl-messageformat').default;
|
||||||
const { timeAgoString } = require('flavours/glitch/components/relative_timestamp');
|
const { timeAgoString } = require('flavours/glitch/components/relative_timestamp');
|
||||||
const { delegate } = require('rails-ujs');
|
const { delegate } = require('@rails/ujs');
|
||||||
const emojify = require('flavours/glitch/util/emoji').default;
|
const emojify = require('flavours/glitch/util/emoji').default;
|
||||||
const { getLocale } = require('locales');
|
const { getLocale } = require('locales');
|
||||||
const { messages } = getLocale();
|
const { messages } = getLocale();
|
||||||
|
|
|
@ -3,7 +3,7 @@ import ready from 'flavours/glitch/util/ready';
|
||||||
import loadKeyboardExtensions from 'flavours/glitch/util/load_keyboard_extensions';
|
import loadKeyboardExtensions from 'flavours/glitch/util/load_keyboard_extensions';
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
const { delegate } = require('rails-ujs');
|
const { delegate } = require('@rails/ujs');
|
||||||
|
|
||||||
delegate(document, '.sidebar__toggle__icon', 'click', () => {
|
delegate(document, '.sidebar__toggle__icon', 'click', () => {
|
||||||
const target = document.querySelector('.sidebar ul');
|
const target = document.querySelector('.sidebar ul');
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Rails from 'rails-ujs';
|
import Rails from '@rails/ujs';
|
||||||
import { signOutLink } from 'flavours/glitch/util/backend_links';
|
import { signOutLink } from 'flavours/glitch/util/backend_links';
|
||||||
|
|
||||||
export const logOut = () => {
|
export const logOut = () => {
|
||||||
|
|
|
@ -230,12 +230,31 @@ export function uploadCompose(files) {
|
||||||
// Account for disparity in size of original image and resized data
|
// Account for disparity in size of original image and resized data
|
||||||
total += file.size - f.size;
|
total += file.size - f.size;
|
||||||
|
|
||||||
return api(getState).post('/api/v1/media', data, {
|
return api(getState).post('/api/v2/media', data, {
|
||||||
onUploadProgress: function({ loaded }){
|
onUploadProgress: function({ loaded }){
|
||||||
progress[i] = loaded;
|
progress[i] = loaded;
|
||||||
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
||||||
},
|
},
|
||||||
}).then(({ data }) => dispatch(uploadComposeSuccess(data, f)));
|
}).then(({ status, data }) => {
|
||||||
|
// If server-side processing of the media attachment has not completed yet,
|
||||||
|
// poll the server until it is, before showing the media attachment as uploaded
|
||||||
|
|
||||||
|
if (status === 200) {
|
||||||
|
dispatch(uploadComposeSuccess(data, f));
|
||||||
|
} else if (status === 202) {
|
||||||
|
const poll = () => {
|
||||||
|
api(getState).get(`/api/v1/media/${data.id}`).then(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
dispatch(uploadComposeSuccess(response.data, f));
|
||||||
|
} else if (response.status === 206) {
|
||||||
|
setTimeout(() => poll(), 1000);
|
||||||
|
}
|
||||||
|
}).catch(error => dispatch(uploadComposeFail(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
poll();
|
||||||
|
}
|
||||||
|
});
|
||||||
}).catch(error => dispatch(uploadComposeFail(error)));
|
}).catch(error => dispatch(uploadComposeFail(error)));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Rails from 'rails-ujs';
|
import Rails from '@rails/ujs';
|
||||||
|
|
||||||
export function start() {
|
export function start() {
|
||||||
require('font-awesome/css/font-awesome.css');
|
require('font-awesome/css/font-awesome.css');
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @injectIntl
|
export default @injectIntl
|
||||||
|
|
|
@ -82,15 +82,19 @@ export default class ScrollableList extends PureComponent {
|
||||||
lastScrollWasSynthetic = false;
|
lastScrollWasSynthetic = false;
|
||||||
scrollToTopOnMouseIdle = false;
|
scrollToTopOnMouseIdle = false;
|
||||||
|
|
||||||
|
_getScrollingElement = () => {
|
||||||
|
if (this.props.bindToDocument) {
|
||||||
|
return (document.scrollingElement || document.body);
|
||||||
|
} else {
|
||||||
|
return this.node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setScrollTop = newScrollTop => {
|
setScrollTop = newScrollTop => {
|
||||||
if (this.getScrollTop() !== newScrollTop) {
|
if (this.getScrollTop() !== newScrollTop) {
|
||||||
this.lastScrollWasSynthetic = true;
|
this.lastScrollWasSynthetic = true;
|
||||||
|
|
||||||
if (this.props.bindToDocument) {
|
this._getScrollingElement().scrollTop = newScrollTop;
|
||||||
document.scrollingElement.scrollTop = newScrollTop;
|
|
||||||
} else {
|
|
||||||
this.node.scrollTop = newScrollTop;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -151,15 +155,15 @@ export default class ScrollableList extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
getScrollTop = () => {
|
getScrollTop = () => {
|
||||||
return this.props.bindToDocument ? document.scrollingElement.scrollTop : this.node.scrollTop;
|
return this._getScrollingElement().scrollTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
getScrollHeight = () => {
|
getScrollHeight = () => {
|
||||||
return this.props.bindToDocument ? document.scrollingElement.scrollHeight : this.node.scrollHeight;
|
return this._getScrollingElement().scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
getClientHeight = () => {
|
getClientHeight = () => {
|
||||||
return this.props.bindToDocument ? document.scrollingElement.clientHeight : this.node.clientHeight;
|
return this._getScrollingElement().clientHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateScrollBottom = (snapshot) => {
|
updateScrollBottom = (snapshot) => {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import Domain from '../components/domain';
|
||||||
import { openModal } from '../actions/modal';
|
import { openModal } from '../actions/modal';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Block entire domain' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
|
|
|
@ -39,7 +39,7 @@ const messages = defineMessages({
|
||||||
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
|
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
|
||||||
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
|
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
|
||||||
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
||||||
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
|
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Blocked domains' },
|
||||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||||
endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },
|
endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },
|
||||||
unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' },
|
unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' },
|
||||||
|
@ -142,7 +142,7 @@ class Header extends ImmutablePureComponent {
|
||||||
if (me !== account.get('id') && account.getIn(['relationship', 'muting'])) {
|
if (me !== account.get('id') && account.getIn(['relationship', 'muting'])) {
|
||||||
info.push(<span key='muted' className='relationship-tag'><FormattedMessage id='account.muted' defaultMessage='Muted' /></span>);
|
info.push(<span key='muted' className='relationship-tag'><FormattedMessage id='account.muted' defaultMessage='Muted' /></span>);
|
||||||
} else if (me !== account.get('id') && account.getIn(['relationship', 'domain_blocking'])) {
|
} else if (me !== account.get('id') && account.getIn(['relationship', 'domain_blocking'])) {
|
||||||
info.push(<span key='domain_blocked' className='relationship-tag'><FormattedMessage id='account.domain_blocked' defaultMessage='Domain hidden' /></span>);
|
info.push(<span key='domain_blocked' className='relationship-tag'><FormattedMessage id='account.domain_blocked' defaultMessage='Domain blocked' /></span>);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me !== account.get('id')) {
|
if (me !== account.get('id')) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ const messages = defineMessages({
|
||||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||||
filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
|
filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
|
||||||
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
||||||
|
bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' },
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @injectIntl
|
export default @injectIntl
|
||||||
|
@ -42,6 +43,7 @@ class ActionBar extends React.PureComponent {
|
||||||
menu.push(null);
|
menu.push(null);
|
||||||
menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
|
menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
|
||||||
menu.push({ text: intl.formatMessage(messages.favourites), to: '/favourites' });
|
menu.push({ text: intl.formatMessage(messages.favourites), to: '/favourites' });
|
||||||
|
menu.push({ text: intl.formatMessage(messages.bookmarks), to: '/bookmarks' });
|
||||||
menu.push({ text: intl.formatMessage(messages.lists), to: '/lists' });
|
menu.push({ text: intl.formatMessage(messages.lists), to: '/lists' });
|
||||||
menu.push(null);
|
menu.push(null);
|
||||||
menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });
|
menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });
|
||||||
|
|
|
@ -13,8 +13,8 @@ import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_bloc
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
import ScrollableList from '../../components/scrollable_list';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' },
|
heading: { id: 'column.domain_blocks', defaultMessage: 'Blocked domains' },
|
||||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
@ -55,7 +55,7 @@ class Blocks extends ImmutablePureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no hidden domains yet.' />;
|
const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no blocked domains yet.' />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column bindToDocument={!multiColumn} icon='minus-circle' heading={intl.formatMessage(messages.heading)}>
|
<Column bindToDocument={!multiColumn} icon='minus-circle' heading={intl.formatMessage(messages.heading)}>
|
||||||
|
|
|
@ -389,7 +389,7 @@ class Announcements extends ImmutablePureComponent {
|
||||||
_markAnnouncementAsRead () {
|
_markAnnouncementAsRead () {
|
||||||
const { dismissAnnouncement, announcements } = this.props;
|
const { dismissAnnouncement, announcements } = this.props;
|
||||||
const { index } = this.state;
|
const { index } = this.state;
|
||||||
const announcement = announcements.get(index);
|
const announcement = announcements.get(index) || announcements.get(index - 1);
|
||||||
if (!announcement.get('read')) dismissAnnouncement(announcement.get('id'));
|
if (!announcement.get('read')) dismissAnnouncement(announcement.get('id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ class Announcements extends ImmutablePureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { announcements, intl } = this.props;
|
const { announcements, intl } = this.props;
|
||||||
const { index } = this.state;
|
const index = this.state.index < announcements.size ? this.state.index : announcements.size - 1;
|
||||||
|
|
||||||
if (announcements.isEmpty()) {
|
if (announcements.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -166,7 +166,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
||||||
reblogIcon = 'lock';
|
reblogIcon = 'lock';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.get('visibility') === 'private') {
|
if (['private', 'direct'].includes(status.get('visibility'))) {
|
||||||
reblogLink = <Icon id={reblogIcon} />;
|
reblogLink = <Icon id={reblogIcon} />;
|
||||||
} else if (this.context.router) {
|
} else if (this.context.router) {
|
||||||
reblogLink = (
|
reblogLink = (
|
||||||
|
|
|
@ -523,7 +523,7 @@
|
||||||
{
|
{
|
||||||
"descriptors": [
|
"descriptors": [
|
||||||
{
|
{
|
||||||
"defaultMessage": "Hide entire domain",
|
"defaultMessage": "Block entire domain",
|
||||||
"id": "confirmations.domain_block.confirm"
|
"id": "confirmations.domain_block.confirm"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -737,7 +737,7 @@
|
||||||
"id": "navigation_bar.blocks"
|
"id": "navigation_bar.blocks"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"defaultMessage": "Hidden domains",
|
"defaultMessage": "Blocked domains",
|
||||||
"id": "navigation_bar.domain_blocks"
|
"id": "navigation_bar.domain_blocks"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -773,7 +773,7 @@
|
||||||
"id": "account.muted"
|
"id": "account.muted"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"defaultMessage": "Domain hidden",
|
"defaultMessage": "Domain blocked",
|
||||||
"id": "account.domain_blocked"
|
"id": "account.domain_blocked"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -917,6 +917,10 @@
|
||||||
{
|
{
|
||||||
"defaultMessage": "Logout",
|
"defaultMessage": "Logout",
|
||||||
"id": "navigation_bar.logout"
|
"id": "navigation_bar.logout"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"defaultMessage": "Bookmarks",
|
||||||
|
"id": "navigation_bar.bookmarks"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"path": "app/javascript/mastodon/features/compose/components/action_bar.json"
|
"path": "app/javascript/mastodon/features/compose/components/action_bar.json"
|
||||||
|
@ -1466,7 +1470,7 @@
|
||||||
{
|
{
|
||||||
"descriptors": [
|
"descriptors": [
|
||||||
{
|
{
|
||||||
"defaultMessage": "Hidden domains",
|
"defaultMessage": "Blocked domains",
|
||||||
"id": "column.domain_blocks"
|
"id": "column.domain_blocks"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1474,7 +1478,7 @@
|
||||||
"id": "account.unblock_domain"
|
"id": "account.unblock_domain"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"defaultMessage": "There are no hidden domains yet.",
|
"defaultMessage": "There are no blocked domains yet.",
|
||||||
"id": "empty_column.domain_blocks"
|
"id": "empty_column.domain_blocks"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -2957,4 +2961,4 @@
|
||||||
],
|
],
|
||||||
"path": "app/javascript/mastodon/features/video/index.json"
|
"path": "app/javascript/mastodon/features/video/index.json"
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -7,7 +7,7 @@
|
||||||
"account.blocked": "Blocked",
|
"account.blocked": "Blocked",
|
||||||
"account.cancel_follow_request": "Cancel follow request",
|
"account.cancel_follow_request": "Cancel follow request",
|
||||||
"account.direct": "Direct message @{name}",
|
"account.direct": "Direct message @{name}",
|
||||||
"account.domain_blocked": "Domain hidden",
|
"account.domain_blocked": "Domain blocked",
|
||||||
"account.edit_profile": "Edit profile",
|
"account.edit_profile": "Edit profile",
|
||||||
"account.endorse": "Feature on profile",
|
"account.endorse": "Feature on profile",
|
||||||
"account.follow": "Follow",
|
"account.follow": "Follow",
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
"column.community": "Local timeline",
|
"column.community": "Local timeline",
|
||||||
"column.direct": "Direct messages",
|
"column.direct": "Direct messages",
|
||||||
"column.directory": "Browse profiles",
|
"column.directory": "Browse profiles",
|
||||||
"column.domain_blocks": "Hidden domains",
|
"column.domain_blocks": "Blocked domains",
|
||||||
"column.favourites": "Favourites",
|
"column.favourites": "Favourites",
|
||||||
"column.follow_requests": "Follow requests",
|
"column.follow_requests": "Follow requests",
|
||||||
"column.home": "Home",
|
"column.home": "Home",
|
||||||
|
@ -107,7 +107,7 @@
|
||||||
"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": "Delete",
|
"confirmations.delete_list.confirm": "Delete",
|
||||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||||
"confirmations.domain_block.confirm": "Hide entire domain",
|
"confirmations.domain_block.confirm": "Block entire domain",
|
||||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
|
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
|
||||||
"confirmations.logout.confirm": "Log out",
|
"confirmations.logout.confirm": "Log out",
|
||||||
"confirmations.logout.message": "Are you sure you want to log out?",
|
"confirmations.logout.message": "Are you sure you want to log out?",
|
||||||
|
@ -150,7 +150,7 @@
|
||||||
"empty_column.bookmarked_statuses": "You don't have any bookmarked toots yet. When you bookmark one, it will show up here.",
|
"empty_column.bookmarked_statuses": "You don't have any bookmarked toots yet. When you bookmark one, it will show up here.",
|
||||||
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
||||||
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
||||||
"empty_column.domain_blocks": "There are no hidden domains yet.",
|
"empty_column.domain_blocks": "There are no blocked domains yet.",
|
||||||
"empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.",
|
"empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.",
|
||||||
"empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.",
|
"empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.",
|
||||||
"empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
|
"empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
|
||||||
|
@ -269,7 +269,7 @@
|
||||||
"navigation_bar.compose": "Compose new toot",
|
"navigation_bar.compose": "Compose new toot",
|
||||||
"navigation_bar.direct": "Direct messages",
|
"navigation_bar.direct": "Direct messages",
|
||||||
"navigation_bar.discover": "Discover",
|
"navigation_bar.discover": "Discover",
|
||||||
"navigation_bar.domain_blocks": "Hidden domains",
|
"navigation_bar.domain_blocks": "Blocked domains",
|
||||||
"navigation_bar.edit_profile": "Edit profile",
|
"navigation_bar.edit_profile": "Edit profile",
|
||||||
"navigation_bar.favourites": "Favourites",
|
"navigation_bar.favourites": "Favourites",
|
||||||
"navigation_bar.filters": "Muted words",
|
"navigation_bar.filters": "Muted words",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Rails from 'rails-ujs';
|
import Rails from '@rails/ujs';
|
||||||
|
|
||||||
export const logOut = () => {
|
export const logOut = () => {
|
||||||
const form = document.createElement('form');
|
const form = document.createElement('form');
|
||||||
|
|
|
@ -8,7 +8,7 @@ start();
|
||||||
function main() {
|
function main() {
|
||||||
const IntlMessageFormat = require('intl-messageformat').default;
|
const IntlMessageFormat = require('intl-messageformat').default;
|
||||||
const { timeAgoString } = require('../mastodon/components/relative_timestamp');
|
const { timeAgoString } = require('../mastodon/components/relative_timestamp');
|
||||||
const { delegate } = require('rails-ujs');
|
const { delegate } = require('@rails/ujs');
|
||||||
const emojify = require('../mastodon/features/emoji/emoji').default;
|
const emojify = require('../mastodon/features/emoji/emoji').default;
|
||||||
const { getLocale } = require('../mastodon/locales');
|
const { getLocale } = require('../mastodon/locales');
|
||||||
const { messages } = getLocale();
|
const { messages } = getLocale();
|
||||||
|
|
|
@ -52,8 +52,10 @@ class LanguageDetector
|
||||||
|
|
||||||
def detect_language_code(text)
|
def detect_language_code(text)
|
||||||
return if unreliable_input?(text)
|
return if unreliable_input?(text)
|
||||||
|
|
||||||
result = @identifier.find_language(text)
|
result = @identifier.find_language(text)
|
||||||
iso6391(result.language.to_s).to_sym if result.reliable?
|
|
||||||
|
iso6391(result.language.to_s).to_sym if result&.reliable?
|
||||||
end
|
end
|
||||||
|
|
||||||
def iso6391(bcp47)
|
def iso6391(bcp47)
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
# silenced_at :datetime
|
# silenced_at :datetime
|
||||||
# suspended_at :datetime
|
# suspended_at :datetime
|
||||||
# trust_level :integer
|
# trust_level :integer
|
||||||
|
# hide_collections :boolean
|
||||||
#
|
#
|
||||||
|
|
||||||
class Account < ApplicationRecord
|
class Account < ApplicationRecord
|
||||||
|
@ -325,6 +326,14 @@ class Account < ApplicationRecord
|
||||||
save!
|
save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def hides_followers?
|
||||||
|
hide_collections? || user_hides_network?
|
||||||
|
end
|
||||||
|
|
||||||
|
def hides_following?
|
||||||
|
hide_collections? || user_hides_network?
|
||||||
|
end
|
||||||
|
|
||||||
def object_type
|
def object_type
|
||||||
:person
|
:person
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,8 +8,11 @@
|
||||||
# text :text default(""), not null
|
# text :text default(""), not null
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
|
# title :string default(""), not null
|
||||||
#
|
#
|
||||||
|
|
||||||
class AccountWarningPreset < ApplicationRecord
|
class AccountWarningPreset < ApplicationRecord
|
||||||
validates :text, presence: true
|
validates :text, presence: true
|
||||||
|
|
||||||
|
scope :alphabetic, -> { order(title: :asc, text: :asc) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -62,8 +62,6 @@ class Admin::AccountAction
|
||||||
|
|
||||||
def process_action!
|
def process_action!
|
||||||
case type
|
case type
|
||||||
when 'none'
|
|
||||||
handle_resolve!
|
|
||||||
when 'disable'
|
when 'disable'
|
||||||
handle_disable!
|
handle_disable!
|
||||||
when 'silence'
|
when 'silence'
|
||||||
|
@ -105,16 +103,6 @@ class Admin::AccountAction
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_resolve!
|
|
||||||
if with_report? && report.account_id == -99 && target_account.trust_level == Account::TRUST_LEVELS[:untrusted]
|
|
||||||
# This is an automated report and it is being dismissed, so it's
|
|
||||||
# a false positive, in which case update the account's trust level
|
|
||||||
# to prevent further spam checks
|
|
||||||
|
|
||||||
target_account.update(trust_level: Account::TRUST_LEVELS[:trusted])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_disable!
|
def handle_disable!
|
||||||
authorize(target_account.user, :disable?)
|
authorize(target_account.user, :disable?)
|
||||||
log_action(:disable, target_account.user)
|
log_action(:disable, target_account.user)
|
||||||
|
|
|
@ -74,7 +74,7 @@ module Attachmentable
|
||||||
self.class.attachment_definitions.each_key do |attachment_name|
|
self.class.attachment_definitions.each_key do |attachment_name|
|
||||||
attachment = send(attachment_name)
|
attachment = send(attachment_name)
|
||||||
|
|
||||||
next if attachment.blank? || attachment.queued_for_write[:original].blank?
|
next if attachment.blank? || attachment.queued_for_write[:original].blank? || attachment.options[:preserve_files]
|
||||||
|
|
||||||
attachment.instance_write :file_name, SecureRandom.hex(8) + File.extname(attachment.instance_read(:file_name))
|
attachment.instance_write :file_name, SecureRandom.hex(8) + File.extname(attachment.instance_read(:file_name))
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,13 +7,27 @@
|
||||||
# domain :string default(""), not null
|
# domain :string default(""), not null
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
|
# parent_id :bigint(8)
|
||||||
#
|
#
|
||||||
|
|
||||||
class EmailDomainBlock < ApplicationRecord
|
class EmailDomainBlock < ApplicationRecord
|
||||||
include DomainNormalizable
|
include DomainNormalizable
|
||||||
|
|
||||||
|
belongs_to :parent, class_name: 'EmailDomainBlock', optional: true
|
||||||
|
has_many :children, class_name: 'EmailDomainBlock', foreign_key: :parent_id, inverse_of: :parent, dependent: :destroy
|
||||||
|
|
||||||
validates :domain, presence: true, uniqueness: true, domain: true
|
validates :domain, presence: true, uniqueness: true, domain: true
|
||||||
|
|
||||||
|
def with_dns_records=(val)
|
||||||
|
@with_dns_records = ActiveModel::Type::Boolean.new.cast(val)
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_dns_records?
|
||||||
|
@with_dns_records
|
||||||
|
end
|
||||||
|
|
||||||
|
alias with_dns_records with_dns_records?
|
||||||
|
|
||||||
def self.block?(email)
|
def self.block?(email)
|
||||||
_, domain = email.split('@', 2)
|
_, domain = email.split('@', 2)
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,14 @@
|
||||||
# description :text
|
# description :text
|
||||||
# scheduled_status_id :bigint(8)
|
# scheduled_status_id :bigint(8)
|
||||||
# blurhash :string
|
# blurhash :string
|
||||||
|
# processing :integer
|
||||||
#
|
#
|
||||||
|
|
||||||
class MediaAttachment < ApplicationRecord
|
class MediaAttachment < ApplicationRecord
|
||||||
self.inheritance_column = nil
|
self.inheritance_column = nil
|
||||||
|
|
||||||
enum type: [:image, :gifv, :video, :unknown, :audio]
|
enum type: [:image, :gifv, :video, :unknown, :audio]
|
||||||
|
enum processing: [:queued, :in_progress, :complete, :failed], _prefix: true
|
||||||
|
|
||||||
MAX_DESCRIPTION_LENGTH = 1_500
|
MAX_DESCRIPTION_LENGTH = 1_500
|
||||||
|
|
||||||
|
@ -55,47 +57,6 @@ class MediaAttachment < ApplicationRecord
|
||||||
},
|
},
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
VIDEO_STYLES = {
|
|
||||||
small: {
|
|
||||||
convert_options: {
|
|
||||||
output: {
|
|
||||||
'loglevel' => 'fatal',
|
|
||||||
vf: 'scale=\'min(400\, iw):min(400\, ih)\':force_original_aspect_ratio=decrease',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
format: 'png',
|
|
||||||
time: 0,
|
|
||||||
file_geometry_parser: FastGeometryParser,
|
|
||||||
blurhash: BLURHASH_OPTIONS,
|
|
||||||
},
|
|
||||||
|
|
||||||
original: {
|
|
||||||
keep_same_format: true,
|
|
||||||
convert_options: {
|
|
||||||
output: {
|
|
||||||
'loglevel' => 'fatal',
|
|
||||||
'map_metadata' => '-1',
|
|
||||||
'c:v' => 'copy',
|
|
||||||
'c:a' => 'copy',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}.freeze
|
|
||||||
|
|
||||||
AUDIO_STYLES = {
|
|
||||||
original: {
|
|
||||||
format: 'mp3',
|
|
||||||
content_type: 'audio/mpeg',
|
|
||||||
convert_options: {
|
|
||||||
output: {
|
|
||||||
'loglevel' => 'fatal',
|
|
||||||
'map_metadata' => '-1',
|
|
||||||
'q:a' => 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}.freeze
|
|
||||||
|
|
||||||
VIDEO_FORMAT = {
|
VIDEO_FORMAT = {
|
||||||
format: 'mp4',
|
format: 'mp4',
|
||||||
content_type: 'video/mp4',
|
content_type: 'video/mp4',
|
||||||
|
@ -116,6 +77,54 @@ class MediaAttachment < ApplicationRecord
|
||||||
},
|
},
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
VIDEO_PASSTHROUGH_OPTIONS = {
|
||||||
|
video_codecs: ['h264'],
|
||||||
|
audio_codecs: ['aac', nil],
|
||||||
|
colorspaces: ['yuv420p'],
|
||||||
|
options: {
|
||||||
|
format: 'mp4',
|
||||||
|
convert_options: {
|
||||||
|
output: {
|
||||||
|
'loglevel' => 'fatal',
|
||||||
|
'map_metadata' => '-1',
|
||||||
|
'c:v' => 'copy',
|
||||||
|
'c:a' => 'copy',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
VIDEO_STYLES = {
|
||||||
|
small: {
|
||||||
|
convert_options: {
|
||||||
|
output: {
|
||||||
|
'loglevel' => 'fatal',
|
||||||
|
vf: 'scale=\'min(400\, iw):min(400\, ih)\':force_original_aspect_ratio=decrease',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
format: 'png',
|
||||||
|
time: 0,
|
||||||
|
file_geometry_parser: FastGeometryParser,
|
||||||
|
blurhash: BLURHASH_OPTIONS,
|
||||||
|
},
|
||||||
|
|
||||||
|
original: VIDEO_FORMAT.merge(passthrough_options: VIDEO_PASSTHROUGH_OPTIONS),
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
AUDIO_STYLES = {
|
||||||
|
original: {
|
||||||
|
format: 'mp3',
|
||||||
|
content_type: 'audio/mpeg',
|
||||||
|
convert_options: {
|
||||||
|
output: {
|
||||||
|
'loglevel' => 'fatal',
|
||||||
|
'map_metadata' => '-1',
|
||||||
|
'q:a' => 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}.freeze
|
||||||
|
|
||||||
VIDEO_CONVERTED_STYLES = {
|
VIDEO_CONVERTED_STYLES = {
|
||||||
small: VIDEO_STYLES[:small],
|
small: VIDEO_STYLES[:small],
|
||||||
original: VIDEO_FORMAT,
|
original: VIDEO_FORMAT,
|
||||||
|
@ -124,6 +133,9 @@ class MediaAttachment < ApplicationRecord
|
||||||
IMAGE_LIMIT = (ENV['MAX_IMAGE_SIZE'] || 10.megabytes).to_i
|
IMAGE_LIMIT = (ENV['MAX_IMAGE_SIZE'] || 10.megabytes).to_i
|
||||||
VIDEO_LIMIT = (ENV['MAX_VIDEO_SIZE'] || 40.megabytes).to_i
|
VIDEO_LIMIT = (ENV['MAX_VIDEO_SIZE'] || 40.megabytes).to_i
|
||||||
|
|
||||||
|
MAX_VIDEO_MATRIX_LIMIT = 2_304_000 # 1920x1200px
|
||||||
|
MAX_VIDEO_FRAME_RATE = 60
|
||||||
|
|
||||||
belongs_to :account, inverse_of: :media_attachments, optional: true
|
belongs_to :account, inverse_of: :media_attachments, optional: true
|
||||||
belongs_to :status, inverse_of: :media_attachments, optional: true
|
belongs_to :status, inverse_of: :media_attachments, optional: true
|
||||||
belongs_to :scheduled_status, inverse_of: :media_attachments, optional: true
|
belongs_to :scheduled_status, inverse_of: :media_attachments, optional: true
|
||||||
|
@ -156,6 +168,10 @@ class MediaAttachment < ApplicationRecord
|
||||||
remote_url.blank?
|
remote_url.blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def not_processed?
|
||||||
|
processing.present? && !processing_complete?
|
||||||
|
end
|
||||||
|
|
||||||
def needs_redownload?
|
def needs_redownload?
|
||||||
file.blank? && remote_url.present?
|
file.blank? && remote_url.present?
|
||||||
end
|
end
|
||||||
|
@ -203,12 +219,21 @@ class MediaAttachment < ApplicationRecord
|
||||||
"#{x},#{y}"
|
"#{x},#{y}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
attr_writer :delay_processing
|
||||||
|
|
||||||
|
def delay_processing?
|
||||||
|
@delay_processing
|
||||||
|
end
|
||||||
|
|
||||||
|
after_commit :enqueue_processing, on: :create
|
||||||
after_commit :reset_parent_cache, on: :update
|
after_commit :reset_parent_cache, on: :update
|
||||||
|
|
||||||
before_create :prepare_description, unless: :local?
|
before_create :prepare_description, unless: :local?
|
||||||
before_create :set_shortcode
|
before_create :set_shortcode
|
||||||
|
before_create :set_processing
|
||||||
|
|
||||||
before_post_process :set_type_and_extension
|
before_post_process :set_type_and_extension
|
||||||
|
before_post_process :check_video_dimensions
|
||||||
|
|
||||||
before_save :set_meta
|
before_save :set_meta
|
||||||
|
|
||||||
|
@ -277,6 +302,21 @@ class MediaAttachment < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_processing
|
||||||
|
self.processing = delay_processing? ? :queued : :complete
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_video_dimensions
|
||||||
|
return unless (video? || gifv?) && file.queued_for_write[:original].present?
|
||||||
|
|
||||||
|
movie = FFMPEG::Movie.new(file.queued_for_write[:original].path)
|
||||||
|
|
||||||
|
return unless movie.valid?
|
||||||
|
|
||||||
|
raise Mastodon::DimensionsValidationError, "#{movie.width}x#{movie.height} videos are not supported" if movie.width * movie.height > MAX_VIDEO_MATRIX_LIMIT
|
||||||
|
raise Mastodon::DimensionsValidationError, "#{movie.frame_rate.to_i}fps videos are not supported" if movie.frame_rate > MAX_VIDEO_FRAME_RATE
|
||||||
|
end
|
||||||
|
|
||||||
def set_meta
|
def set_meta
|
||||||
meta = populate_meta
|
meta = populate_meta
|
||||||
|
|
||||||
|
@ -322,9 +362,11 @@ class MediaAttachment < ApplicationRecord
|
||||||
}.compact
|
}.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_parent_cache
|
def enqueue_processing
|
||||||
return if status_id.nil?
|
PostProcessMediaWorker.perform_async(id) if delay_processing?
|
||||||
|
end
|
||||||
|
|
||||||
Rails.cache.delete("statuses/#{status_id}")
|
def reset_parent_cache
|
||||||
|
Rails.cache.delete("statuses/#{status_id}") if status_id.present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,6 +59,14 @@ class Report < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def resolve!(acting_account)
|
def resolve!(acting_account)
|
||||||
|
if account_id == -99 && target_account.trust_level == Account::TRUST_LEVELS[:untrusted]
|
||||||
|
# This is an automated report and it is being dismissed, so it's
|
||||||
|
# a false positive, in which case update the account's trust level
|
||||||
|
# to prevent further spam checks
|
||||||
|
|
||||||
|
target_account.update(trust_level: Account::TRUST_LEVELS[:trusted])
|
||||||
|
end
|
||||||
|
|
||||||
RemovalWorker.push_bulk(Status.with_discarded.discarded.where(id: status_ids).pluck(:id)) { |status_id| [status_id, { immediate: true }] }
|
RemovalWorker.push_bulk(Status.with_discarded.discarded.where(id: status_ids).pluck(:id)) { |status_id| [status_id, { immediate: true }] }
|
||||||
update!(action_taken: true, action_taken_by_account_id: acting_account.id)
|
update!(action_taken: true, action_taken_by_account_id: acting_account.id)
|
||||||
end
|
end
|
||||||
|
|
|
@ -148,10 +148,12 @@ class Status < ApplicationRecord
|
||||||
ids += mentions.where(account: Account.local).pluck(:account_id)
|
ids += mentions.where(account: Account.local).pluck(:account_id)
|
||||||
ids += favourites.where(account: Account.local).pluck(:account_id)
|
ids += favourites.where(account: Account.local).pluck(:account_id)
|
||||||
ids += reblogs.where(account: Account.local).pluck(:account_id)
|
ids += reblogs.where(account: Account.local).pluck(:account_id)
|
||||||
|
ids += bookmarks.where(account: Account.local).pluck(:account_id)
|
||||||
else
|
else
|
||||||
ids += preloaded.mentions[id] || []
|
ids += preloaded.mentions[id] || []
|
||||||
ids += preloaded.favourites[id] || []
|
ids += preloaded.favourites[id] || []
|
||||||
ids += preloaded.reblogs[id] || []
|
ids += preloaded.reblogs[id] || []
|
||||||
|
ids += preloaded.bookmarks[id] || []
|
||||||
end
|
end
|
||||||
|
|
||||||
ids.uniq
|
ids.uniq
|
||||||
|
|
|
@ -12,7 +12,9 @@ class REST::MediaAttachmentSerializer < ActiveModel::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def url
|
def url
|
||||||
if object.needs_redownload?
|
if object.not_processed?
|
||||||
|
nil
|
||||||
|
elsif object.needs_redownload?
|
||||||
media_proxy_url(object.id, :original)
|
media_proxy_url(object.id, :original)
|
||||||
else
|
else
|
||||||
full_asset_url(object.file.url(:original))
|
full_asset_url(object.file.url(:original))
|
||||||
|
|
|
@ -94,6 +94,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
@account.statuses_count = outbox_total_items if outbox_total_items.present?
|
@account.statuses_count = outbox_total_items if outbox_total_items.present?
|
||||||
@account.following_count = following_total_items if following_total_items.present?
|
@account.following_count = following_total_items if following_total_items.present?
|
||||||
@account.followers_count = followers_total_items if followers_total_items.present?
|
@account.followers_count = followers_total_items if followers_total_items.present?
|
||||||
|
@account.hide_collections = following_private? || followers_private?
|
||||||
@account.moved_to_account = @json['movedTo'].present? ? moved_account : nil
|
@account.moved_to_account = @json['movedTo'].present? ? moved_account : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -166,26 +167,36 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def outbox_total_items
|
def outbox_total_items
|
||||||
collection_total_items('outbox')
|
collection_info('outbox').first
|
||||||
end
|
end
|
||||||
|
|
||||||
def following_total_items
|
def following_total_items
|
||||||
collection_total_items('following')
|
collection_info('following').first
|
||||||
end
|
end
|
||||||
|
|
||||||
def followers_total_items
|
def followers_total_items
|
||||||
collection_total_items('followers')
|
collection_info('followers').first
|
||||||
end
|
end
|
||||||
|
|
||||||
def collection_total_items(type)
|
def following_private?
|
||||||
return if @json[type].blank?
|
!collection_info('following').last
|
||||||
|
end
|
||||||
|
|
||||||
|
def followers_private?
|
||||||
|
!collection_info('followers').last
|
||||||
|
end
|
||||||
|
|
||||||
|
def collection_info(type)
|
||||||
|
return [nil, nil] if @json[type].blank?
|
||||||
return @collections[type] if @collections.key?(type)
|
return @collections[type] if @collections.key?(type)
|
||||||
|
|
||||||
collection = fetch_resource_without_id_validation(@json[type])
|
collection = fetch_resource_without_id_validation(@json[type])
|
||||||
|
|
||||||
@collections[type] = collection.is_a?(Hash) && collection['totalItems'].present? && collection['totalItems'].is_a?(Numeric) ? collection['totalItems'] : nil
|
total_items = collection.is_a?(Hash) && collection['totalItems'].present? && collection['totalItems'].is_a?(Numeric) ? collection['totalItems'] : nil
|
||||||
|
has_first_page = collection.is_a?(Hash) && collection['first'].present?
|
||||||
|
@collections[type] = [total_items, has_first_page]
|
||||||
rescue HTTP::Error, OpenSSL::SSL::SSLError
|
rescue HTTP::Error, OpenSSL::SSL::SSLError
|
||||||
@collections[type] = nil
|
@collections[type] = [nil, nil]
|
||||||
end
|
end
|
||||||
|
|
||||||
def moved_account
|
def moved_account
|
||||||
|
|
|
@ -5,6 +5,8 @@ class FetchResourceService < BaseService
|
||||||
|
|
||||||
ACCEPT_HEADER = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", text/html;q=0.1'
|
ACCEPT_HEADER = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", text/html;q=0.1'
|
||||||
|
|
||||||
|
attr_reader :response_code
|
||||||
|
|
||||||
def call(url)
|
def call(url)
|
||||||
return if url.blank?
|
return if url.blank?
|
||||||
|
|
||||||
|
@ -27,6 +29,7 @@ class FetchResourceService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_response(response, terminal = false)
|
def process_response(response, terminal = false)
|
||||||
|
@response_code = response.code
|
||||||
return nil if response.code != 200
|
return nil if response.code != 200
|
||||||
|
|
||||||
if ['application/activity+json', 'application/ld+json'].include?(response.mime_type)
|
if ['application/activity+json', 'application/ld+json'].include?(response.mime_type)
|
||||||
|
|
|
@ -110,6 +110,7 @@ class PostStatusService < BaseService
|
||||||
@media = @account.media_attachments.where(status_id: nil).where(id: @options[:media_ids].take(4).map(&:to_i))
|
@media = @account.media_attachments.where(status_id: nil).where(id: @options[:media_ids].take(4).map(&:to_i))
|
||||||
|
|
||||||
raise Mastodon::ValidationError, I18n.t('media_attachments.validations.images_and_video') if @media.size > 1 && @media.find(&:audio_or_video?)
|
raise Mastodon::ValidationError, I18n.t('media_attachments.validations.images_and_video') if @media.size > 1 && @media.find(&:audio_or_video?)
|
||||||
|
raise Mastodon::ValidationError, I18n.t('media_attachments.validations.not_ready') if @media.any?(&:not_processed?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def language_from_option(str)
|
def language_from_option(str)
|
||||||
|
|
|
@ -12,7 +12,7 @@ class ResolveURLService < BaseService
|
||||||
process_local_url
|
process_local_url
|
||||||
elsif !fetched_resource.nil?
|
elsif !fetched_resource.nil?
|
||||||
process_url
|
process_url
|
||||||
elsif @on_behalf_of.present?
|
else
|
||||||
process_url_from_db
|
process_url_from_db
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -30,6 +30,8 @@ class ResolveURLService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_url_from_db
|
def process_url_from_db
|
||||||
|
return unless @on_behalf_of.present? && [401, 403, 404].include?(fetch_resource_service.response_code)
|
||||||
|
|
||||||
# It may happen that the resource is a private toot, and thus not fetchable,
|
# It may happen that the resource is a private toot, and thus not fetchable,
|
||||||
# but we can return the toot if we already know about it.
|
# but we can return the toot if we already know about it.
|
||||||
status = Status.find_by(uri: @url) || Status.find_by(url: @url)
|
status = Status.find_by(uri: @url) || Status.find_by(url: @url)
|
||||||
|
@ -40,7 +42,11 @@ class ResolveURLService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetched_resource
|
def fetched_resource
|
||||||
@fetched_resource ||= FetchResourceService.new.call(@url)
|
@fetched_resource ||= fetch_resource_service.call(@url)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_resource_service
|
||||||
|
@_fetch_resource_service ||= FetchResourceService.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_url
|
def resource_url
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
- unless @warning_presets.empty?
|
- unless @warning_presets.empty?
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :warning_preset_id, collection: @warning_presets, label_method: :text, wrapper: :with_block_label
|
= f.input :warning_preset_id, collection: @warning_presets, label_method: ->(warning_preset) { [warning_preset.title.presence, truncate(warning_preset.text)].compact.join(' - ') }, wrapper: :with_block_label
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :text, as: :text, wrapper: :with_block_label, hint: t('simple_form.hints.admin_account_action.text_html', path: admin_warning_presets_path)
|
= f.input :text, as: :text, wrapper: :with_block_label, hint: t('simple_form.hints.admin_account_action.text_html', path: admin_warning_presets_path)
|
||||||
|
|
|
@ -96,10 +96,17 @@
|
||||||
= table_link_to 'angle-double-down', t('admin.accounts.demote'), demote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:demote, @account.user)
|
= table_link_to 'angle-double-down', t('admin.accounts.demote'), demote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:demote, @account.user)
|
||||||
|
|
||||||
%tr
|
%tr
|
||||||
%th= t('admin.accounts.email')
|
%th{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= t('admin.accounts.email')
|
||||||
%td= @account.user_email
|
%td{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= @account.user_email
|
||||||
%td= table_link_to 'edit', t('admin.accounts.change_email.label'), admin_account_change_email_path(@account.id) if can?(:change_email, @account.user)
|
%td= table_link_to 'edit', t('admin.accounts.change_email.label'), admin_account_change_email_path(@account.id) if can?(:change_email, @account.user)
|
||||||
|
|
||||||
|
%tr
|
||||||
|
%td= table_link_to 'search', t('admin.accounts.search_same_email_domain'), admin_accounts_path(email: "%@#{@account.user_email.split('@').last}")
|
||||||
|
|
||||||
|
- if can?(:create, :email_domain_block)
|
||||||
|
%tr
|
||||||
|
%td= table_link_to 'ban', t('admin.accounts.add_email_domain_block'), new_admin_email_domain_block_path(_domain: @account.user_email.split('@').last)
|
||||||
|
|
||||||
- if @account.user_unconfirmed_email.present?
|
- if @account.user_unconfirmed_email.present?
|
||||||
%tr
|
%tr
|
||||||
%th= t('admin.accounts.unconfirmed_email')
|
%th= t('admin.accounts.unconfirmed_email')
|
||||||
|
@ -204,7 +211,7 @@
|
||||||
= link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(@account.id, type: 'suspend'), class: 'button button--destructive' if can?(:suspend, @account)
|
= link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(@account.id, type: 'suspend'), class: 'button button--destructive' if can?(:suspend, @account)
|
||||||
|
|
||||||
- unless @account.local?
|
- unless @account.local?
|
||||||
- if DomainBlock.where(domain: @account.domain).exists?
|
- if DomainBlock.rule_for(@account.domain)
|
||||||
= link_to t('admin.domain_blocks.view'), admin_instance_path(@account.domain), class: 'button'
|
= link_to t('admin.domain_blocks.view'), admin_instance_path(@account.domain), class: 'button'
|
||||||
- else
|
- else
|
||||||
= link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @account.domain), class: 'button button--destructive'
|
= link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @account.domain), class: 'button button--destructive'
|
||||||
|
|
|
@ -3,3 +3,13 @@
|
||||||
%samp= email_domain_block.domain
|
%samp= email_domain_block.domain
|
||||||
%td
|
%td
|
||||||
= table_link_to 'trash', t('admin.email_domain_blocks.delete'), admin_email_domain_block_path(email_domain_block), method: :delete
|
= table_link_to 'trash', t('admin.email_domain_blocks.delete'), admin_email_domain_block_path(email_domain_block), method: :delete
|
||||||
|
|
||||||
|
- email_domain_block.children.each do |child_email_domain_block|
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
%samp= child_email_domain_block.domain
|
||||||
|
%span.muted-hint
|
||||||
|
= surround '(', ')' do
|
||||||
|
= t('admin.email_domain_blocks.from_html', domain: content_tag(:samp, email_domain_block.domain))
|
||||||
|
%td
|
||||||
|
= table_link_to 'trash', t('admin.email_domain_blocks.delete'), admin_email_domain_block_path(child_email_domain_block), method: :delete
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
= render 'shared/error_messages', object: @email_domain_block
|
= render 'shared/error_messages', object: @email_domain_block
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :domain, wrapper: :with_label, label: t('admin.email_domain_blocks.domain')
|
= f.input :domain, wrapper: :with_block_label, label: t('admin.email_domain_blocks.domain')
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :with_dns_records, as: :boolean, wrapper: :with_label
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
= f.button :button, t('.create'), type: :submit
|
= f.button :button, t('.create'), type: :submit
|
||||||
|
|
10
app/views/admin/warning_presets/_warning_preset.html.haml
Normal file
10
app/views/admin/warning_presets/_warning_preset.html.haml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
.announcements-list__item
|
||||||
|
= link_to edit_admin_warning_preset_path(warning_preset), class: 'announcements-list__item__title' do
|
||||||
|
= warning_preset.title.presence || truncate(warning_preset.text)
|
||||||
|
|
||||||
|
.announcements-list__item__action-bar
|
||||||
|
.announcements-list__item__meta
|
||||||
|
= truncate(warning_preset.text)
|
||||||
|
|
||||||
|
%div
|
||||||
|
= table_link_to 'trash', t('admin.warning_presets.delete'), admin_warning_preset_path(warning_preset), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:destroy, warning_preset)
|
|
@ -4,6 +4,9 @@
|
||||||
= simple_form_for @warning_preset, url: admin_warning_preset_path(@warning_preset) do |f|
|
= simple_form_for @warning_preset, url: admin_warning_preset_path(@warning_preset) do |f|
|
||||||
= render 'shared/error_messages', object: @warning_preset
|
= render 'shared/error_messages', object: @warning_preset
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :title, wrapper: :with_block_label
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :text, wrapper: :with_block_label
|
= f.input :text, wrapper: :with_block_label
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
= simple_form_for @warning_preset, url: admin_warning_presets_path do |f|
|
= simple_form_for @warning_preset, url: admin_warning_presets_path do |f|
|
||||||
= render 'shared/error_messages', object: @warning_preset
|
= render 'shared/error_messages', object: @warning_preset
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :title, wrapper: :with_block_label
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :text, wrapper: :with_block_label
|
= f.input :text, wrapper: :with_block_label
|
||||||
|
|
||||||
|
@ -13,18 +16,9 @@
|
||||||
|
|
||||||
%hr.spacer/
|
%hr.spacer/
|
||||||
|
|
||||||
- unless @warning_presets.empty?
|
- if @warning_presets.empty?
|
||||||
.table-wrapper
|
%div.muted-hint.center-text
|
||||||
%table.table
|
= t 'admin.warning_presets.empty'
|
||||||
%thead
|
- else
|
||||||
%tr
|
.announcements-list
|
||||||
%th= t('simple_form.labels.account_warning_preset.text')
|
= render partial: 'warning_preset', collection: @warning_presets
|
||||||
%th
|
|
||||||
%tbody
|
|
||||||
- @warning_presets.each do |preset|
|
|
||||||
%tr
|
|
||||||
%td
|
|
||||||
= Formatter.instance.linkify(preset.text)
|
|
||||||
%td
|
|
||||||
= table_link_to 'pencil', t('admin.warning_presets.edit'), edit_admin_warning_preset_path(preset)
|
|
||||||
= table_link_to 'trash', t('admin.warning_presets.delete'), admin_warning_preset_path(preset), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }
|
|
||||||
|
|
|
@ -9,8 +9,12 @@ class BackupWorker
|
||||||
backup_id = msg['args'].first
|
backup_id = msg['args'].first
|
||||||
|
|
||||||
ActiveRecord::Base.connection_pool.with_connection do
|
ActiveRecord::Base.connection_pool.with_connection do
|
||||||
backup = Backup.find(backup_id)
|
begin
|
||||||
backup&.destroy
|
backup = Backup.find(backup_id)
|
||||||
|
backup.destroy
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
34
app/workers/post_process_media_worker.rb
Normal file
34
app/workers/post_process_media_worker.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class PostProcessMediaWorker
|
||||||
|
include Sidekiq::Worker
|
||||||
|
|
||||||
|
sidekiq_options retry: 1, dead: false
|
||||||
|
|
||||||
|
sidekiq_retries_exhausted do |msg|
|
||||||
|
media_attachment_id = msg['args'].first
|
||||||
|
|
||||||
|
ActiveRecord::Base.connection_pool.with_connection do
|
||||||
|
begin
|
||||||
|
media_attachment = MediaAttachment.find(media_attachment_id)
|
||||||
|
media_attachment.processing = :failed
|
||||||
|
media_attachment.save
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Sidekiq.logger.error("Processing media attachment #{media_attachment_id} failed with #{msg['error_message']}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform(media_attachment_id)
|
||||||
|
media_attachment = MediaAttachment.find(media_attachment_id)
|
||||||
|
media_attachment.processing = :in_progress
|
||||||
|
media_attachment.save
|
||||||
|
media_attachment.file.reprocess_original!
|
||||||
|
media_attachment.processing = :complete
|
||||||
|
media_attachment.save
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,6 +7,7 @@ require 'rails/all'
|
||||||
Bundler.require(*Rails.groups)
|
Bundler.require(*Rails.groups)
|
||||||
|
|
||||||
require_relative '../app/lib/exceptions'
|
require_relative '../app/lib/exceptions'
|
||||||
|
require_relative '../lib/paperclip/attachment_extensions'
|
||||||
require_relative '../lib/paperclip/lazy_thumbnail'
|
require_relative '../lib/paperclip/lazy_thumbnail'
|
||||||
require_relative '../lib/paperclip/gif_transcoder'
|
require_relative '../lib/paperclip/gif_transcoder'
|
||||||
require_relative '../lib/paperclip/video_transcoder'
|
require_relative '../lib/paperclip/video_transcoder'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
lock '3.11.2'
|
lock '3.12.1'
|
||||||
|
|
||||||
set :repo_url, ENV.fetch('REPO', 'https://github.com/tootsuite/mastodon.git')
|
set :repo_url, ENV.fetch('REPO', 'https://github.com/tootsuite/mastodon.git')
|
||||||
set :branch, ENV.fetch('BRANCH', 'master')
|
set :branch, ENV.fetch('BRANCH', 'master')
|
||||||
|
|
|
@ -19,4 +19,4 @@ Sidekiq.configure_client do |config|
|
||||||
config.redis = redis_params
|
config.redis = redis_params
|
||||||
end
|
end
|
||||||
|
|
||||||
Sidekiq::Logging.logger.level = ::Logger.const_get(ENV.fetch('RAILS_LOG_LEVEL', 'info').upcase.to_s)
|
Sidekiq.logger.level = ::Logger.const_get(ENV.fetch('RAILS_LOG_LEVEL', 'info').upcase.to_s)
|
||||||
|
|
|
@ -562,7 +562,6 @@ ar:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: إضافة واحد جديد
|
add_new: إضافة واحد جديد
|
||||||
delete: حذف
|
delete: حذف
|
||||||
edit: تعديل
|
|
||||||
edit_preset: تعديل نموذج التحذير
|
edit_preset: تعديل نموذج التحذير
|
||||||
title: إدارة نماذج التحذير
|
title: إدارة نماذج التحذير
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ ca:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Afegeix-ne un de nou
|
add_new: Afegeix-ne un de nou
|
||||||
delete: Esborra
|
delete: Esborra
|
||||||
edit: Edita
|
|
||||||
edit_preset: Edita l'avís predeterminat
|
edit_preset: Edita l'avís predeterminat
|
||||||
title: Gestiona les configuracions predefinides dels avisos
|
title: Gestiona les configuracions predefinides dels avisos
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ co:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Aghjunghje
|
add_new: Aghjunghje
|
||||||
delete: Sguassà
|
delete: Sguassà
|
||||||
edit: Cambià
|
|
||||||
edit_preset: Cambià a preselezzione d'avertimentu
|
edit_preset: Cambià a preselezzione d'avertimentu
|
||||||
title: Amministrà e preselezzione d'avertimentu
|
title: Amministrà e preselezzione d'avertimentu
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -588,7 +588,6 @@ cs:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Přidat nové
|
add_new: Přidat nové
|
||||||
delete: Smazat
|
delete: Smazat
|
||||||
edit: Upravit
|
|
||||||
edit_preset: Upravit předlohu pro varování
|
edit_preset: Upravit předlohu pro varování
|
||||||
title: Spravovat předlohy pro varování
|
title: Spravovat předlohy pro varování
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -605,7 +605,6 @@ cy:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Ychwanegu newydd
|
add_new: Ychwanegu newydd
|
||||||
delete: Dileu
|
delete: Dileu
|
||||||
edit: Golygu
|
|
||||||
edit_preset: Golygu rhagosodiad rhybudd
|
edit_preset: Golygu rhagosodiad rhybudd
|
||||||
title: Rheoli rhagosodiadau rhybudd
|
title: Rheoli rhagosodiadau rhybudd
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -489,7 +489,6 @@ da:
|
||||||
most_recent: Seneste
|
most_recent: Seneste
|
||||||
warning_presets:
|
warning_presets:
|
||||||
delete: Slet
|
delete: Slet
|
||||||
edit: Rediger
|
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
new_report:
|
new_report:
|
||||||
body: "%{reporter} har anmeldt %{target}"
|
body: "%{reporter} har anmeldt %{target}"
|
||||||
|
|
|
@ -573,7 +573,6 @@ de:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Neu hinzufügen
|
add_new: Neu hinzufügen
|
||||||
delete: Löschen
|
delete: Löschen
|
||||||
edit: Bearbeiten
|
|
||||||
edit_preset: Warnungsvorlage bearbeiten
|
edit_preset: Warnungsvorlage bearbeiten
|
||||||
title: Warnungsvorlagen verwalten
|
title: Warnungsvorlagen verwalten
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ el:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Πρόσθεση νέου
|
add_new: Πρόσθεση νέου
|
||||||
delete: Διαγραφή
|
delete: Διαγραφή
|
||||||
edit: Ενημέρωση
|
|
||||||
edit_preset: Ενημέρωση προκαθορισμένης προειδοποίησης
|
edit_preset: Ενημέρωση προκαθορισμένης προειδοποίησης
|
||||||
title: Διαχείριση προκαθορισμένων προειδοποιήσεων
|
title: Διαχείριση προκαθορισμένων προειδοποιήσεων
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -92,6 +92,7 @@ en:
|
||||||
delete: Delete
|
delete: Delete
|
||||||
destroyed_msg: Moderation note successfully destroyed!
|
destroyed_msg: Moderation note successfully destroyed!
|
||||||
accounts:
|
accounts:
|
||||||
|
add_email_domain_block: Blacklist e-mail domain
|
||||||
approve: Approve
|
approve: Approve
|
||||||
approve_all: Approve all
|
approve_all: Approve all
|
||||||
are_you_sure: Are you sure?
|
are_you_sure: Are you sure?
|
||||||
|
@ -172,6 +173,7 @@ en:
|
||||||
staff: Staff
|
staff: Staff
|
||||||
user: User
|
user: User
|
||||||
search: Search
|
search: Search
|
||||||
|
search_same_email_domain: Other users with the same e-mail domain
|
||||||
search_same_ip: Other users with the same IP
|
search_same_ip: Other users with the same IP
|
||||||
shared_inbox_url: Shared inbox URL
|
shared_inbox_url: Shared inbox URL
|
||||||
show:
|
show:
|
||||||
|
@ -359,6 +361,7 @@ en:
|
||||||
destroyed_msg: Successfully deleted e-mail domain from blacklist
|
destroyed_msg: Successfully deleted e-mail domain from blacklist
|
||||||
domain: Domain
|
domain: Domain
|
||||||
empty: No e-mail domains currently blacklisted.
|
empty: No e-mail domains currently blacklisted.
|
||||||
|
from_html: from %{domain}
|
||||||
new:
|
new:
|
||||||
create: Add domain
|
create: Add domain
|
||||||
title: New e-mail blacklist entry
|
title: New e-mail blacklist entry
|
||||||
|
@ -589,7 +592,6 @@ en:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Add new
|
add_new: Add new
|
||||||
delete: Delete
|
delete: Delete
|
||||||
edit: Edit
|
|
||||||
edit_preset: Edit warning preset
|
edit_preset: Edit warning preset
|
||||||
title: Manage warning presets
|
title: Manage warning presets
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
@ -867,6 +869,7 @@ en:
|
||||||
media_attachments:
|
media_attachments:
|
||||||
validations:
|
validations:
|
||||||
images_and_video: Cannot attach a video to a status that already contains images
|
images_and_video: Cannot attach a video to a status that already contains images
|
||||||
|
not_ready: Cannot attach files that have not finished processing. Try again in a moment!
|
||||||
too_many: Cannot attach more than 4 files
|
too_many: Cannot attach more than 4 files
|
||||||
migrations:
|
migrations:
|
||||||
acct: Moved to
|
acct: Moved to
|
||||||
|
|
|
@ -474,7 +474,6 @@ en_GB:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Add new
|
add_new: Add new
|
||||||
delete: Delete
|
delete: Delete
|
||||||
edit: Edit
|
|
||||||
edit_preset: Edit warning preset
|
edit_preset: Edit warning preset
|
||||||
title: Manage warning presets
|
title: Manage warning presets
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -557,7 +557,6 @@ eo:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Aldoni novan
|
add_new: Aldoni novan
|
||||||
delete: Forigi
|
delete: Forigi
|
||||||
edit: Redakti
|
|
||||||
edit_preset: Redakti avertan antaŭagordon
|
edit_preset: Redakti avertan antaŭagordon
|
||||||
title: Administri avertajn antaŭagordojn
|
title: Administri avertajn antaŭagordojn
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ es-AR:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Agregar nuevo
|
add_new: Agregar nuevo
|
||||||
delete: Eliminar
|
delete: Eliminar
|
||||||
edit: Editar
|
|
||||||
edit_preset: Editar preajuste de advertencia
|
edit_preset: Editar preajuste de advertencia
|
||||||
title: Administrar preajustes de advertencia
|
title: Administrar preajustes de advertencia
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ es:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Añadir nuevo
|
add_new: Añadir nuevo
|
||||||
delete: Borrar
|
delete: Borrar
|
||||||
edit: Editar
|
|
||||||
edit_preset: Editar aviso predeterminado
|
edit_preset: Editar aviso predeterminado
|
||||||
title: Editar configuración predeterminada de avisos
|
title: Editar configuración predeterminada de avisos
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -576,7 +576,6 @@ et:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Lisa uus
|
add_new: Lisa uus
|
||||||
delete: Kustuta
|
delete: Kustuta
|
||||||
edit: Redigeeri
|
|
||||||
edit_preset: Redigeeri hoiatuse eelseadistust
|
edit_preset: Redigeeri hoiatuse eelseadistust
|
||||||
title: Halda hoiatuste eelseadistusi
|
title: Halda hoiatuste eelseadistusi
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ eu:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Gehitu berria
|
add_new: Gehitu berria
|
||||||
delete: Ezabatu
|
delete: Ezabatu
|
||||||
edit: Editatu
|
|
||||||
edit_preset: Editatu abisu aurre-ezarpena
|
edit_preset: Editatu abisu aurre-ezarpena
|
||||||
title: Kudeatu abisu aurre-ezarpenak
|
title: Kudeatu abisu aurre-ezarpenak
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -575,7 +575,6 @@ fa:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: افزودن تازه
|
add_new: افزودن تازه
|
||||||
delete: زدودن
|
delete: زدودن
|
||||||
edit: ویرایش
|
|
||||||
edit_preset: ویرایش هشدار پیشفرض
|
edit_preset: ویرایش هشدار پیشفرض
|
||||||
title: مدیریت هشدارهای پیشفرض
|
title: مدیریت هشدارهای پیشفرض
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ fr:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Ajouter un nouveau
|
add_new: Ajouter un nouveau
|
||||||
delete: Effacer
|
delete: Effacer
|
||||||
edit: Éditer
|
|
||||||
edit_preset: Éditer les avertissements prédéfinis
|
edit_preset: Éditer les avertissements prédéfinis
|
||||||
title: Gérer les avertissements prédéfinis
|
title: Gérer les avertissements prédéfinis
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ gl:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Engadir novo
|
add_new: Engadir novo
|
||||||
delete: Eliminar
|
delete: Eliminar
|
||||||
edit: Editar
|
|
||||||
edit_preset: Editar aviso preestablecido
|
edit_preset: Editar aviso preestablecido
|
||||||
title: Xestionar avisos preestablecidos
|
title: Xestionar avisos preestablecidos
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -575,7 +575,6 @@ hu:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Új hozzáadása
|
add_new: Új hozzáadása
|
||||||
delete: Törlés
|
delete: Törlés
|
||||||
edit: Szerkesztés
|
|
||||||
edit_preset: Figyelmeztetés szerkesztése
|
edit_preset: Figyelmeztetés szerkesztése
|
||||||
title: Figyelmeztetések
|
title: Figyelmeztetések
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -565,7 +565,6 @@ id:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Tambah baru
|
add_new: Tambah baru
|
||||||
delete: Hapus
|
delete: Hapus
|
||||||
edit: Sunting
|
|
||||||
edit_preset: Sunting preset peringatan
|
edit_preset: Sunting preset peringatan
|
||||||
title: Kelola preset peringatan
|
title: Kelola preset peringatan
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ is:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Bæta við nýju
|
add_new: Bæta við nýju
|
||||||
delete: Eyða
|
delete: Eyða
|
||||||
edit: Breyta
|
|
||||||
edit_preset: Breyta forstilltri aðvörun
|
edit_preset: Breyta forstilltri aðvörun
|
||||||
title: Sýsla með forstilltar aðvaranir
|
title: Sýsla með forstilltar aðvaranir
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ it:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Aggiungi nuovo
|
add_new: Aggiungi nuovo
|
||||||
delete: Cancella
|
delete: Cancella
|
||||||
edit: Modifica
|
|
||||||
edit_preset: Modifica avviso predefinito
|
edit_preset: Modifica avviso predefinito
|
||||||
title: Gestisci avvisi predefiniti
|
title: Gestisci avvisi predefiniti
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -565,7 +565,6 @@ ja:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: 追加
|
add_new: 追加
|
||||||
delete: 削除
|
delete: 削除
|
||||||
edit: 編集
|
|
||||||
edit_preset: プリセット警告文を編集
|
edit_preset: プリセット警告文を編集
|
||||||
title: プリセット警告文を管理
|
title: プリセット警告文を管理
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -330,7 +330,6 @@ kab:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Rnu amaynut
|
add_new: Rnu amaynut
|
||||||
delete: Kkes
|
delete: Kkes
|
||||||
edit: Ẓreg
|
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
new_report:
|
new_report:
|
||||||
subject: Aneqqis amaynut i %{instance} (#%{id})
|
subject: Aneqqis amaynut i %{instance} (#%{id})
|
||||||
|
|
|
@ -555,7 +555,6 @@ kk:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Add nеw
|
add_new: Add nеw
|
||||||
delete: Deletе
|
delete: Deletе
|
||||||
edit: Еdit
|
|
||||||
edit_preset: Edit warning prеset
|
edit_preset: Edit warning prеset
|
||||||
title: Manage warning presеts
|
title: Manage warning presеts
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -567,7 +567,6 @@ ko:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: 새로 추가
|
add_new: 새로 추가
|
||||||
delete: 삭제
|
delete: 삭제
|
||||||
edit: 편집
|
|
||||||
edit_preset: 경고 틀 수정
|
edit_preset: 경고 틀 수정
|
||||||
title: 경고 틀 관리
|
title: 경고 틀 관리
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -410,7 +410,6 @@ lt:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Pridėti naują
|
add_new: Pridėti naują
|
||||||
delete: Ištrinti
|
delete: Ištrinti
|
||||||
edit: Keisti
|
|
||||||
edit_preset: Keisti įspėjimo nustatymus
|
edit_preset: Keisti įspėjimo nustatymus
|
||||||
title: Valdyti įspėjimo nustatymus
|
title: Valdyti įspėjimo nustatymus
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ nl:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Nieuwe toevoegen
|
add_new: Nieuwe toevoegen
|
||||||
delete: Verwijderen
|
delete: Verwijderen
|
||||||
edit: Bewerken
|
|
||||||
edit_preset: Voorinstelling van waarschuwing bewerken
|
edit_preset: Voorinstelling van waarschuwing bewerken
|
||||||
title: Voorinstellingen van waarschuwingen beheren
|
title: Voorinstellingen van waarschuwingen beheren
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -566,7 +566,6 @@ nn:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Legg til ny
|
add_new: Legg til ny
|
||||||
delete: Slett
|
delete: Slett
|
||||||
edit: Rediger
|
|
||||||
edit_preset: Endr åtvaringsoppsett
|
edit_preset: Endr åtvaringsoppsett
|
||||||
title: Handsam åtvaringsoppsett
|
title: Handsam åtvaringsoppsett
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -561,7 +561,6 @@
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Legg til ny
|
add_new: Legg til ny
|
||||||
delete: Slett
|
delete: Slett
|
||||||
edit: Rediger
|
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
new_pending_account:
|
new_pending_account:
|
||||||
body: Detaljer om den nye kontoen er nedenfor. Du kan godkjenne eller avvise denne søknaden.
|
body: Detaljer om den nye kontoen er nedenfor. Du kan godkjenne eller avvise denne søknaden.
|
||||||
|
|
|
@ -558,7 +558,6 @@ oc:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: N’ajustar un nòu
|
add_new: N’ajustar un nòu
|
||||||
delete: Escafar
|
delete: Escafar
|
||||||
edit: Modificar
|
|
||||||
edit_preset: Modificar lo tèxt predefinit d’avertiment
|
edit_preset: Modificar lo tèxt predefinit d’avertiment
|
||||||
title: Gerir los tèxtes predefinits
|
title: Gerir los tèxtes predefinits
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -541,7 +541,6 @@ pl:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Dodaj nowy
|
add_new: Dodaj nowy
|
||||||
delete: Usuń
|
delete: Usuń
|
||||||
edit: Edytuj
|
|
||||||
edit_preset: Edytuj szablon ostrzeżenia
|
edit_preset: Edytuj szablon ostrzeżenia
|
||||||
title: Zarządzaj szablonami ostrzeżeń
|
title: Zarządzaj szablonami ostrzeżeń
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ pt-BR:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Adicionar novo
|
add_new: Adicionar novo
|
||||||
delete: Excluir
|
delete: Excluir
|
||||||
edit: Editar
|
|
||||||
edit_preset: Editar o aviso pré-definido
|
edit_preset: Editar o aviso pré-definido
|
||||||
title: Gerenciar os avisos pré-definidos
|
title: Gerenciar os avisos pré-definidos
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -573,7 +573,6 @@ pt-PT:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Adicionar novo
|
add_new: Adicionar novo
|
||||||
delete: Apagar
|
delete: Apagar
|
||||||
edit: Editar
|
|
||||||
edit_preset: Editar o aviso predefinido
|
edit_preset: Editar o aviso predefinido
|
||||||
title: Gerir os avisos predefinidos
|
title: Gerir os avisos predefinidos
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -594,7 +594,6 @@ ru:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Добавить
|
add_new: Добавить
|
||||||
delete: Удалить
|
delete: Удалить
|
||||||
edit: Изменить
|
|
||||||
edit_preset: Удалить шаблон предупреждения
|
edit_preset: Удалить шаблон предупреждения
|
||||||
title: Управление шаблонами предупреждений
|
title: Управление шаблонами предупреждений
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -8,6 +8,7 @@ en:
|
||||||
acct: Specify the username@domain of the account you want to move to
|
acct: Specify the username@domain of the account you want to move to
|
||||||
account_warning_preset:
|
account_warning_preset:
|
||||||
text: You can use toot syntax, such as URLs, hashtags and mentions
|
text: You can use toot syntax, such as URLs, hashtags and mentions
|
||||||
|
title: Optional. Not visible to the recipient
|
||||||
admin_account_action:
|
admin_account_action:
|
||||||
include_statuses: The user will see which toots have caused the moderation action or warning
|
include_statuses: The user will see which toots have caused the moderation action or warning
|
||||||
send_email_notification: The user will receive an explanation of what happened with their account
|
send_email_notification: The user will receive an explanation of what happened with their account
|
||||||
|
@ -58,6 +59,9 @@ en:
|
||||||
whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word
|
whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word
|
||||||
domain_allow:
|
domain_allow:
|
||||||
domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored
|
domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored
|
||||||
|
email_domain_block:
|
||||||
|
domain: This can be the domain name that shows up in the e-mail address, the MX record that domain resolves to, or IP of the server that MX record resolves to. Those will be checked upon user sign-up and the sign-up will be rejected.
|
||||||
|
with_dns_records: An attempt to resolve the given domain's DNS records will be made and the results will also be blacklisted
|
||||||
featured_tag:
|
featured_tag:
|
||||||
name: 'You might want to use one of these:'
|
name: 'You might want to use one of these:'
|
||||||
form_challenge:
|
form_challenge:
|
||||||
|
@ -83,6 +87,7 @@ en:
|
||||||
acct: Handle of the new account
|
acct: Handle of the new account
|
||||||
account_warning_preset:
|
account_warning_preset:
|
||||||
text: Preset text
|
text: Preset text
|
||||||
|
title: Title
|
||||||
admin_account_action:
|
admin_account_action:
|
||||||
include_statuses: Include reported toots in the e-mail
|
include_statuses: Include reported toots in the e-mail
|
||||||
send_email_notification: Notify the user per e-mail
|
send_email_notification: Notify the user per e-mail
|
||||||
|
@ -163,6 +168,8 @@ en:
|
||||||
username: Username
|
username: Username
|
||||||
username_or_email: Username or Email
|
username_or_email: Username or Email
|
||||||
whole_word: Whole word
|
whole_word: Whole word
|
||||||
|
email_domain_block:
|
||||||
|
with_dns_records: Include MX records and IPs of the domain
|
||||||
featured_tag:
|
featured_tag:
|
||||||
name: Hashtag
|
name: Hashtag
|
||||||
interactions:
|
interactions:
|
||||||
|
|
|
@ -574,7 +574,6 @@ sk:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Pridaj nové
|
add_new: Pridaj nové
|
||||||
delete: Vymaž
|
delete: Vymaž
|
||||||
edit: Uprav
|
|
||||||
edit_preset: Uprav varovnú predlohu
|
edit_preset: Uprav varovnú predlohu
|
||||||
title: Spravuj varovné predlohy
|
title: Spravuj varovné predlohy
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -485,7 +485,6 @@ sl:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Dodaj novo
|
add_new: Dodaj novo
|
||||||
delete: Izbriši
|
delete: Izbriši
|
||||||
edit: Uredi
|
|
||||||
edit_preset: Uredi prednastavitev opozoril
|
edit_preset: Uredi prednastavitev opozoril
|
||||||
title: Upravljaj prednastavitev opozoril
|
title: Upravljaj prednastavitev opozoril
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -415,7 +415,6 @@ sq:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Shtoni të ri
|
add_new: Shtoni të ri
|
||||||
delete: Fshije
|
delete: Fshije
|
||||||
edit: Përpunoni
|
|
||||||
edit_preset: Përpunoni sinjalizim të paracaktuar
|
edit_preset: Përpunoni sinjalizim të paracaktuar
|
||||||
title: Administroni sinjalizime të paracaktuara
|
title: Administroni sinjalizime të paracaktuara
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -431,7 +431,6 @@ sr:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Додај нови
|
add_new: Додај нови
|
||||||
delete: Избриши
|
delete: Избриши
|
||||||
edit: Уреди
|
|
||||||
edit_preset: Уреди пресет упозорења
|
edit_preset: Уреди пресет упозорења
|
||||||
title: Управљај пресетима упозорења
|
title: Управљај пресетима упозорења
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
|
|
@ -448,7 +448,6 @@ sv:
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Lägg till ny
|
add_new: Lägg till ny
|
||||||
delete: Radera
|
delete: Radera
|
||||||
edit: Redigera
|
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
new_report:
|
new_report:
|
||||||
body: "%{reporter} har rapporterat %{target}"
|
body: "%{reporter} har rapporterat %{target}"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue