mirror of https://framagit.org/tykayn/mastodon.git
merge with master, add todo for statuses
This commit is contained in:
commit
8d6362e3e5
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
name: Bug Report
|
||||
about: If something isn't working as expected
|
||||
|
||||
labels: bug
|
||||
---
|
||||
|
||||
<!-- Make sure that you are submitting a new bug that was not previously reported or already fixed -->
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
name: Feature Request
|
||||
about: I have a suggestion
|
||||
|
||||
---
|
||||
|
||||
<!-- Please use a concise and distinct title for the issue -->
|
||||
|
|
|
@ -1 +1 @@
|
|||
2.6.6
|
||||
2.7.2
|
||||
|
|
|
@ -40,7 +40,7 @@ RUN apt update && \
|
|||
cd .. && rm -rf jemalloc-$JE_VER $JE_VER.tar.gz
|
||||
|
||||
# Install Ruby
|
||||
ENV RUBY_VER="2.6.6"
|
||||
ENV RUBY_VER="2.7.2"
|
||||
ENV CPPFLAGS="-I/opt/jemalloc/include"
|
||||
ENV LDFLAGS="-L/opt/jemalloc/lib/"
|
||||
RUN apt update && \
|
||||
|
|
19
Gemfile
19
Gemfile
|
@ -11,16 +11,13 @@ gem 'sprockets', '~> 3.7.2'
|
|||
gem 'thor', '~> 1.0'
|
||||
gem 'rack', '~> 2.2.3'
|
||||
|
||||
gem 'thwait', '~> 0.2.0'
|
||||
gem 'e2mmap', '~> 0.1.0'
|
||||
|
||||
gem 'hamlit-rails', '~> 0.2'
|
||||
gem 'pg', '~> 1.2'
|
||||
gem 'makara', '~> 0.4'
|
||||
gem 'pghero', '~> 2.7'
|
||||
gem 'dotenv-rails', '~> 2.7'
|
||||
|
||||
gem 'aws-sdk-s3', '~> 1.83', require: false
|
||||
gem 'aws-sdk-s3', '~> 1.85', require: false
|
||||
gem 'fog-core', '<= 2.1.0'
|
||||
gem 'fog-openstack', '~> 0.3', require: false
|
||||
gem 'paperclip', '~> 6.0'
|
||||
|
@ -30,7 +27,7 @@ gem 'blurhash', '~> 0.1'
|
|||
|
||||
gem 'active_model_serializers', '~> 0.10'
|
||||
gem 'addressable', '~> 2.7'
|
||||
gem 'bootsnap', '~> 1.4', require: false
|
||||
gem 'bootsnap', '~> 1.5', require: false
|
||||
gem 'browser'
|
||||
gem 'charlock_holmes', '~> 0.7.7'
|
||||
gem 'iso-639'
|
||||
|
@ -44,7 +41,7 @@ group :pam_authentication, optional: true do
|
|||
end
|
||||
|
||||
gem 'net-ldap', '~> 0.16'
|
||||
gem 'omniauth-cas', '~> 1.1'
|
||||
gem 'omniauth-cas', '~> 2.0'
|
||||
gem 'omniauth-saml', '~> 1.10'
|
||||
gem 'omniauth', '~> 1.9'
|
||||
|
||||
|
@ -71,7 +68,7 @@ gem 'nsa', '~> 0.2'
|
|||
gem 'oj', '~> 3.10'
|
||||
gem 'ox', '~> 2.13'
|
||||
gem 'parslet'
|
||||
gem 'parallel', '~> 1.19'
|
||||
gem 'parallel', '~> 1.20'
|
||||
gem 'posix-spawn'
|
||||
gem 'pundit', '~> 2.1'
|
||||
gem 'premailer-rails'
|
||||
|
@ -125,21 +122,21 @@ group :test do
|
|||
gem 'rails-controller-testing', '~> 1.0'
|
||||
gem 'rspec-sidekiq', '~> 3.1'
|
||||
gem 'simplecov', '~> 0.19', require: false
|
||||
gem 'webmock', '~> 3.9'
|
||||
gem 'parallel_tests', '~> 3.3'
|
||||
gem 'webmock', '~> 3.10'
|
||||
gem 'parallel_tests', '~> 3.4'
|
||||
gem 'rspec_junit_formatter', '~> 0.4'
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'active_record_query_trace', '~> 1.8'
|
||||
gem 'annotate', '~> 3.1'
|
||||
gem 'better_errors', '~> 2.8'
|
||||
gem 'better_errors', '~> 2.9'
|
||||
gem 'binding_of_caller', '~> 0.7'
|
||||
gem 'bullet', '~> 6.1'
|
||||
gem 'letter_opener', '~> 1.7'
|
||||
gem 'letter_opener_web', '~> 1.4'
|
||||
gem 'memory_profiler'
|
||||
gem 'rubocop', '~> 0.93', require: false
|
||||
gem 'rubocop', '~> 1.3', require: false
|
||||
gem 'rubocop-rails', '~> 2.8', require: false
|
||||
gem 'brakeman', '~> 4.10', require: false
|
||||
gem 'bundler-audit', '~> 0.7', require: false
|
||||
|
|
86
Gemfile.lock
86
Gemfile.lock
|
@ -79,8 +79,8 @@ GEM
|
|||
cocaine (~> 0.5.3)
|
||||
awrence (1.1.1)
|
||||
aws-eventstream (1.1.0)
|
||||
aws-partitions (1.388.0)
|
||||
aws-sdk-core (3.109.1)
|
||||
aws-partitions (1.397.0)
|
||||
aws-sdk-core (3.109.3)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.239.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
|
@ -88,14 +88,14 @@ GEM
|
|||
aws-sdk-kms (1.39.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.83.1)
|
||||
aws-sdk-s3 (1.85.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sigv4 (1.2.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
bcrypt (3.1.16)
|
||||
better_errors (2.8.3)
|
||||
better_errors (2.9.1)
|
||||
coderay (>= 1.0.0)
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
|
@ -104,10 +104,10 @@ GEM
|
|||
debug_inspector (>= 0.0.1)
|
||||
blurhash (0.1.4)
|
||||
ffi (~> 1.10.0)
|
||||
bootsnap (1.4.9)
|
||||
bootsnap (1.5.1)
|
||||
msgpack (~> 1.0)
|
||||
brakeman (4.10.0)
|
||||
browser (5.1.0)
|
||||
browser (4.2.0)
|
||||
builder (3.2.4)
|
||||
bullet (6.1.0)
|
||||
activesupport (>= 3.0.0)
|
||||
|
@ -147,7 +147,7 @@ GEM
|
|||
activesupport (>= 4.0)
|
||||
elasticsearch (>= 2.0.0)
|
||||
elasticsearch-dsl
|
||||
chunky_png (1.3.14)
|
||||
chunky_png (1.3.12)
|
||||
cld3 (3.3.0)
|
||||
ffi (>= 1.1.0, < 1.12.0)
|
||||
climate_control (0.2.0)
|
||||
|
@ -207,13 +207,12 @@ GEM
|
|||
erubi (1.9.0)
|
||||
et-orbi (1.2.4)
|
||||
tzinfo
|
||||
excon (0.78.0)
|
||||
excon (0.76.0)
|
||||
fabrication (2.21.1)
|
||||
faker (2.14.0)
|
||||
i18n (>= 1.6, < 2)
|
||||
faraday (1.1.0)
|
||||
faraday (1.0.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ruby2_keywords
|
||||
fast_blank (1.0.0)
|
||||
fastimage (2.2.0)
|
||||
ffi (1.10.0)
|
||||
|
@ -233,9 +232,9 @@ GEM
|
|||
fog-json (>= 1.0)
|
||||
ipaddress (>= 0.8)
|
||||
formatador (0.2.5)
|
||||
fugit (1.4.0)
|
||||
fugit (1.3.9)
|
||||
et-orbi (~> 1.1, >= 1.1.8)
|
||||
raabro (~> 1.4)
|
||||
raabro (~> 1.3)
|
||||
fuubar (2.5.0)
|
||||
rspec-core (~> 3.0)
|
||||
ruby-progressbar (~> 1.4)
|
||||
|
@ -290,7 +289,7 @@ GEM
|
|||
jmespath (1.4.0)
|
||||
json (2.3.1)
|
||||
json-canonicalization (0.2.0)
|
||||
json-ld (3.1.4)
|
||||
json-ld (3.1.5)
|
||||
htmlentities (~> 4.3)
|
||||
json-canonicalization (~> 0.2)
|
||||
link_header (~> 0.0, >= 0.0.8)
|
||||
|
@ -368,11 +367,11 @@ GEM
|
|||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
sidekiq (>= 3.5)
|
||||
statsd-ruby (~> 1.4, >= 1.4.0)
|
||||
oj (3.10.15)
|
||||
oj (3.10.16)
|
||||
omniauth (1.9.1)
|
||||
hashie (>= 3.4.6)
|
||||
rack (>= 1.6.2, < 3)
|
||||
omniauth-cas (1.1.1)
|
||||
omniauth-cas (2.0.0)
|
||||
addressable (~> 2.3)
|
||||
nokogiri (~> 1.5)
|
||||
omniauth (~> 1.2)
|
||||
|
@ -383,7 +382,7 @@ GEM
|
|||
openssl-signature_algorithm (0.4.0)
|
||||
orm_adapter (0.5.0)
|
||||
ox (2.13.4)
|
||||
paperclip (6.1.0)
|
||||
paperclip (6.0.0)
|
||||
activemodel (>= 4.2.0)
|
||||
activesupport (>= 4.2.0)
|
||||
mime-types
|
||||
|
@ -392,8 +391,8 @@ GEM
|
|||
paperclip-av-transcoder (0.6.4)
|
||||
av (~> 0.9.0)
|
||||
paperclip (>= 2.5.2)
|
||||
parallel (1.19.2)
|
||||
parallel_tests (3.3.0)
|
||||
parallel (1.20.1)
|
||||
parallel_tests (3.4.0)
|
||||
parallel
|
||||
parser (2.7.2.0)
|
||||
ast (~> 2.4.1)
|
||||
|
@ -429,7 +428,7 @@ GEM
|
|||
nio4r (~> 2.0)
|
||||
pundit (2.1.0)
|
||||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
raabro (1.3.3)
|
||||
rack (2.2.3)
|
||||
rack-attack (6.3.1)
|
||||
rack (>= 1.0, < 3)
|
||||
|
@ -464,7 +463,7 @@ GEM
|
|||
rails-i18n (5.1.3)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 5.0, < 6)
|
||||
rails-settings-cached (0.7.2)
|
||||
rails-settings-cached (0.6.6)
|
||||
rails (>= 4.2.0)
|
||||
railties (5.2.4.4)
|
||||
actionpack (= 5.2.4.4)
|
||||
|
@ -474,12 +473,12 @@ GEM
|
|||
thor (>= 0.19.0, < 2.0)
|
||||
rainbow (3.0.0)
|
||||
rake (13.0.1)
|
||||
rdf (3.1.6)
|
||||
rdf (3.1.7)
|
||||
hamster (~> 3.0)
|
||||
link_header (~> 0.0, >= 0.0.8)
|
||||
rdf-normalize (0.4.0)
|
||||
rdf (~> 3.1)
|
||||
redis (4.2.2)
|
||||
redis (4.2.5)
|
||||
redis-actionpack (5.2.0)
|
||||
actionpack (>= 5, < 7)
|
||||
redis-rack (>= 2.1.0, < 3)
|
||||
|
@ -511,14 +510,14 @@ GEM
|
|||
chunky_png (~> 1.0)
|
||||
rqrcode_core (~> 0.1)
|
||||
rqrcode_core (0.1.2)
|
||||
rspec-core (3.10.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-expectations (3.10.0)
|
||||
rspec-core (3.9.3)
|
||||
rspec-support (~> 3.9.3)
|
||||
rspec-expectations (3.9.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-mocks (3.10.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-mocks (3.9.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-rails (4.0.1)
|
||||
actionpack (>= 4.2)
|
||||
activesupport (>= 4.2)
|
||||
|
@ -530,19 +529,19 @@ GEM
|
|||
rspec-sidekiq (3.1.0)
|
||||
rspec-core (~> 3.0, >= 3.0.0)
|
||||
sidekiq (>= 2.4.0)
|
||||
rspec-support (3.10.0)
|
||||
rspec-support (3.9.3)
|
||||
rspec_junit_formatter (0.4.1)
|
||||
rspec-core (>= 2, < 4, != 2.12.0)
|
||||
rubocop (0.93.1)
|
||||
rubocop (1.3.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.7.1.5)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8)
|
||||
rexml
|
||||
rubocop-ast (>= 0.6.0)
|
||||
rubocop-ast (>= 1.1.1)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 2.0)
|
||||
rubocop-ast (1.1.0)
|
||||
rubocop-ast (1.1.1)
|
||||
parser (>= 2.7.1.5)
|
||||
rubocop-rails (2.8.1)
|
||||
activesupport (>= 4.2.0)
|
||||
|
@ -551,7 +550,6 @@ GEM
|
|||
ruby-progressbar (1.10.1)
|
||||
ruby-saml (1.11.0)
|
||||
nokogiri (>= 1.5.10)
|
||||
ruby2_keywords (0.0.2)
|
||||
rufus-scheduler (3.6.0)
|
||||
fugit (~> 1.1, >= 1.1.6)
|
||||
safety_net_attestation (0.4.0)
|
||||
|
@ -651,7 +649,7 @@ GEM
|
|||
safety_net_attestation (~> 0.4.0)
|
||||
securecompare (~> 1.0)
|
||||
tpm-key_attestation (~> 0.9.0)
|
||||
webmock (3.9.3)
|
||||
webmock (3.10.0)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
|
@ -660,7 +658,7 @@ GEM
|
|||
rack-proxy (>= 0.6.1)
|
||||
railties (>= 5.2)
|
||||
semantic_range (>= 2.3.0)
|
||||
webpush (1.0.0)
|
||||
webpush (0.3.8)
|
||||
hkdf (~> 0.2)
|
||||
jwt (~> 2.0)
|
||||
websocket-driver (0.7.3)
|
||||
|
@ -679,11 +677,11 @@ DEPENDENCIES
|
|||
active_record_query_trace (~> 1.8)
|
||||
addressable (~> 2.7)
|
||||
annotate (~> 3.1)
|
||||
aws-sdk-s3 (~> 1.83)
|
||||
better_errors (~> 2.8)
|
||||
aws-sdk-s3 (~> 1.85)
|
||||
better_errors (~> 2.9)
|
||||
binding_of_caller (~> 0.7)
|
||||
blurhash (~> 0.1)
|
||||
bootsnap (~> 1.4)
|
||||
bootsnap (~> 1.5)
|
||||
brakeman (~> 4.10)
|
||||
browser
|
||||
bullet (~> 6.1)
|
||||
|
@ -706,7 +704,6 @@ DEPENDENCIES
|
|||
discard (~> 1.2)
|
||||
doorkeeper (~> 5.4)
|
||||
dotenv-rails (~> 2.7)
|
||||
e2mmap (~> 0.1.0)
|
||||
ed25519 (~> 1.2)
|
||||
fabrication (~> 2.21)
|
||||
faker (~> 2.14)
|
||||
|
@ -743,13 +740,13 @@ DEPENDENCIES
|
|||
nsa (~> 0.2)
|
||||
oj (~> 3.10)
|
||||
omniauth (~> 1.9)
|
||||
omniauth-cas (~> 1.1)
|
||||
omniauth-cas (~> 2.0)
|
||||
omniauth-saml (~> 1.10)
|
||||
ox (~> 2.13)
|
||||
paperclip (~> 6.0)
|
||||
paperclip-av-transcoder (~> 0.6)
|
||||
parallel (~> 1.19)
|
||||
parallel_tests (~> 3.3)
|
||||
parallel (~> 1.20)
|
||||
parallel_tests (~> 3.4)
|
||||
parslet
|
||||
pg (~> 1.2)
|
||||
pghero (~> 2.7)
|
||||
|
@ -777,7 +774,7 @@ DEPENDENCIES
|
|||
rspec-rails (~> 4.0)
|
||||
rspec-sidekiq (~> 3.1)
|
||||
rspec_junit_formatter (~> 0.4)
|
||||
rubocop (~> 0.93)
|
||||
rubocop (~> 1.3)
|
||||
rubocop-rails (~> 2.8)
|
||||
ruby-progressbar (~> 1.10)
|
||||
sanitize (~> 5.2)
|
||||
|
@ -795,12 +792,11 @@ DEPENDENCIES
|
|||
streamio-ffmpeg (~> 3.0)
|
||||
strong_migrations (~> 0.7)
|
||||
thor (~> 1.0)
|
||||
thwait (~> 0.2.0)
|
||||
tty-prompt (~> 0.22)
|
||||
twitter-text (~> 1.14)
|
||||
tzinfo-data (~> 1.2020)
|
||||
webauthn (~> 3.0.0.alpha1)
|
||||
webmock (~> 3.9)
|
||||
webmock (~> 3.10)
|
||||
webpacker (~> 5.2)
|
||||
webpush
|
||||
xorcist (~> 1.1)
|
||||
|
|
|
@ -102,6 +102,10 @@ class AccountsController < ApplicationController
|
|||
params[:username]
|
||||
end
|
||||
|
||||
def skip_temporary_suspension_response?
|
||||
request.format == :json
|
||||
end
|
||||
|
||||
def rss_url
|
||||
if tag_requested?
|
||||
short_account_tag_url(@account, params[:tag], format: 'rss')
|
||||
|
|
|
@ -8,4 +8,8 @@ class ActivityPub::BaseController < Api::BaseController
|
|||
def set_cache_headers
|
||||
response.headers['Vary'] = 'Signature' if authorized_fetch_mode?
|
||||
end
|
||||
|
||||
def skip_temporary_suspension_response?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,6 +33,10 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
|
|||
params[:account_username].present?
|
||||
end
|
||||
|
||||
def skip_temporary_suspension_response?
|
||||
true
|
||||
end
|
||||
|
||||
def body
|
||||
return @body if defined?(@body)
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
|
|||
end
|
||||
|
||||
def set_replies
|
||||
@replies = only_other_accounts? ? Status.where.not(account_id: @account.id) : @account.statuses
|
||||
@replies = only_other_accounts? ? Status.where.not(account_id: @account.id).joins(:account).merge(Account.without_suspended) : @account.statuses
|
||||
@replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])
|
||||
@replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])
|
||||
end
|
||||
|
|
|
@ -53,6 +53,13 @@ module Admin
|
|||
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.destroyed_msg', username: @account.acct)
|
||||
end
|
||||
|
||||
def unsensitive
|
||||
authorize @account, :unsensitive?
|
||||
@account.unsensitize!
|
||||
log_action :unsensitive, @account
|
||||
redirect_to admin_account_path(@account.id)
|
||||
end
|
||||
|
||||
def unsilence
|
||||
authorize @account, :unsilence?
|
||||
@account.unsilence!
|
||||
|
|
|
@ -71,7 +71,7 @@ class Admin::AnnouncementsController < Admin::BaseController
|
|||
private
|
||||
|
||||
def set_announcements
|
||||
@announcements = AnnouncementFilter.new(filter_params).results.page(params[:page])
|
||||
@announcements = AnnouncementFilter.new(filter_params).results.reverse_chronological.page(params[:page])
|
||||
end
|
||||
|
||||
def set_announcement
|
||||
|
|
|
@ -103,7 +103,7 @@ class Api::BaseController < ApplicationController
|
|||
elsif !current_user.functional?
|
||||
render json: { error: 'Your login is currently disabled' }, status: 403
|
||||
else
|
||||
set_user_activity
|
||||
update_user_sign_in
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
|||
active
|
||||
pending
|
||||
disabled
|
||||
sensitized
|
||||
silenced
|
||||
suspended
|
||||
username
|
||||
|
@ -68,6 +69,13 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
|||
render json: @account, serializer: REST::Admin::AccountSerializer
|
||||
end
|
||||
|
||||
def unsensitive
|
||||
authorize @account, :unsensitive?
|
||||
@account.unsensitize!
|
||||
log_action :unsensitive, @account
|
||||
render json: @account, serializer: REST::Admin::AccountSerializer
|
||||
end
|
||||
|
||||
def unsilence
|
||||
authorize @account, :unsilence?
|
||||
@account.unsilence!
|
||||
|
|
|
@ -5,7 +5,7 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController
|
|||
|
||||
before_action -> { doorkeeper_authorize! :write, :'write:favourites' }
|
||||
before_action :require_user!
|
||||
before_action :set_status
|
||||
before_action :set_status, only: [:create]
|
||||
|
||||
def create
|
||||
FavouriteService.new.call(current_account, @status)
|
||||
|
@ -13,8 +13,19 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController
|
|||
end
|
||||
|
||||
def destroy
|
||||
UnfavouriteWorker.perform_async(current_account.id, @status.id)
|
||||
fav = current_account.favourites.find_by(status_id: params[:status_id])
|
||||
|
||||
if fav
|
||||
@status = fav.status
|
||||
UnfavouriteWorker.perform_async(current_account.id, @status.id)
|
||||
else
|
||||
@status = Status.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
end
|
||||
|
||||
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, favourites_map: { @status.id => false })
|
||||
rescue Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -7,6 +7,7 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
|
||||
skip_before_action :require_no_authentication, only: [:create]
|
||||
skip_before_action :require_functional!
|
||||
skip_before_action :update_user_sign_in
|
||||
|
||||
include TwoFactorAuthenticationConcern
|
||||
include SignInTokenAuthenticationConcern
|
||||
|
@ -24,6 +25,7 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
|
||||
def create
|
||||
super do |resource|
|
||||
resource.update_sign_in!(request, new_sign_in: true)
|
||||
remember_me(resource)
|
||||
flash.delete(:notice)
|
||||
end
|
||||
|
@ -57,7 +59,7 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
|
||||
def find_user
|
||||
if session[:attempt_user_id]
|
||||
User.find(session[:attempt_user_id])
|
||||
User.find_by(id: session[:attempt_user_id])
|
||||
else
|
||||
user = User.authenticate_with_ldap(user_params) if Devise.ldap_authentication
|
||||
user ||= User.authenticate_with_pam(user_params) if Devise.pam_authentication
|
||||
|
@ -90,6 +92,7 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
|
||||
def require_no_authentication
|
||||
super
|
||||
|
||||
# Delete flash message that isn't entirely useful and may be confusing in
|
||||
# most cases because /web doesn't display/clear flash messages.
|
||||
flash.delete(:alert) if flash[:alert] == I18n.t('devise.failure.already_authenticated')
|
||||
|
@ -107,13 +110,30 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
|
||||
def home_paths(resource)
|
||||
paths = [about_path]
|
||||
|
||||
if single_user_mode? && resource.is_a?(User)
|
||||
paths << short_account_path(username: resource.account)
|
||||
end
|
||||
|
||||
paths
|
||||
end
|
||||
|
||||
def continue_after?
|
||||
truthy_param?(:continue)
|
||||
end
|
||||
|
||||
def restart_session
|
||||
clear_attempt_from_session
|
||||
redirect_to new_user_session_path, alert: I18n.t('devise.failure.timeout')
|
||||
end
|
||||
|
||||
def set_attempt_session(user)
|
||||
session[:attempt_user_id] = user.id
|
||||
session[:attempt_user_updated_at] = user.updated_at.to_s
|
||||
end
|
||||
|
||||
def clear_attempt_from_session
|
||||
session.delete(:attempt_user_id)
|
||||
session.delete(:attempt_user_updated_at)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,6 +29,24 @@ module AccountOwnedConcern
|
|||
end
|
||||
|
||||
def check_account_suspension
|
||||
expires_in(3.minutes, public: true) && gone if @account.suspended?
|
||||
if @account.suspended_permanently?
|
||||
permanent_suspension_response
|
||||
elsif @account.suspended? && !skip_temporary_suspension_response?
|
||||
temporary_suspension_response
|
||||
end
|
||||
end
|
||||
|
||||
def skip_temporary_suspension_response?
|
||||
false
|
||||
end
|
||||
|
||||
def permanent_suspension_response
|
||||
expires_in(3.minutes, public: true)
|
||||
gone
|
||||
end
|
||||
|
||||
def temporary_suspension_response
|
||||
expires_in(3.minutes, public: true)
|
||||
forbidden
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,7 +18,9 @@ module SignInTokenAuthenticationConcern
|
|||
def authenticate_with_sign_in_token
|
||||
user = self.resource = find_user
|
||||
|
||||
if user_params[:sign_in_token_attempt].present? && session[:attempt_user_id]
|
||||
if user.present? && session[:attempt_user_id].present? && session[:attempt_user_updated_at] != user.updated_at.to_s
|
||||
restart_session
|
||||
elsif user_params.key?(:sign_in_token_attempt) && session[:attempt_user_id]
|
||||
authenticate_with_sign_in_token_attempt(user)
|
||||
elsif user.present? && user.external_or_valid_password?(user_params[:password])
|
||||
prompt_for_sign_in_token(user)
|
||||
|
@ -27,7 +29,7 @@ module SignInTokenAuthenticationConcern
|
|||
|
||||
def authenticate_with_sign_in_token_attempt(user)
|
||||
if valid_sign_in_token_attempt?(user)
|
||||
session.delete(:attempt_user_id)
|
||||
clear_attempt_from_session
|
||||
remember_me(user)
|
||||
sign_in(user)
|
||||
else
|
||||
|
@ -42,10 +44,10 @@ module SignInTokenAuthenticationConcern
|
|||
UserMailer.sign_in_token(user, request.remote_ip, request.user_agent, Time.now.utc.to_s).deliver_later!
|
||||
end
|
||||
|
||||
set_locale do
|
||||
session[:attempt_user_id] = user.id
|
||||
@body_classes = 'lighter'
|
||||
render :sign_in_token
|
||||
end
|
||||
set_attempt_session(user)
|
||||
|
||||
@body_classes = 'lighter'
|
||||
|
||||
set_locale { render :sign_in_token }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -76,6 +76,7 @@ module SignatureVerification
|
|||
raise SignatureVerificationError, 'Signed request date outside acceptable time window' unless matches_time_window?
|
||||
|
||||
verify_signature_strength!
|
||||
verify_body_digest!
|
||||
|
||||
account = account_from_key_id(signature_params['keyId'])
|
||||
|
||||
|
@ -126,10 +127,19 @@ module SignatureVerification
|
|||
def verify_signature_strength!
|
||||
raise SignatureVerificationError, 'Mastodon requires the Date header or (created) pseudo-header to be signed' unless signed_headers.include?('date') || signed_headers.include?('(created)')
|
||||
raise SignatureVerificationError, 'Mastodon requires the Digest header or (request-target) pseudo-header to be signed' unless signed_headers.include?(Request::REQUEST_TARGET) || signed_headers.include?('digest')
|
||||
raise SignatureVerificationError, 'Mastodon requires the Host header to be signed' unless signed_headers.include?('host')
|
||||
raise SignatureVerificationError, 'Mastodon requires the Host header to be signed when doing a GET request' if request.get? && !signed_headers.include?('host')
|
||||
raise SignatureVerificationError, 'Mastodon requires the Digest header to be signed when doing a POST request' if request.post? && !signed_headers.include?('digest')
|
||||
end
|
||||
|
||||
def verify_body_digest!
|
||||
return unless signed_headers.include?('digest')
|
||||
|
||||
digests = request.headers['Digest'].split(',').map { |digest| digest.split('=', 2) }.map { |key, value| [key.downcase, value] }
|
||||
sha256 = digests.assoc('sha-256')
|
||||
raise SignatureVerificationError, "Mastodon only supports SHA-256 in Digest header. Offered algorithms: #{digests.map(&:first).join(', ')}" if sha256.nil?
|
||||
raise SignatureVerificationError, "Invalid Digest value. Computed SHA-256 digest: #{body_digest}; given: #{sha256[1]}" if body_digest != sha256[1]
|
||||
end
|
||||
|
||||
def verify_signature(account, signature, compare_signed_string)
|
||||
if account.keypair.public_key.verify(OpenSSL::Digest.new('SHA256'), signature, compare_signed_string)
|
||||
@signed_request_account = account
|
||||
|
@ -153,8 +163,6 @@ module SignatureVerification
|
|||
raise SignatureVerificationError, 'Pseudo-header (expires) used but corresponding argument missing' if signature_params['expires'].blank?
|
||||
|
||||
"(expires): #{signature_params['expires']}"
|
||||
elsif signed_header == 'digest'
|
||||
"digest: #{body_digest}"
|
||||
else
|
||||
"#{signed_header}: #{request.headers[to_header_name(signed_header)]}"
|
||||
end
|
||||
|
@ -187,7 +195,7 @@ module SignatureVerification
|
|||
end
|
||||
|
||||
def body_digest
|
||||
"SHA-256=#{Digest::SHA256.base64digest(request_body)}"
|
||||
@body_digest ||= Digest::SHA256.base64digest(request_body)
|
||||
end
|
||||
|
||||
def to_header_name(name)
|
||||
|
|
|
@ -37,9 +37,11 @@ module TwoFactorAuthenticationConcern
|
|||
def authenticate_with_two_factor
|
||||
user = self.resource = find_user
|
||||
|
||||
if user.webauthn_enabled? && user_params[:credential].present? && session[:attempt_user_id]
|
||||
if user.present? && session[:attempt_user_id].present? && session[:attempt_user_updated_at] != user.updated_at.to_s
|
||||
restart_session
|
||||
elsif user.webauthn_enabled? && user_params.key?(:credential) && session[:attempt_user_id]
|
||||
authenticate_with_two_factor_via_webauthn(user)
|
||||
elsif user_params[:otp_attempt].present? && session[:attempt_user_id]
|
||||
elsif user_params.key?(:otp_attempt) && session[:attempt_user_id]
|
||||
authenticate_with_two_factor_via_otp(user)
|
||||
elsif user.present? && user.external_or_valid_password?(user_params[:password])
|
||||
prompt_for_two_factor(user)
|
||||
|
@ -50,7 +52,7 @@ module TwoFactorAuthenticationConcern
|
|||
webauthn_credential = WebAuthn::Credential.from_get(user_params[:credential])
|
||||
|
||||
if valid_webauthn_credential?(user, webauthn_credential)
|
||||
session.delete(:attempt_user_id)
|
||||
clear_attempt_from_session
|
||||
remember_me(user)
|
||||
sign_in(user)
|
||||
render json: { redirect_path: root_path }, status: :ok
|
||||
|
@ -61,7 +63,7 @@ module TwoFactorAuthenticationConcern
|
|||
|
||||
def authenticate_with_two_factor_via_otp(user)
|
||||
if valid_otp_attempt?(user)
|
||||
session.delete(:attempt_user_id)
|
||||
clear_attempt_from_session
|
||||
remember_me(user)
|
||||
sign_in(user)
|
||||
else
|
||||
|
@ -71,16 +73,18 @@ module TwoFactorAuthenticationConcern
|
|||
end
|
||||
|
||||
def prompt_for_two_factor(user)
|
||||
set_locale do
|
||||
session[:attempt_user_id] = user.id
|
||||
@body_classes = 'lighter'
|
||||
@webauthn_enabled = user.webauthn_enabled?
|
||||
@scheme_type = if user.webauthn_enabled? && user_params[:otp_attempt].blank?
|
||||
'webauthn'
|
||||
else
|
||||
'totp'
|
||||
end
|
||||
render :two_factor
|
||||
set_attempt_session(user)
|
||||
|
||||
@body_classes = 'lighter'
|
||||
@webauthn_enabled = user.webauthn_enabled?
|
||||
@scheme_type = begin
|
||||
if user.webauthn_enabled? && user_params[:otp_attempt].blank?
|
||||
'webauthn'
|
||||
else
|
||||
'totp'
|
||||
end
|
||||
end
|
||||
|
||||
set_locale { render :two_factor }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,14 +6,13 @@ module UserTrackingConcern
|
|||
UPDATE_SIGN_IN_HOURS = 24
|
||||
|
||||
included do
|
||||
before_action :set_user_activity
|
||||
before_action :update_user_sign_in
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_user_activity
|
||||
return unless user_needs_sign_in_update?
|
||||
current_user.update_tracked_fields!(request)
|
||||
def update_user_sign_in
|
||||
current_user.update_sign_in!(request) if user_needs_sign_in_update?
|
||||
end
|
||||
|
||||
def user_needs_sign_in_update?
|
||||
|
|
|
@ -52,6 +52,14 @@ class FollowerAccountsController < ApplicationController
|
|||
account_followers_url(@account, page: page) unless page.nil?
|
||||
end
|
||||
|
||||
def next_page_url
|
||||
page_url(follows.next_page) if follows.respond_to?(:next_page)
|
||||
end
|
||||
|
||||
def prev_page_url
|
||||
page_url(follows.prev_page) if follows.respond_to?(:prev_page)
|
||||
end
|
||||
|
||||
def collection_presenter
|
||||
if page_requested?
|
||||
ActivityPub::CollectionPresenter.new(
|
||||
|
@ -60,8 +68,8 @@ class FollowerAccountsController < ApplicationController
|
|||
size: @account.followers_count,
|
||||
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) },
|
||||
part_of: account_followers_url(@account),
|
||||
next: page_url(follows.next_page),
|
||||
prev: page_url(follows.prev_page)
|
||||
next: next_page_url,
|
||||
prev: prev_page_url
|
||||
)
|
||||
else
|
||||
ActivityPub::CollectionPresenter.new(
|
||||
|
|
|
@ -52,6 +52,14 @@ class FollowingAccountsController < ApplicationController
|
|||
account_following_index_url(@account, page: page) unless page.nil?
|
||||
end
|
||||
|
||||
def next_page_url
|
||||
page_url(follows.next_page) if follows.respond_to?(:next_page)
|
||||
end
|
||||
|
||||
def prev_page_url
|
||||
page_url(follows.prev_page) if follows.respond_to?(:prev_page)
|
||||
end
|
||||
|
||||
def collection_presenter
|
||||
if page_requested?
|
||||
ActivityPub::CollectionPresenter.new(
|
||||
|
@ -60,8 +68,8 @@ class FollowingAccountsController < ApplicationController
|
|||
size: @account.following_count,
|
||||
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) },
|
||||
part_of: account_following_index_url(@account),
|
||||
next: page_url(follows.next_page),
|
||||
prev: page_url(follows.prev_page)
|
||||
next: next_page_url,
|
||||
prev: prev_page_url
|
||||
)
|
||||
else
|
||||
ActivityPub::CollectionPresenter.new(
|
||||
|
|
|
@ -5,6 +5,7 @@ class RelationshipsController < ApplicationController
|
|||
|
||||
before_action :authenticate_user!
|
||||
before_action :set_accounts, only: :show
|
||||
before_action :set_relationships, only: :show
|
||||
before_action :set_body_classes
|
||||
|
||||
helper_method :following_relationship?, :followed_by_relationship?, :mutual_relationship?
|
||||
|
@ -28,6 +29,10 @@ class RelationshipsController < ApplicationController
|
|||
@accounts = RelationshipFilter.new(current_account, filter_params).results.page(params[:page]).per(40)
|
||||
end
|
||||
|
||||
def set_relationships
|
||||
@relationships = AccountRelationshipsPresenter.new(@accounts.pluck(:id), current_user.account_id)
|
||||
end
|
||||
|
||||
def form_account_batch_params
|
||||
params.require(:form_account_batch).permit(:action, account_ids: [])
|
||||
end
|
||||
|
@ -49,7 +54,9 @@ class RelationshipsController < ApplicationController
|
|||
end
|
||||
|
||||
def action_from_button
|
||||
if params[:unfollow]
|
||||
if params[:follow]
|
||||
'follow'
|
||||
elsif params[:unfollow]
|
||||
'unfollow'
|
||||
elsif params[:remove_from_followers]
|
||||
'remove_from_followers'
|
||||
|
|
|
@ -42,7 +42,7 @@ class Settings::DeletesController < Settings::BaseController
|
|||
end
|
||||
|
||||
def destroy_account!
|
||||
current_account.suspend!
|
||||
current_account.suspend!(origin: :local)
|
||||
AccountDeletionWorker.perform_async(current_user.account_id)
|
||||
sign_out
|
||||
end
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Settings
|
||||
module Exports
|
||||
class BookmarksController < BaseController
|
||||
include ExportControllerConcern
|
||||
|
||||
def index
|
||||
send_export_file
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def export_data
|
||||
@export.to_bookmarks_csv
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -35,7 +35,7 @@ module WellKnown
|
|||
end
|
||||
|
||||
def check_account_suspension
|
||||
expires_in(3.minutes, public: true) && gone if @account.suspended?
|
||||
expires_in(3.minutes, public: true) && gone if @account.suspended_permanently?
|
||||
end
|
||||
|
||||
def bad_request
|
||||
|
|
|
@ -89,6 +89,16 @@ module ApplicationHelper
|
|||
end
|
||||
end
|
||||
|
||||
def interrelationships_icon(relationships, account_id)
|
||||
if relationships.following[account_id] && relationships.followed_by[account_id]
|
||||
fa_icon('exchange', title: I18n.t('relationships.mutual'), class: 'fa-fw active passive')
|
||||
elsif relationships.following[account_id]
|
||||
fa_icon(locale_direction == 'ltr' ? 'arrow-right' : 'arrow-left', title: I18n.t('relationships.following'), class: 'fa-fw active')
|
||||
elsif relationships.followed_by[account_id]
|
||||
fa_icon(locale_direction == 'ltr' ? 'arrow-left' : 'arrow-right', title: I18n.t('relationships.followers'), class: 'fa-fw passive')
|
||||
end
|
||||
end
|
||||
|
||||
def custom_emoji_tag(custom_emoji, animate = true)
|
||||
if animate
|
||||
image_tag(custom_emoji.image.url, class: 'emojione', alt: ":#{custom_emoji.shortcode}:")
|
||||
|
|
|
@ -40,6 +40,7 @@ module SettingsHelper
|
|||
kk: 'Қазақша',
|
||||
kn: 'ಕನ್ನಡ',
|
||||
ko: '한국어',
|
||||
ku: 'سۆرانی',
|
||||
lt: 'Lietuvių',
|
||||
lv: 'Latviešu',
|
||||
mk: 'Македонски',
|
||||
|
@ -56,6 +57,8 @@ module SettingsHelper
|
|||
pt: 'Português',
|
||||
ro: 'Română',
|
||||
ru: 'Русский',
|
||||
sa: 'संस्कृतम्',
|
||||
sc: 'Sardu',
|
||||
sk: 'Slovenčina',
|
||||
sl: 'Slovenščina',
|
||||
sq: 'Shqip',
|
||||
|
@ -69,6 +72,7 @@ module SettingsHelper
|
|||
uk: 'Українська',
|
||||
ur: 'اُردُو',
|
||||
vi: 'Tiếng Việt',
|
||||
zgh: 'ⵜⴰⵎⴰⵣⵉⵖⵜ',
|
||||
'zh-CN': '简体中文',
|
||||
'zh-HK': '繁體中文(香港)',
|
||||
'zh-TW': '繁體中文(臺灣)',
|
||||
|
|
|
@ -4,8 +4,12 @@ module StatusesHelper
|
|||
EMBEDDED_CONTROLLER = 'statuses'
|
||||
EMBEDDED_ACTION = 'embed'
|
||||
|
||||
def link_to_more(url)
|
||||
link_to t('statuses.show_more'), url, class: 'load-more load-gap'
|
||||
def link_to_newer(url)
|
||||
link_to t('statuses.show_newer'), url, class: 'load-more load-gap'
|
||||
end
|
||||
|
||||
def link_to_older(url)
|
||||
link_to t('statuses.show_older'), url, class: 'load-more load-gap'
|
||||
end
|
||||
|
||||
def nothing_here(extra_classes = '')
|
||||
|
@ -117,6 +121,14 @@ module StatusesHelper
|
|||
end
|
||||
end
|
||||
|
||||
def sensitized?(status, account)
|
||||
if !account.nil? && account.id == status.account_id
|
||||
status.sensitive
|
||||
else
|
||||
status.account.sensitized? || status.sensitive
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def simplified_text(text)
|
||||
|
|
|
@ -8,3 +8,10 @@ export const focusApp = () => ({
|
|||
export const unfocusApp = () => ({
|
||||
type: APP_UNFOCUS,
|
||||
});
|
||||
|
||||
export const APP_LAYOUT_CHANGE = 'APP_LAYOUT_CHANGE';
|
||||
|
||||
export const changeLayout = layout => ({
|
||||
type: APP_LAYOUT_CHANGE,
|
||||
layout,
|
||||
});
|
||||
|
|
|
@ -151,9 +151,7 @@ export function submitCompose(routerHistory) {
|
|||
'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']),
|
||||
},
|
||||
}).then(function (response) {
|
||||
if (response.data.visibility === 'direct' && getState().getIn(['conversations', 'mounted']) <= 0 && routerHistory) {
|
||||
routerHistory.push('/timelines/direct');
|
||||
} else if (routerHistory && routerHistory.location.pathname === '/statuses/new' && window.history.state) {
|
||||
if (routerHistory && routerHistory.location.pathname === '/statuses/new' && window.history.state) {
|
||||
routerHistory.goBack();
|
||||
}
|
||||
|
||||
|
|
|
@ -37,8 +37,9 @@ export const NOTIFICATIONS_UNMOUNT = 'NOTIFICATIONS_UNMOUNT';
|
|||
|
||||
export const NOTIFICATIONS_MARK_AS_READ = 'NOTIFICATIONS_MARK_AS_READ';
|
||||
|
||||
export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
||||
export const NOTIFICATIONS_SET_BROWSER_PERMISSION = 'NOTIFICATIONS_SET_BROWSER_PERMISSION';
|
||||
export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
||||
export const NOTIFICATIONS_SET_BROWSER_PERMISSION = 'NOTIFICATIONS_SET_BROWSER_PERMISSION';
|
||||
export const NOTIFICATIONS_DISMISS_BROWSER_PERMISSION = 'NOTIFICATIONS_DISMISS_BROWSER_PERMISSION';
|
||||
|
||||
defineMessages({
|
||||
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
|
||||
|
@ -256,7 +257,7 @@ export function setupBrowserNotifications() {
|
|||
if ('Notification' in window && 'permissions' in navigator) {
|
||||
navigator.permissions.query({ name: 'notifications' }).then((status) => {
|
||||
status.onchange = () => dispatch(setBrowserPermission(Notification.permission));
|
||||
});
|
||||
}).catch(console.warn);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -283,3 +284,7 @@ export function setBrowserPermission (value) {
|
|||
value,
|
||||
};
|
||||
}
|
||||
|
||||
export const dismissBrowserPermission = () => ({
|
||||
type: NOTIFICATIONS_DISMISS_BROWSER_PERMISSION,
|
||||
});
|
||||
|
|
|
@ -137,7 +137,14 @@ export function fetchContext(id) {
|
|||
dispatch(fetchContextRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/statuses/${id}/context`).then(response => {
|
||||
dispatch(importFetchedStatuses(response.data.ancestors.concat(response.data.descendants)));
|
||||
/**
|
||||
* TODO
|
||||
* the goal here is to get a way to have all the status of a conversation somewhere
|
||||
*/
|
||||
const statusConcat = response.data.ancestors.concat(response.data.descendants);
|
||||
console.log('statusConcat', statusConcat);
|
||||
|
||||
dispatch(importFetchedStatuses(statusConcat));
|
||||
dispatch(fetchContextSuccess(id, response.data.ancestors, response.data.descendants));
|
||||
|
||||
}).catch(error => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import detectPassiveEvents from 'detect-passive-events';
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
import { scrollTop } from '../scroll';
|
||||
|
||||
export default class Column extends React.PureComponent {
|
||||
|
@ -35,9 +35,9 @@ export default class Column extends React.PureComponent {
|
|||
|
||||
componentDidMount () {
|
||||
if (this.props.bindToDocument) {
|
||||
document.addEventListener('wheel', this.handleWheel, detectPassiveEvents.hasSupport ? { passive: true } : false);
|
||||
document.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false);
|
||||
} else {
|
||||
this.node.addEventListener('wheel', this.handleWheel, detectPassiveEvents.hasSupport ? { passive: true } : false);
|
||||
this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ import IconButton from './icon_button';
|
|||
import Overlay from 'react-overlays/lib/Overlay';
|
||||
import Motion from '../features/ui/util/optional_motion';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import detectPassiveEvents from 'detect-passive-events';
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
|
||||
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;
|
||||
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
|
||||
let id = 0;
|
||||
|
||||
class DropdownMenu extends React.PureComponent {
|
||||
|
|
|
@ -9,11 +9,7 @@ export default class ModalRoot extends React.PureComponent {
|
|||
onClose: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
revealed: !!this.props.children,
|
||||
};
|
||||
|
||||
activeElement = this.state.revealed ? document.activeElement : null;
|
||||
activeElement = this.props.children ? document.activeElement : null;
|
||||
|
||||
handleKeyUp = (e) => {
|
||||
if ((e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27)
|
||||
|
@ -53,8 +49,6 @@ export default class ModalRoot extends React.PureComponent {
|
|||
this.activeElement = document.activeElement;
|
||||
|
||||
this.getSiblings().forEach(sibling => sibling.setAttribute('inert', true));
|
||||
} else if (!nextProps.children) {
|
||||
this.setState({ revealed: false });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,11 +66,6 @@ export default class ModalRoot extends React.PureComponent {
|
|||
console.error(error);
|
||||
});
|
||||
}
|
||||
if (this.props.children) {
|
||||
requestAnimationFrame(() => {
|
||||
this.setState({ revealed: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
@ -94,7 +83,6 @@ export default class ModalRoot extends React.PureComponent {
|
|||
|
||||
render () {
|
||||
const { children, onClose } = this.props;
|
||||
const { revealed } = this.state;
|
||||
const visible = !!children;
|
||||
|
||||
if (!visible) {
|
||||
|
@ -104,7 +92,7 @@ export default class ModalRoot extends React.PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className='modal-root' ref={this.setRef} style={{ opacity: revealed ? 1 : 0 }}>
|
||||
<div className='modal-root' ref={this.setRef}>
|
||||
<div style={{ pointerEvents: visible ? 'auto' : 'none' }}>
|
||||
<div role='presentation' className='modal-root__overlay' onClick={onClose} />
|
||||
<div role='dialog' className='modal-root__container'>{children}</div>
|
||||
|
|
|
@ -97,7 +97,10 @@ class Status extends ImmutablePureComponent {
|
|||
cachedMediaWidth: PropTypes.number,
|
||||
scrollKey: PropTypes.string,
|
||||
deployPictureInPicture: PropTypes.func,
|
||||
usingPiP: PropTypes.bool,
|
||||
pictureInPicture: PropTypes.shape({
|
||||
inUse: PropTypes.bool,
|
||||
available: PropTypes.bool,
|
||||
}),
|
||||
};
|
||||
|
||||
// Avoid checking props that are functions (and whose equality will always
|
||||
|
@ -108,7 +111,7 @@ class Status extends ImmutablePureComponent {
|
|||
'muted',
|
||||
'hidden',
|
||||
'unread',
|
||||
'usingPiP',
|
||||
'pictureInPicture',
|
||||
];
|
||||
|
||||
state = {
|
||||
|
@ -277,7 +280,7 @@ class Status extends ImmutablePureComponent {
|
|||
let media = null;
|
||||
let statusAvatar, prepend, rebloggedByText;
|
||||
|
||||
const { intl, hidden, featured, otherAccounts, unread, showThread, scrollKey, usingPiP } = this.props;
|
||||
const { intl, hidden, featured, otherAccounts, unread, showThread, scrollKey, pictureInPicture } = this.props;
|
||||
|
||||
let { status, account, ... |