Merge branch 'master' of https://github.com/glitch-soc/mastodon
commit
10733881f3
|
@ -6,6 +6,7 @@ aliases:
|
||||||
- image: circleci/ruby:2.7-buster-node
|
- image: circleci/ruby:2.7-buster-node
|
||||||
environment: &ruby_environment
|
environment: &ruby_environment
|
||||||
BUNDLE_APP_CONFIG: ./.bundle/
|
BUNDLE_APP_CONFIG: ./.bundle/
|
||||||
|
BUNDLE_PATH: ./vendor/bundle/
|
||||||
DB_HOST: localhost
|
DB_HOST: localhost
|
||||||
DB_USER: root
|
DB_USER: root
|
||||||
RAILS_ENV: test
|
RAILS_ENV: test
|
||||||
|
@ -138,9 +139,10 @@ jobs:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/ruby:2.7-buster-node
|
- image: circleci/ruby:2.7-buster-node
|
||||||
environment: *ruby_environment
|
environment: *ruby_environment
|
||||||
- image: circleci/postgres:10.6-alpine
|
- image: circleci/postgres:12.2
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: root
|
POSTGRES_USER: root
|
||||||
|
POSTGRES_HOST_AUTH_METHOD: trust
|
||||||
- image: circleci/redis:5-alpine
|
- image: circleci/redis:5-alpine
|
||||||
steps:
|
steps:
|
||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
|
@ -157,9 +159,10 @@ jobs:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/ruby:2.7-buster-node
|
- image: circleci/ruby:2.7-buster-node
|
||||||
environment: *ruby_environment
|
environment: *ruby_environment
|
||||||
- image: circleci/postgres:10.6-alpine
|
- image: circleci/postgres:12.2
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: root
|
POSTGRES_USER: root
|
||||||
|
POSTGRES_HOST_AUTH_METHOD: trust
|
||||||
- image: circleci/redis:5-alpine
|
- image: circleci/redis:5-alpine
|
||||||
<<: *test_steps
|
<<: *test_steps
|
||||||
|
|
||||||
|
@ -168,9 +171,10 @@ jobs:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/ruby:2.6-buster-node
|
- image: circleci/ruby:2.6-buster-node
|
||||||
environment: *ruby_environment
|
environment: *ruby_environment
|
||||||
- image: circleci/postgres:10.6-alpine
|
- image: circleci/postgres:12.2
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: root
|
POSTGRES_USER: root
|
||||||
|
POSTGRES_HOST_AUTH_METHOD: trust
|
||||||
- image: circleci/redis:5-alpine
|
- image: circleci/redis:5-alpine
|
||||||
<<: *test_steps
|
<<: *test_steps
|
||||||
|
|
||||||
|
@ -179,9 +183,10 @@ jobs:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/ruby:2.5-buster-node
|
- image: circleci/ruby:2.5-buster-node
|
||||||
environment: *ruby_environment
|
environment: *ruby_environment
|
||||||
- image: circleci/postgres:10.6-alpine
|
- image: circleci/postgres:12.2
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: root
|
POSTGRES_USER: root
|
||||||
|
POSTGRES_HOST_AUTH_METHOD: trust
|
||||||
- image: circleci/redis:5-alpine
|
- image: circleci/redis:5-alpine
|
||||||
<<: *test_steps
|
<<: *test_steps
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2.6.5
|
2.6.6
|
||||||
|
|
73
CHANGELOG.md
73
CHANGELOG.md
|
@ -3,6 +3,79 @@ Changelog
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [v3.1.3] - 2020-04-05
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add ability to filter audit log in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/13381))
|
||||||
|
- Add titles to warning presets in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/13252))
|
||||||
|
- Add option to include resolved DNS records when blacklisting e-mail domains in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/13254))
|
||||||
|
- Add ability to delete files uploaded for settings in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13192))
|
||||||
|
- Add sorting by username, creation and last activity in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13076))
|
||||||
|
- Add explanation as to why unlocked accounts may have follow requests in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13385))
|
||||||
|
- Add link to bookmarks to dropdown in web UI ([mayaeh](https://github.com/tootsuite/mastodon/pull/13273))
|
||||||
|
- Add support for links to statuses in announcements to be opened in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13212), [ThibG](https://github.com/tootsuite/mastodon/pull/13250))
|
||||||
|
- Add tooltips to audio/video player buttons in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/13203))
|
||||||
|
- Add submit button to the top of preferences pages ([guigeekz](https://github.com/tootsuite/mastodon/pull/13068))
|
||||||
|
- Add specific rate limits for posting, following and reporting ([Gargron](https://github.com/tootsuite/mastodon/pull/13172), [Gargron](https://github.com/tootsuite/mastodon/pull/13390))
|
||||||
|
- 300 posts every 3 hours
|
||||||
|
- 400 follows or follow requests every 24 hours
|
||||||
|
- 400 reports every 24 hours
|
||||||
|
- Add federation support for the "hide network" preference ([ThibG](https://github.com/tootsuite/mastodon/pull/11673))
|
||||||
|
- Add `--skip-media-remove` option to `tootctl statuses remove` ([tateisu](https://github.com/tootsuite/mastodon/pull/13080))
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Change design of polls in web UI** ([Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/13257), [ThibG](https://github.com/tootsuite/mastodon/pull/13313))
|
||||||
|
- Change status click areas in web UI to be bigger ([ariasuni](https://github.com/tootsuite/mastodon/pull/13327))
|
||||||
|
- **Change `tootctl media remove-orphans` to work for all classes** ([Gargron](https://github.com/tootsuite/mastodon/pull/13316))
|
||||||
|
- **Change local media attachments to perform heavy processing asynchronously** ([Gargron](https://github.com/tootsuite/mastodon/pull/13210))
|
||||||
|
- Change video uploads to always be converted to H264/MP4 ([Gargron](https://github.com/tootsuite/mastodon/pull/13220), [ThibG](https://github.com/tootsuite/mastodon/pull/13239), [ThibG](https://github.com/tootsuite/mastodon/pull/13242))
|
||||||
|
- Change video uploads to enforce certain limits ([Gargron](https://github.com/tootsuite/mastodon/pull/13218))
|
||||||
|
- Dimensions smaller than 1920x1200px
|
||||||
|
- Frame rate at most 60fps
|
||||||
|
- Change the tooltip "Toggle visibility" to "Hide media" in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/13199))
|
||||||
|
- Change description of privacy levels to be more intuitive in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/13197))
|
||||||
|
- Change GIF label to be displayed even when autoplay is enabled in web UI ([koyuawsmbrtn](https://github.com/tootsuite/mastodon/pull/13209))
|
||||||
|
- Change the string "Hide everything from …" to "Block domain …" in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13178), [mayaeh](https://github.com/tootsuite/mastodon/pull/13221))
|
||||||
|
- Change wording of media display preferences to be more intuitive ([ariasuni](https://github.com/tootsuite/mastodon/pull/13198))
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- `POST /api/v1/media` → `POST /api/v2/media` ([Gargron](https://github.com/tootsuite/mastodon/pull/13210))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix `tootctl media remove-orphans` ignoring `PAPERCLIP_ROOT_PATH` ([Gargron](https://github.com/tootsuite/mastodon/pull/13375))
|
||||||
|
- Fix returning results when searching for URL with non-zero offset ([Gargron](https://github.com/tootsuite/mastodon/pull/13377))
|
||||||
|
- Fix pinning a column in web UI sometimes redirecting out of web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/13376))
|
||||||
|
- Fix background jobs not using locks like they are supposed to ([Gargron](https://github.com/tootsuite/mastodon/pull/13361))
|
||||||
|
- Fix content warning being unnecessarily cleared when hiding content warning input in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13348))
|
||||||
|
- Fix "Show more" not switching to "Show less" on public pages ([ThibG](https://github.com/tootsuite/mastodon/pull/13174))
|
||||||
|
- Fix import overwrite option not being selectable ([noellabo](https://github.com/tootsuite/mastodon/pull/13347))
|
||||||
|
- Fix wrong color for ellipsis in boost confirmation dialog in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/13355))
|
||||||
|
- Fix unnecessary unfollowing when importing follows with overwrite option ([noellabo](https://github.com/tootsuite/mastodon/pull/13350))
|
||||||
|
- Fix 404 and 410 API errors being silently discarded in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13279))
|
||||||
|
- Fix OCR not working on Safari because of unsupported worker-src CSP ([ThibG](https://github.com/tootsuite/mastodon/pull/13323))
|
||||||
|
- Fix media not being marked sensitive when a content warning is set with no text ([ThibG](https://github.com/tootsuite/mastodon/pull/13277))
|
||||||
|
- Fix crash after deleting announcements in web UI ([codesections](https://github.com/tootsuite/mastodon/pull/13283), [ThibG](https://github.com/tootsuite/mastodon/pull/13312))
|
||||||
|
- Fix bookmarks not being searchable ([Kjwon15](https://github.com/tootsuite/mastodon/pull/13271), [noellabo](https://github.com/tootsuite/mastodon/pull/13293))
|
||||||
|
- Fix reported accounts not being whitelisted from further spam checks when resolving a spam check report ([ThibG](https://github.com/tootsuite/mastodon/pull/13289))
|
||||||
|
- Fix web UI crash in single-column mode on prehistoric browsers ([ThibG](https://github.com/tootsuite/mastodon/pull/13267))
|
||||||
|
- Fix some timeouts when searching for URLs ([ThibG](https://github.com/tootsuite/mastodon/pull/13253))
|
||||||
|
- Fix detailed view of direct messages displaying a 0 boost count in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13244))
|
||||||
|
- Fix regression in “Edit media” modal in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13243))
|
||||||
|
- Fix public posts from silenced accounts not being changed to unlisted visibility ([ThibG](https://github.com/tootsuite/mastodon/pull/13096))
|
||||||
|
- Fix error when searching for URLs that contain the mention syntax ([ThibG](https://github.com/tootsuite/mastodon/pull/13151))
|
||||||
|
- Fix text area above/right of emoji picker being accidentally clickable in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/13148))
|
||||||
|
- Fix too large announcements not being scrollable in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13211))
|
||||||
|
- Fix `tootctl media remove-orphans` crashing when encountering invalid media ([ThibG](https://github.com/tootsuite/mastodon/pull/13170))
|
||||||
|
- Fix installation failing when Redis password contains special characters ([ThibG](https://github.com/tootsuite/mastodon/pull/13156))
|
||||||
|
- Fix announcements with fully-qualified mentions to local users crashing web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13164))
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Fix re-sending of e-mail confirmation not being rate limited ([Gargron](https://github.com/tootsuite/mastodon/pull/13360))
|
||||||
|
|
||||||
## [v3.1.2] - 2020-02-27
|
## [v3.1.2] - 2020-02-27
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
|
|
@ -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 \
|
||||||
|
@ -38,8 +38,8 @@ RUN apt update && \
|
||||||
make -j$(nproc) > /dev/null && \
|
make -j$(nproc) > /dev/null && \
|
||||||
make install_bin install_include install_lib
|
make install_bin install_include install_lib
|
||||||
|
|
||||||
# Install ruby
|
# Install Ruby
|
||||||
ENV RUBY_VER="2.6.5"
|
ENV RUBY_VER="2.6.6"
|
||||||
ENV CPPFLAGS="-I/opt/jemalloc/include"
|
ENV CPPFLAGS="-I/opt/jemalloc/include"
|
||||||
ENV LDFLAGS="-L/opt/jemalloc/lib/"
|
ENV LDFLAGS="-L/opt/jemalloc/lib/"
|
||||||
RUN apt update && \
|
RUN apt update && \
|
||||||
|
|
32
Gemfile
32
Gemfile
|
@ -1,12 +1,12 @@
|
||||||
# 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'
|
||||||
|
|
||||||
gem 'puma', '~> 4.3'
|
gem 'puma', '~> 4.3'
|
||||||
gem 'rails', '~> 5.2.4'
|
gem 'rails', '~> 5.2.4.2'
|
||||||
gem 'sprockets', '~> 3.7.2'
|
gem 'sprockets', '~> 3.7.2'
|
||||||
gem 'thor', '~> 0.20'
|
gem 'thor', '~> 0.20'
|
||||||
gem 'rack', '~> 2.2.2'
|
gem 'rack', '~> 2.2.2'
|
||||||
|
@ -20,7 +20,7 @@ gem 'makara', '~> 0.4'
|
||||||
gem 'pghero', '~> 2.4'
|
gem 'pghero', '~> 2.4'
|
||||||
gem 'dotenv-rails', '~> 2.7'
|
gem 'dotenv-rails', '~> 2.7'
|
||||||
|
|
||||||
gem 'aws-sdk-s3', '~> 1.60', require: false
|
gem 'aws-sdk-s3', '~> 1.61', require: false
|
||||||
gem 'fog-core', '<= 2.1.0'
|
gem 'fog-core', '<= 2.1.0'
|
||||||
gem 'fog-openstack', '~> 0.3', require: false
|
gem 'fog-openstack', '~> 0.3', require: false
|
||||||
gem 'paperclip', '~> 6.0'
|
gem 'paperclip', '~> 6.0'
|
||||||
|
@ -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'
|
||||||
|
|
||||||
|
@ -48,8 +48,8 @@ gem 'omniauth-cas', '~> 1.1'
|
||||||
gem 'omniauth-saml', '~> 1.10'
|
gem 'omniauth-saml', '~> 1.10'
|
||||||
gem 'omniauth', '~> 1.9'
|
gem 'omniauth', '~> 1.9'
|
||||||
|
|
||||||
gem 'discard', '~> 1.1'
|
gem 'discard', '~> 1.2'
|
||||||
gem 'doorkeeper', '~> 5.2'
|
gem 'doorkeeper', '~> 5.3'
|
||||||
gem 'fast_blank', '~> 1.0'
|
gem 'fast_blank', '~> 1.0'
|
||||||
gem 'fastimage'
|
gem 'fastimage'
|
||||||
gem 'goldfinger', '~> 2.1'
|
gem 'goldfinger', '~> 2.1'
|
||||||
|
@ -69,7 +69,7 @@ gem 'nilsimsa', git: 'https://github.com/witgo/nilsimsa', ref: 'fd184883048b922b
|
||||||
gem 'nokogiri', '~> 1.10'
|
gem 'nokogiri', '~> 1.10'
|
||||||
gem 'nsa', '~> 0.2'
|
gem 'nsa', '~> 0.2'
|
||||||
gem 'oj', '~> 3.10'
|
gem 'oj', '~> 3.10'
|
||||||
gem 'ox', '~> 2.12'
|
gem 'ox', '~> 2.13'
|
||||||
gem 'parslet'
|
gem 'parslet'
|
||||||
gem 'parallel', '~> 1.19'
|
gem 'parallel', '~> 1.19'
|
||||||
gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
|
gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
|
||||||
|
@ -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'
|
||||||
|
@ -92,9 +92,9 @@ gem 'simple-navigation', '~> 4.1'
|
||||||
gem 'simple_form', '~> 5.0'
|
gem 'simple_form', '~> 5.0'
|
||||||
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
|
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
|
||||||
gem 'stoplight', '~> 2.2.0'
|
gem 'stoplight', '~> 2.2.0'
|
||||||
gem 'strong_migrations', '~> 0.5'
|
gem 'strong_migrations', '~> 0.6'
|
||||||
gem 'tty-command', '~> 0.9', require: false
|
gem 'tty-command', '~> 0.9', require: false
|
||||||
gem 'tty-prompt', '~> 0.20', require: false
|
gem 'tty-prompt', '~> 0.21', require: false
|
||||||
gem 'twitter-text', '~> 1.14'
|
gem 'twitter-text', '~> 1.14'
|
||||||
gem 'tzinfo-data', '~> 1.2019'
|
gem 'tzinfo-data', '~> 1.2019'
|
||||||
gem 'webpacker', '~> 4.2'
|
gem 'webpacker', '~> 4.2'
|
||||||
|
@ -112,7 +112,7 @@ group :development, :test do
|
||||||
gem 'i18n-tasks', '~> 0.9', require: false
|
gem 'i18n-tasks', '~> 0.9', require: false
|
||||||
gem 'pry-byebug', '~> 3.8'
|
gem 'pry-byebug', '~> 3.8'
|
||||||
gem 'pry-rails', '~> 0.3'
|
gem 'pry-rails', '~> 0.3'
|
||||||
gem 'rspec-rails', '~> 3.9'
|
gem 'rspec-rails', '~> 4.0'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :production, :test do
|
group :production, :test do
|
||||||
|
@ -122,19 +122,19 @@ end
|
||||||
group :test do
|
group :test do
|
||||||
gem 'capybara', '~> 3.31'
|
gem 'capybara', '~> 3.31'
|
||||||
gem 'climate_control', '~> 0.2'
|
gem 'climate_control', '~> 0.2'
|
||||||
gem 'faker', '~> 2.10'
|
gem 'faker', '~> 2.11'
|
||||||
gem 'microformats', '~> 4.2'
|
gem 'microformats', '~> 4.2'
|
||||||
gem 'rails-controller-testing', '~> 1.0'
|
gem 'rails-controller-testing', '~> 1.0'
|
||||||
gem 'rspec-sidekiq', '~> 3.0'
|
gem 'rspec-sidekiq', '~> 3.0'
|
||||||
gem 'simplecov', '~> 0.18', require: false
|
gem 'simplecov', '~> 0.18', require: false
|
||||||
gem 'webmock', '~> 3.8'
|
gem 'webmock', '~> 3.8'
|
||||||
gem 'parallel_tests', '~> 2.30'
|
gem 'parallel_tests', '~> 2.32'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'active_record_query_trace', '~> 1.7'
|
gem 'active_record_query_trace', '~> 1.7'
|
||||||
gem 'annotate', '~> 3.0'
|
gem 'annotate', '~> 3.0'
|
||||||
gem 'better_errors', '~> 2.5'
|
gem 'better_errors', '~> 2.6'
|
||||||
gem 'binding_of_caller', '~> 0.7'
|
gem 'binding_of_caller', '~> 0.7'
|
||||||
gem 'bullet', '~> 6.1'
|
gem 'bullet', '~> 6.1'
|
||||||
gem 'letter_opener', '~> 1.7'
|
gem 'letter_opener', '~> 1.7'
|
||||||
|
@ -142,10 +142,10 @@ group :development do
|
||||||
gem 'memory_profiler'
|
gem 'memory_profiler'
|
||||||
gem 'rubocop', '~> 0.79', require: false
|
gem 'rubocop', '~> 0.79', require: false
|
||||||
gem 'rubocop-rails', '~> 2.4', require: false
|
gem 'rubocop-rails', '~> 2.4', require: false
|
||||||
gem 'brakeman', '~> 4.7', require: false
|
gem 'brakeman', '~> 4.8', 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'
|
||||||
|
|
242
Gemfile.lock
242
Gemfile.lock
|
@ -31,25 +31,25 @@ GIT
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (5.2.4.1)
|
actioncable (5.2.4.2)
|
||||||
actionpack (= 5.2.4.1)
|
actionpack (= 5.2.4.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailer (5.2.4.1)
|
actionmailer (5.2.4.2)
|
||||||
actionpack (= 5.2.4.1)
|
actionpack (= 5.2.4.2)
|
||||||
actionview (= 5.2.4.1)
|
actionview (= 5.2.4.2)
|
||||||
activejob (= 5.2.4.1)
|
activejob (= 5.2.4.2)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (5.2.4.1)
|
actionpack (5.2.4.2)
|
||||||
actionview (= 5.2.4.1)
|
actionview (= 5.2.4.2)
|
||||||
activesupport (= 5.2.4.1)
|
activesupport (= 5.2.4.2)
|
||||||
rack (~> 2.0, >= 2.0.8)
|
rack (~> 2.0, >= 2.0.8)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||||
actionview (5.2.4.1)
|
actionview (5.2.4.2)
|
||||||
activesupport (= 5.2.4.1)
|
activesupport (= 5.2.4.2)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
|
@ -60,20 +60,20 @@ GEM
|
||||||
case_transform (>= 0.2)
|
case_transform (>= 0.2)
|
||||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||||
active_record_query_trace (1.7)
|
active_record_query_trace (1.7)
|
||||||
activejob (5.2.4.1)
|
activejob (5.2.4.2)
|
||||||
activesupport (= 5.2.4.1)
|
activesupport (= 5.2.4.2)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (5.2.4.1)
|
activemodel (5.2.4.2)
|
||||||
activesupport (= 5.2.4.1)
|
activesupport (= 5.2.4.2)
|
||||||
activerecord (5.2.4.1)
|
activerecord (5.2.4.2)
|
||||||
activemodel (= 5.2.4.1)
|
activemodel (= 5.2.4.2)
|
||||||
activesupport (= 5.2.4.1)
|
activesupport (= 5.2.4.2)
|
||||||
arel (>= 9.0)
|
arel (>= 9.0)
|
||||||
activestorage (5.2.4.1)
|
activestorage (5.2.4.2)
|
||||||
actionpack (= 5.2.4.1)
|
actionpack (= 5.2.4.2)
|
||||||
activerecord (= 5.2.4.1)
|
activerecord (= 5.2.4.2)
|
||||||
marcel (~> 0.3.1)
|
marcel (~> 0.3.1)
|
||||||
activesupport (5.2.4.1)
|
activesupport (5.2.4.2)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
|
@ -92,23 +92,23 @@ GEM
|
||||||
av (0.9.0)
|
av (0.9.0)
|
||||||
cocaine (~> 0.5.3)
|
cocaine (~> 0.5.3)
|
||||||
aws-eventstream (1.0.3)
|
aws-eventstream (1.0.3)
|
||||||
aws-partitions (1.261.0)
|
aws-partitions (1.286.0)
|
||||||
aws-sdk-core (3.86.0)
|
aws-sdk-core (3.92.0)
|
||||||
aws-eventstream (~> 1.0, >= 1.0.2)
|
aws-eventstream (~> 1.0, >= 1.0.2)
|
||||||
aws-partitions (~> 1, >= 1.239.0)
|
aws-partitions (~> 1, >= 1.239.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
jmespath (~> 1.0)
|
jmespath (~> 1.0)
|
||||||
aws-sdk-kms (1.27.0)
|
aws-sdk-kms (1.30.0)
|
||||||
aws-sdk-core (~> 3, >= 3.71.0)
|
aws-sdk-core (~> 3, >= 3.71.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sdk-s3 (1.60.1)
|
aws-sdk-s3 (1.61.1)
|
||||||
aws-sdk-core (~> 3, >= 3.83.0)
|
aws-sdk-core (~> 3, >= 3.83.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sigv4 (1.1.0)
|
aws-sigv4 (1.1.1)
|
||||||
aws-eventstream (~> 1.0, >= 1.0.2)
|
aws-eventstream (~> 1.0, >= 1.0.2)
|
||||||
bcrypt (3.1.12)
|
bcrypt (3.1.12)
|
||||||
better_errors (2.5.1)
|
better_errors (2.6.0)
|
||||||
coderay (>= 1.0.0)
|
coderay (>= 1.0.0)
|
||||||
erubi (>= 1.0.0)
|
erubi (>= 1.0.0)
|
||||||
rack (>= 0.9.0)
|
rack (>= 0.9.0)
|
||||||
|
@ -116,10 +116,10 @@ GEM
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
blurhash (0.1.4)
|
blurhash (0.1.4)
|
||||||
ffi (~> 1.10.0)
|
ffi (~> 1.10.0)
|
||||||
bootsnap (1.4.5)
|
bootsnap (1.4.6)
|
||||||
msgpack (~> 1.0)
|
msgpack (~> 1.0)
|
||||||
brakeman (4.7.2)
|
brakeman (4.8.0)
|
||||||
browser (3.0.3)
|
browser (4.0.0)
|
||||||
builder (3.2.4)
|
builder (3.2.4)
|
||||||
bullet (6.1.0)
|
bullet (6.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
|
@ -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,13 +160,13 @@ 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)
|
||||||
climate_control (>= 0.0.3, < 1.0)
|
climate_control (>= 0.0.3, < 1.0)
|
||||||
coderay (1.1.2)
|
coderay (1.1.2)
|
||||||
concurrent-ruby (1.1.5)
|
concurrent-ruby (1.1.6)
|
||||||
connection_pool (2.2.2)
|
connection_pool (2.2.2)
|
||||||
crack (0.4.3)
|
crack (0.4.3)
|
||||||
safe_yaml (~> 1.0.0)
|
safe_yaml (~> 1.0.0)
|
||||||
|
@ -190,12 +190,12 @@ GEM
|
||||||
devise (>= 4.0.0)
|
devise (>= 4.0.0)
|
||||||
rpam2 (~> 4.0)
|
rpam2 (~> 4.0)
|
||||||
diff-lcs (1.3)
|
diff-lcs (1.3)
|
||||||
discard (1.1.0)
|
discard (1.2.0)
|
||||||
activerecord (>= 4.2, < 7)
|
activerecord (>= 4.2, < 7)
|
||||||
docile (1.3.2)
|
docile (1.3.2)
|
||||||
domain_name (0.5.20190701)
|
domain_name (0.5.20190701)
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
doorkeeper (5.2.3)
|
doorkeeper (5.3.1)
|
||||||
railties (>= 5)
|
railties (>= 5)
|
||||||
dotenv (2.7.5)
|
dotenv (2.7.5)
|
||||||
dotenv-rails (2.7.5)
|
dotenv-rails (2.7.5)
|
||||||
|
@ -214,11 +214,11 @@ 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)
|
||||||
faker (2.10.1)
|
faker (2.11.0)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
faraday (0.17.3)
|
faraday (0.17.3)
|
||||||
multipart-post (>= 1.2, < 3)
|
multipart-post (>= 1.2, < 3)
|
||||||
|
@ -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)
|
||||||
|
@ -287,7 +287,7 @@ GEM
|
||||||
rainbow (>= 2.0.0)
|
rainbow (>= 2.0.0)
|
||||||
i18n (1.8.2)
|
i18n (1.8.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
i18n-tasks (0.9.30)
|
i18n-tasks (0.9.31)
|
||||||
activesupport (>= 4.0.2)
|
activesupport (>= 4.0.2)
|
||||||
ast (>= 2.1.0)
|
ast (>= 2.1.0)
|
||||||
erubi
|
erubi
|
||||||
|
@ -299,19 +299,19 @@ GEM
|
||||||
terminal-table (>= 1.5.1)
|
terminal-table (>= 1.5.1)
|
||||||
idn-ruby (0.1.0)
|
idn-ruby (0.1.0)
|
||||||
ipaddress (0.8.3)
|
ipaddress (0.8.3)
|
||||||
iso-639 (0.2.8)
|
iso-639 (0.3.5)
|
||||||
jaro_winkler (1.5.4)
|
jaro_winkler (1.5.4)
|
||||||
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.2)
|
||||||
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)
|
||||||
rdf (~> 3.1)
|
rdf (~> 3.1)
|
||||||
json-ld-preloaded (3.1.0)
|
json-ld-preloaded (3.1.2)
|
||||||
json-ld (~> 3.1)
|
json-ld (~> 3.1)
|
||||||
rdf (~> 3.1)
|
rdf (~> 3.1)
|
||||||
jsonapi-renderer (0.2.2)
|
jsonapi-renderer (0.2.2)
|
||||||
|
@ -361,11 +361,11 @@ GEM
|
||||||
mime-types (3.3.1)
|
mime-types (3.3.1)
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2019.1009)
|
mime-types-data (3.2019.1009)
|
||||||
mimemagic (0.3.3)
|
mimemagic (0.3.4)
|
||||||
mini_mime (1.0.2)
|
mini_mime (1.0.2)
|
||||||
mini_portile2 (2.4.0)
|
mini_portile2 (2.4.0)
|
||||||
minitest (5.14.0)
|
minitest (5.14.0)
|
||||||
msgpack (1.3.1)
|
msgpack (1.3.3)
|
||||||
multi_json (1.14.1)
|
multi_json (1.14.1)
|
||||||
multipart-post (2.1.1)
|
multipart-post (2.1.1)
|
||||||
necromancer (0.5.1)
|
necromancer (0.5.1)
|
||||||
|
@ -374,7 +374,7 @@ GEM
|
||||||
net-ssh (>= 2.6.5, < 6.0.0)
|
net-ssh (>= 2.6.5, < 6.0.0)
|
||||||
net-ssh (5.2.0)
|
net-ssh (5.2.0)
|
||||||
nio4r (2.5.2)
|
nio4r (2.5.2)
|
||||||
nokogiri (1.10.8)
|
nokogiri (1.10.9)
|
||||||
mini_portile2 (~> 2.4.0)
|
mini_portile2 (~> 2.4.0)
|
||||||
nokogumbo (2.0.1)
|
nokogumbo (2.0.1)
|
||||||
nokogiri (~> 1.8, >= 1.8.4)
|
nokogiri (~> 1.8, >= 1.8.4)
|
||||||
|
@ -383,9 +383,9 @@ GEM
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
sidekiq (>= 3.5)
|
sidekiq (>= 3.5)
|
||||||
statsd-ruby (~> 1.4, >= 1.4.0)
|
statsd-ruby (~> 1.4, >= 1.4.0)
|
||||||
oj (3.10.1)
|
oj (3.10.5)
|
||||||
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)
|
||||||
|
@ -395,7 +395,7 @@ GEM
|
||||||
omniauth (~> 1.3, >= 1.3.2)
|
omniauth (~> 1.3, >= 1.3.2)
|
||||||
ruby-saml (~> 1.7)
|
ruby-saml (~> 1.7)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
ox (2.12.1)
|
ox (2.13.2)
|
||||||
paperclip (6.0.0)
|
paperclip (6.0.0)
|
||||||
activemodel (>= 4.2.0)
|
activemodel (>= 4.2.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
|
@ -406,15 +406,15 @@ GEM
|
||||||
av (~> 0.9.0)
|
av (~> 0.9.0)
|
||||||
paperclip (>= 2.5.2)
|
paperclip (>= 2.5.2)
|
||||||
parallel (1.19.1)
|
parallel (1.19.1)
|
||||||
parallel_tests (2.30.1)
|
parallel_tests (2.32.0)
|
||||||
parallel
|
parallel
|
||||||
parser (2.7.0.2)
|
parser (2.7.0.5)
|
||||||
ast (~> 2.4.0)
|
ast (~> 2.4.0)
|
||||||
parslet (1.8.2)
|
parslet (1.8.2)
|
||||||
pastel (0.7.3)
|
pastel (0.7.3)
|
||||||
equatable (~> 0.6)
|
equatable (~> 0.6)
|
||||||
tty-color (~> 0.5)
|
tty-color (~> 0.5)
|
||||||
pg (1.2.2)
|
pg (1.2.3)
|
||||||
pghero (2.4.1)
|
pghero (2.4.1)
|
||||||
activerecord (>= 5)
|
activerecord (>= 5)
|
||||||
pkg-config (1.4.1)
|
pkg-config (1.4.1)
|
||||||
|
@ -445,24 +445,24 @@ 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
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (5.2.4.1)
|
rails (5.2.4.2)
|
||||||
actioncable (= 5.2.4.1)
|
actioncable (= 5.2.4.2)
|
||||||
actionmailer (= 5.2.4.1)
|
actionmailer (= 5.2.4.2)
|
||||||
actionpack (= 5.2.4.1)
|
actionpack (= 5.2.4.2)
|
||||||
actionview (= 5.2.4.1)
|
actionview (= 5.2.4.2)
|
||||||
activejob (= 5.2.4.1)
|
activejob (= 5.2.4.2)
|
||||||
activemodel (= 5.2.4.1)
|
activemodel (= 5.2.4.2)
|
||||||
activerecord (= 5.2.4.1)
|
activerecord (= 5.2.4.2)
|
||||||
activestorage (= 5.2.4.1)
|
activestorage (= 5.2.4.2)
|
||||||
activesupport (= 5.2.4.1)
|
activesupport (= 5.2.4.2)
|
||||||
bundler (>= 1.3.0)
|
bundler (>= 1.3.0)
|
||||||
railties (= 5.2.4.1)
|
railties (= 5.2.4.2)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-controller-testing (1.0.4)
|
rails-controller-testing (1.0.4)
|
||||||
actionpack (>= 5.0.1.x)
|
actionpack (>= 5.0.1.x)
|
||||||
|
@ -478,9 +478,9 @@ GEM
|
||||||
railties (>= 5.0, < 6)
|
railties (>= 5.0, < 6)
|
||||||
rails-settings-cached (0.6.6)
|
rails-settings-cached (0.6.6)
|
||||||
rails (>= 4.2.0)
|
rails (>= 4.2.0)
|
||||||
railties (5.2.4.1)
|
railties (5.2.4.2)
|
||||||
actionpack (= 5.2.4.1)
|
actionpack (= 5.2.4.2)
|
||||||
activesupport (= 5.2.4.1)
|
activesupport (= 5.2.4.2)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.19.0, < 2.0)
|
thor (>= 0.19.0, < 2.0)
|
||||||
|
@ -523,26 +523,26 @@ GEM
|
||||||
chunky_png (~> 1.0)
|
chunky_png (~> 1.0)
|
||||||
rqrcode_core (~> 0.1)
|
rqrcode_core (~> 0.1)
|
||||||
rqrcode_core (0.1.1)
|
rqrcode_core (0.1.1)
|
||||||
rspec-core (3.9.0)
|
rspec-core (3.9.1)
|
||||||
rspec-support (~> 3.9.0)
|
rspec-support (~> 3.9.1)
|
||||||
rspec-expectations (3.9.0)
|
rspec-expectations (3.9.1)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.9.0)
|
rspec-support (~> 3.9.0)
|
||||||
rspec-mocks (3.9.0)
|
rspec-mocks (3.9.1)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.9.0)
|
rspec-support (~> 3.9.0)
|
||||||
rspec-rails (3.9.0)
|
rspec-rails (4.0.0)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 4.2)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 4.2)
|
||||||
railties (>= 3.0)
|
railties (>= 4.2)
|
||||||
rspec-core (~> 3.9.0)
|
rspec-core (~> 3.9)
|
||||||
rspec-expectations (~> 3.9.0)
|
rspec-expectations (~> 3.9)
|
||||||
rspec-mocks (~> 3.9.0)
|
rspec-mocks (~> 3.9)
|
||||||
rspec-support (~> 3.9.0)
|
rspec-support (~> 3.9)
|
||||||
rspec-sidekiq (3.0.3)
|
rspec-sidekiq (3.0.3)
|
||||||
rspec-core (~> 3.0, >= 3.0.0)
|
rspec-core (~> 3.0, >= 3.0.0)
|
||||||
sidekiq (>= 2.4.0)
|
sidekiq (>= 2.4.0)
|
||||||
rspec-support (3.9.0)
|
rspec-support (3.9.2)
|
||||||
rubocop (0.79.0)
|
rubocop (0.79.0)
|
||||||
jaro_winkler (~> 1.5.1)
|
jaro_winkler (~> 1.5.1)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
|
@ -556,38 +556,40 @@ 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.21)
|
||||||
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.5)
|
||||||
docile (~> 1.1)
|
docile (~> 1.1)
|
||||||
simplecov-html (~> 0.11)
|
simplecov-html (~> 0.11)
|
||||||
simplecov-html (0.12.0)
|
simplecov-html (0.12.2)
|
||||||
sprockets (3.7.2)
|
sprockets (3.7.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
rack (> 1, < 3)
|
rack (> 1, < 3)
|
||||||
|
@ -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)
|
||||||
|
@ -603,7 +605,7 @@ GEM
|
||||||
stoplight (2.2.0)
|
stoplight (2.2.0)
|
||||||
streamio-ffmpeg (3.0.2)
|
streamio-ffmpeg (3.0.2)
|
||||||
multi_json (~> 1.8)
|
multi_json (~> 1.8)
|
||||||
strong_migrations (0.5.1)
|
strong_migrations (0.6.2)
|
||||||
activerecord (>= 5)
|
activerecord (>= 5)
|
||||||
temple (0.8.2)
|
temple (0.8.2)
|
||||||
terminal-table (1.8.0)
|
terminal-table (1.8.0)
|
||||||
|
@ -614,11 +616,11 @@ GEM
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
thwait (0.1.0)
|
thwait (0.1.0)
|
||||||
tilt (2.0.10)
|
tilt (2.0.10)
|
||||||
tty-color (0.5.0)
|
tty-color (0.5.1)
|
||||||
tty-command (0.9.0)
|
tty-command (0.9.0)
|
||||||
pastel (~> 0.7.0)
|
pastel (~> 0.7.0)
|
||||||
tty-cursor (0.7.0)
|
tty-cursor (0.7.1)
|
||||||
tty-prompt (0.20.0)
|
tty-prompt (0.21.0)
|
||||||
necromancer (~> 0.5.0)
|
necromancer (~> 0.5.0)
|
||||||
pastel (~> 0.7.0)
|
pastel (~> 0.7.0)
|
||||||
tty-reader (~> 0.7.0)
|
tty-reader (~> 0.7.0)
|
||||||
|
@ -626,10 +628,10 @@ GEM
|
||||||
tty-cursor (~> 0.7)
|
tty-cursor (~> 0.7)
|
||||||
tty-screen (~> 0.7)
|
tty-screen (~> 0.7)
|
||||||
wisper (~> 2.0.0)
|
wisper (~> 2.0.0)
|
||||||
tty-screen (0.7.0)
|
tty-screen (0.7.1)
|
||||||
twitter-text (1.14.7)
|
twitter-text (1.14.7)
|
||||||
unf (~> 0.1.0)
|
unf (~> 0.1.0)
|
||||||
tzinfo (1.2.6)
|
tzinfo (1.2.7)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
tzinfo-data (1.2019.3)
|
tzinfo-data (1.2019.3)
|
||||||
tzinfo (>= 1.0.0)
|
tzinfo (>= 1.0.0)
|
||||||
|
@ -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)
|
||||||
|
@ -666,35 +668,35 @@ DEPENDENCIES
|
||||||
active_record_query_trace (~> 1.7)
|
active_record_query_trace (~> 1.7)
|
||||||
addressable (~> 2.7)
|
addressable (~> 2.7)
|
||||||
annotate (~> 3.0)
|
annotate (~> 3.0)
|
||||||
aws-sdk-s3 (~> 1.60)
|
aws-sdk-s3 (~> 1.61)
|
||||||
better_errors (~> 2.5)
|
better_errors (~> 2.6)
|
||||||
binding_of_caller (~> 0.7)
|
binding_of_caller (~> 0.7)
|
||||||
blurhash (~> 0.1)
|
blurhash (~> 0.1)
|
||||||
bootsnap (~> 1.4)
|
bootsnap (~> 1.4)
|
||||||
brakeman (~> 4.7)
|
brakeman (~> 4.8)
|
||||||
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
|
||||||
devise (~> 4.7)
|
devise (~> 4.7)
|
||||||
devise-two-factor (~> 3.1)
|
devise-two-factor (~> 3.1)
|
||||||
devise_pam_authenticatable2 (~> 9.2)
|
devise_pam_authenticatable2 (~> 9.2)
|
||||||
discard (~> 1.1)
|
discard (~> 1.2)
|
||||||
doorkeeper (~> 5.2)
|
doorkeeper (~> 5.3)
|
||||||
dotenv-rails (~> 2.7)
|
dotenv-rails (~> 2.7)
|
||||||
e2mmap (~> 0.1.0)
|
e2mmap (~> 0.1.0)
|
||||||
fabrication (~> 2.21)
|
fabrication (~> 2.21)
|
||||||
faker (~> 2.10)
|
faker (~> 2.11)
|
||||||
fast_blank (~> 1.0)
|
fast_blank (~> 1.0)
|
||||||
fastimage
|
fastimage
|
||||||
fog-core (<= 2.1.0)
|
fog-core (<= 2.1.0)
|
||||||
|
@ -732,11 +734,11 @@ DEPENDENCIES
|
||||||
omniauth (~> 1.9)
|
omniauth (~> 1.9)
|
||||||
omniauth-cas (~> 1.1)
|
omniauth-cas (~> 1.1)
|
||||||
omniauth-saml (~> 1.10)
|
omniauth-saml (~> 1.10)
|
||||||
ox (~> 2.12)
|
ox (~> 2.13)
|
||||||
paperclip (~> 6.0)
|
paperclip (~> 6.0)
|
||||||
paperclip-av-transcoder (~> 0.6)
|
paperclip-av-transcoder (~> 0.6)
|
||||||
parallel (~> 1.19)
|
parallel (~> 1.19)
|
||||||
parallel_tests (~> 2.30)
|
parallel_tests (~> 2.32)
|
||||||
parslet
|
parslet
|
||||||
pg (~> 1.2)
|
pg (~> 1.2)
|
||||||
pghero (~> 2.4)
|
pghero (~> 2.4)
|
||||||
|
@ -751,7 +753,7 @@ DEPENDENCIES
|
||||||
rack (~> 2.2.2)
|
rack (~> 2.2.2)
|
||||||
rack-attack (~> 6.2)
|
rack-attack (~> 6.2)
|
||||||
rack-cors (~> 1.1)
|
rack-cors (~> 1.1)
|
||||||
rails (~> 5.2.4)
|
rails (~> 5.2.4.2)
|
||||||
rails-controller-testing (~> 1.0)
|
rails-controller-testing (~> 1.0)
|
||||||
rails-i18n (~> 5.1)
|
rails-i18n (~> 5.1)
|
||||||
rails-settings-cached (~> 0.6)
|
rails-settings-cached (~> 0.6)
|
||||||
|
@ -761,13 +763,13 @@ DEPENDENCIES
|
||||||
redis-namespace (~> 1.7)
|
redis-namespace (~> 1.7)
|
||||||
redis-rails (~> 5.0)
|
redis-rails (~> 5.0)
|
||||||
rqrcode (~> 1.1)
|
rqrcode (~> 1.1)
|
||||||
rspec-rails (~> 3.9)
|
rspec-rails (~> 4.0)
|
||||||
rspec-sidekiq (~> 3.0)
|
rspec-sidekiq (~> 3.0)
|
||||||
rubocop (~> 0.79)
|
rubocop (~> 0.79)
|
||||||
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)
|
||||||
|
@ -779,11 +781,11 @@ DEPENDENCIES
|
||||||
stackprof
|
stackprof
|
||||||
stoplight (~> 2.2.0)
|
stoplight (~> 2.2.0)
|
||||||
streamio-ffmpeg (~> 3.0)
|
streamio-ffmpeg (~> 3.0)
|
||||||
strong_migrations (~> 0.5)
|
strong_migrations (~> 0.6)
|
||||||
thor (~> 0.20)
|
thor (~> 0.20)
|
||||||
thwait (~> 0.1.0)
|
thwait (~> 0.1.0)
|
||||||
tty-command (~> 0.9)
|
tty-command (~> 0.9)
|
||||||
tty-prompt (~> 0.20)
|
tty-prompt (~> 0.21)
|
||||||
twitter-text (~> 1.14)
|
twitter-text (~> 1.14)
|
||||||
tzinfo-data (~> 1.2019)
|
tzinfo-data (~> 1.2019)
|
||||||
webmock (~> 3.8)
|
webmock (~> 3.8)
|
||||||
|
|
|
@ -91,7 +91,7 @@ VAGRANTFILE_API_VERSION = "2"
|
||||||
|
|
||||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||||
|
|
||||||
config.vm.box = "ubuntu/xenial64"
|
config.vm.box = "ubuntu/bionic64"
|
||||||
|
|
||||||
config.vm.provider :virtualbox do |vb|
|
config.vm.provider :virtualbox do |vb|
|
||||||
vb.name = "mastodon"
|
vb.name = "mastodon"
|
||||||
|
|
|
@ -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,7 +6,7 @@ class AccountFollowController < ApplicationController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
|
|
||||||
def create
|
def create
|
||||||
FollowService.new.call(current_user.account, @account.acct)
|
FollowService.new.call(current_user.account, @account, with_rate_limit: true)
|
||||||
redirect_to account_path(@account)
|
redirect_to account_path(@account)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,8 +2,18 @@
|
||||||
|
|
||||||
module Admin
|
module Admin
|
||||||
class ActionLogsController < BaseController
|
class ActionLogsController < BaseController
|
||||||
def index
|
before_action :set_action_logs
|
||||||
@action_logs = Admin::ActionLog.page(params[:page])
|
|
||||||
|
def index; end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_action_logs
|
||||||
|
@action_logs = Admin::ActionLogFilter.new(filter_params).results.page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_params
|
||||||
|
params.slice(:page, *Admin::ActionLogFilter::KEYS).permit(:page, *Admin::ActionLogFilter::KEYS)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class SiteUploadsController < BaseController
|
||||||
|
before_action :set_site_upload
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
authorize :settings, :destroy?
|
||||||
|
|
||||||
|
@site_upload.destroy!
|
||||||
|
|
||||||
|
redirect_to edit_admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_site_upload
|
||||||
|
@site_upload = SiteUpload.find(params[:id])
|
||||||
|
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
|
||||||
|
|
|
@ -44,6 +44,10 @@ class Api::BaseController < ApplicationController
|
||||||
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
|
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
|
||||||
end
|
end
|
||||||
|
|
||||||
|
rescue_from Mastodon::RateLimitExceededError do
|
||||||
|
render json: { error: I18n.t('errors.429') }, status: 429
|
||||||
|
end
|
||||||
|
|
||||||
rescue_from ActionController::ParameterMissing do |e|
|
rescue_from ActionController::ParameterMissing do |e|
|
||||||
render json: { error: e.to_s }, status: 400
|
render json: { error: e.to_s }, status: 400
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@accounts = load_accounts
|
@accounts = load_accounts
|
||||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||||
|
@ -27,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
|
||||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@accounts = load_accounts
|
@accounts = load_accounts
|
||||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||||
|
@ -27,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
|
||||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::Accounts::IdentityProofsController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@proofs = @account.identity_proofs.active
|
@proofs = @account.identity_proofs.active
|
||||||
render json: @proofs, each_serializer: REST::IdentityProofSerializer
|
render json: @proofs, each_serializer: REST::IdentityProofSerializer
|
||||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::Accounts::ListsController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@lists = @account.lists.where(account: current_account)
|
@lists = @account.lists.where(account: current_account)
|
||||||
render json: @lists, each_serializer: REST::ListSerializer
|
render json: @lists, each_serializer: REST::ListSerializer
|
||||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Accounts::PinsController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def create
|
def create
|
||||||
AccountPin.create!(account: current_account, target_account: @account)
|
AccountPin.create!(account: current_account, target_account: @account)
|
||||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships_presenter
|
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships_presenter
|
||||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :read, :'read:follows' }
|
before_action -> { doorkeeper_authorize! :read, :'read:follows' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
accounts = Account.where(id: account_ids).select('id')
|
accounts = Account.where(id: account_ids).select('id')
|
||||||
# .where doesn't guarantee that our results are in the same order
|
# .where doesn't guarantee that our results are in the same order
|
||||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::Accounts::SearchController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }
|
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@accounts = account_search
|
@accounts = account_search
|
||||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||||
|
|
|
@ -6,8 +6,6 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
||||||
|
|
||||||
after_action :insert_pagination_headers, unless: -> { truthy_param?(:pinned) }
|
after_action :insert_pagination_headers, unless: -> { truthy_param?(:pinned) }
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||||
|
|
|
@ -14,7 +14,7 @@ class Api::V1::AccountsController < Api::BaseController
|
||||||
|
|
||||||
skip_before_action :require_authenticated_user!, only: :create
|
skip_before_action :require_authenticated_user!, only: :create
|
||||||
|
|
||||||
respond_to :json
|
override_rate_limit_headers :follow, family: :follows
|
||||||
|
|
||||||
def show
|
def show
|
||||||
render json: @account, serializer: REST::AccountSerializer
|
render json: @account, serializer: REST::AccountSerializer
|
||||||
|
@ -31,7 +31,7 @@ class Api::V1::AccountsController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def follow
|
def follow
|
||||||
FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs))
|
FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs), with_rate_limit: true)
|
||||||
|
|
||||||
options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } }
|
options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } }
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
class Api::V1::Apps::CredentialsController < Api::BaseController
|
class Api::V1::Apps::CredentialsController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :read }
|
before_action -> { doorkeeper_authorize! :read }
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key)
|
render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key)
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::BlocksController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@accounts = load_accounts
|
@accounts = load_accounts
|
||||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::BookmarksController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||||
|
|
|
@ -9,8 +9,6 @@ class Api::V1::ConversationsController < Api::BaseController
|
||||||
before_action :set_conversation, except: :index
|
before_action :set_conversation, except: :index
|
||||||
after_action :insert_pagination_headers, only: :index
|
after_action :insert_pagination_headers, only: :index
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@conversations = paginated_conversations
|
@conversations = paginated_conversations
|
||||||
render json: @conversations, each_serializer: REST::ConversationSerializer
|
render json: @conversations, each_serializer: REST::ConversationSerializer
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::CustomEmojisController < Api::BaseController
|
class Api::V1::CustomEmojisController < Api::BaseController
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
skip_before_action :set_cache_headers
|
skip_before_action :set_cache_headers
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -8,8 +8,6 @@ class Api::V1::DomainBlocksController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers, only: :show
|
after_action :insert_pagination_headers, only: :show
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@blocks = load_domain_blocks
|
@blocks = load_domain_blocks
|
||||||
render json: @blocks.map(&:domain)
|
render json: @blocks.map(&:domain)
|
||||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::EndorsementsController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@accounts = load_accounts
|
@accounts = load_accounts
|
||||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::FavouritesController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||||
|
|
|
@ -2,12 +2,9 @@
|
||||||
|
|
||||||
class Api::V1::FeaturedTags::SuggestionsController < Api::BaseController
|
class Api::V1::FeaturedTags::SuggestionsController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, only: :index
|
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, only: :index
|
||||||
|
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_most_used_tags, only: :index
|
before_action :set_most_used_tags, only: :index
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: @most_used_tags, each_serializer: REST::TagSerializer
|
render json: @most_used_tags, each_serializer: REST::TagSerializer
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::FiltersController < Api::BaseController
|
||||||
before_action :set_filters, only: :index
|
before_action :set_filters, only: :index
|
||||||
before_action :set_filter, only: [:show, :update, :destroy]
|
before_action :set_filter, only: [:show, :update, :destroy]
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: @filters, each_serializer: REST::FilterSerializer
|
render json: @filters, each_serializer: REST::FilterSerializer
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,8 +6,6 @@ class Api::V1::Instances::ActivityController < Api::BaseController
|
||||||
skip_before_action :set_cache_headers
|
skip_before_action :set_cache_headers
|
||||||
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
expires_in 1.day, public: true
|
expires_in 1.day, public: true
|
||||||
render_with_cache json: :activity, expires_in: 1.day
|
render_with_cache json: :activity, expires_in: 1.day
|
||||||
|
|
|
@ -6,8 +6,6 @@ class Api::V1::Instances::PeersController < Api::BaseController
|
||||||
skip_before_action :set_cache_headers
|
skip_before_action :set_cache_headers
|
||||||
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
expires_in 1.day, public: true
|
expires_in 1.day, public: true
|
||||||
render_with_cache(expires_in: 1.day) { Account.remote.domains }
|
render_with_cache(expires_in: 1.day) { Account.remote.domains }
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::InstancesController < Api::BaseController
|
class Api::V1::InstancesController < Api::BaseController
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
skip_before_action :set_cache_headers
|
skip_before_action :set_cache_headers
|
||||||
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
||||||
|
|
||||||
|
|
|
@ -3,27 +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]
|
||||||
respond_to :json
|
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
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::MutesController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@data = @accounts = load_accounts
|
@data = @accounts = load_accounts
|
||||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||||
|
|
|
@ -6,8 +6,6 @@ class Api::V1::NotificationsController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers, only: :index
|
after_action :insert_pagination_headers, only: :index
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
DEFAULT_NOTIFICATIONS_LIMIT = 15
|
DEFAULT_NOTIFICATIONS_LIMIT = 15
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Polls::VotesController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_poll
|
before_action :set_poll
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def create
|
def create
|
||||||
VoteService.new.call(current_account, @poll, vote_params[:choices])
|
VoteService.new.call(current_account, @poll, vote_params[:choices])
|
||||||
render json: @poll, serializer: REST::PollSerializer
|
render json: @poll, serializer: REST::PollSerializer
|
||||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::PollsController < Api::BaseController
|
||||||
before_action :set_poll
|
before_action :set_poll
|
||||||
before_action :refresh_poll
|
before_action :refresh_poll
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
render json: @poll, serializer: REST::PollSerializer, include_results: true
|
render json: @poll, serializer: REST::PollSerializer, include_results: true
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::PreferencesController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }
|
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: current_account, serializer: REST::PreferencesSerializer
|
render json: current_account, serializer: REST::PreferencesSerializer
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@ class Api::V1::ReportsController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create]
|
before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create]
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
|
||||||
respond_to :json
|
override_rate_limit_headers :create, family: :reports
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@report = ReportService.new.call(
|
@report = ReportService.new.call(
|
||||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Statuses::BookmarksController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_status
|
before_action :set_status
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def create
|
def create
|
||||||
current_account.bookmarks.find_or_create_by!(account: current_account, status: @status)
|
current_account.bookmarks.find_or_create_by!(account: current_account, status: @status)
|
||||||
render json: @status, serializer: REST::StatusSerializer
|
render json: @status, serializer: REST::StatusSerializer
|
||||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
|
||||||
before_action :set_status
|
before_action :set_status
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@accounts = load_accounts
|
@accounts = load_accounts
|
||||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_status
|
before_action :set_status
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def create
|
def create
|
||||||
FavouriteService.new.call(current_account, @status)
|
FavouriteService.new.call(current_account, @status)
|
||||||
render json: @status, serializer: REST::StatusSerializer
|
render json: @status, serializer: REST::StatusSerializer
|
||||||
|
|
|
@ -8,8 +8,6 @@ class Api::V1::Statuses::MutesController < Api::BaseController
|
||||||
before_action :set_status
|
before_action :set_status
|
||||||
before_action :set_conversation
|
before_action :set_conversation
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def create
|
def create
|
||||||
current_account.mute_conversation!(@conversation)
|
current_account.mute_conversation!(@conversation)
|
||||||
@mutes_map = { @conversation.id => true }
|
@mutes_map = { @conversation.id => true }
|
||||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Statuses::PinsController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_status
|
before_action :set_status
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def create
|
def create
|
||||||
StatusPin.create!(account: current_account, status: @status)
|
StatusPin.create!(account: current_account, status: @status)
|
||||||
distribute_add_activity!
|
distribute_add_activity!
|
||||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
|
||||||
before_action :set_status
|
before_action :set_status
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@accounts = load_accounts
|
@accounts = load_accounts
|
||||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||||
|
|
|
@ -7,10 +7,11 @@ class Api::V1::Statuses::ReblogsController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_reblog
|
before_action :set_reblog
|
||||||
|
|
||||||
respond_to :json
|
override_rate_limit_headers :create, family: :statuses
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@status = ReblogService.new.call(current_account, @reblog, reblog_params)
|
@status = ReblogService.new.call(current_account, @reblog, reblog_params)
|
||||||
|
|
||||||
render json: @status, serializer: REST::StatusSerializer
|
render json: @status, serializer: REST::StatusSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,9 @@ class Api::V1::StatusesController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :destroy]
|
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :destroy]
|
||||||
before_action :require_user!, except: [:show, :context]
|
before_action :require_user!, except: [:show, :context]
|
||||||
before_action :set_status, only: [:show, :context]
|
before_action :set_status, only: [:show, :context]
|
||||||
|
before_action :set_thread, only: [:create]
|
||||||
|
|
||||||
respond_to :json
|
override_rate_limit_headers :create, family: :statuses
|
||||||
|
|
||||||
# This API was originally unlimited, pagination cannot be introduced without
|
# This API was originally unlimited, pagination cannot be introduced without
|
||||||
# breaking backwards-compatibility. Arbitrarily high number to cover most
|
# breaking backwards-compatibility. Arbitrarily high number to cover most
|
||||||
|
@ -36,7 +37,7 @@ class Api::V1::StatusesController < Api::BaseController
|
||||||
def create
|
def create
|
||||||
@status = PostStatusService.new.call(current_user.account,
|
@status = PostStatusService.new.call(current_user.account,
|
||||||
text: status_params[:status],
|
text: status_params[:status],
|
||||||
thread: status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]),
|
thread: @thread,
|
||||||
media_ids: status_params[:media_ids],
|
media_ids: status_params[:media_ids],
|
||||||
sensitive: status_params[:sensitive],
|
sensitive: status_params[:sensitive],
|
||||||
spoiler_text: status_params[:spoiler_text],
|
spoiler_text: status_params[:spoiler_text],
|
||||||
|
@ -45,7 +46,8 @@ class Api::V1::StatusesController < Api::BaseController
|
||||||
application: doorkeeper_token.application,
|
application: doorkeeper_token.application,
|
||||||
poll: status_params[:poll],
|
poll: status_params[:poll],
|
||||||
content_type: status_params[:content_type],
|
content_type: status_params[:content_type],
|
||||||
idempotency: request.headers['Idempotency-Key'])
|
idempotency: request.headers['Idempotency-Key'],
|
||||||
|
with_rate_limit: true)
|
||||||
|
|
||||||
render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer
|
render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer
|
||||||
end
|
end
|
||||||
|
@ -69,6 +71,12 @@ class Api::V1::StatusesController < Api::BaseController
|
||||||
raise ActiveRecord::RecordNotFound
|
raise ActiveRecord::RecordNotFound
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_thread
|
||||||
|
@thread = status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id])
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404
|
||||||
|
end
|
||||||
|
|
||||||
def status_params
|
def status_params
|
||||||
params.permit(
|
params.permit(
|
||||||
:status,
|
:status,
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::StreamingController < Api::BaseController
|
class Api::V1::StreamingController < Api::BaseController
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
if Rails.configuration.x.streaming_api_base_url != request.host
|
if Rails.configuration.x.streaming_api_base_url != request.host
|
||||||
redirect_to streaming_api_url, status: 301
|
redirect_to streaming_api_url, status: 301
|
||||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::SuggestionsController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_accounts
|
before_action :set_accounts
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::Timelines::HomeController < Api::BaseController
|
||||||
before_action :require_user!, only: [:show]
|
before_action :require_user!, only: [:show]
|
||||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::Timelines::PublicController < Api::BaseController
|
||||||
before_action :require_user!, only: [:show], if: :require_auth?
|
before_action :require_user!, only: [:show], if: :require_auth?
|
||||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::Timelines::TagController < Api::BaseController
|
||||||
before_action :load_tag
|
before_action :load_tag
|
||||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
class Api::V1::TrendsController < Api::BaseController
|
class Api::V1::TrendsController < Api::BaseController
|
||||||
before_action :set_tags
|
before_action :set_tags
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: @tags, each_serializer: REST::TagSerializer
|
render json: @tags, each_serializer: REST::TagSerializer
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
|
@ -8,8 +8,6 @@ class Api::V2::SearchController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :read, :'read:search' }
|
before_action -> { doorkeeper_authorize! :read, :'read:search' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@search = Search.new(search_results)
|
@search = Search.new(search_results)
|
||||||
render json: @search, serializer: REST::SearchSerializer
|
render json: @search, serializer: REST::SearchSerializer
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::Web::EmbedsController < Api::Web::BaseController
|
class Api::Web::EmbedsController < Api::Web::BaseController
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::Web::SettingsController < Api::Web::BaseController
|
class Api::Web::SettingsController < Api::Web::BaseController
|
||||||
respond_to :json
|
|
||||||
|
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
|
|
@ -30,6 +30,7 @@ class ApplicationController < ActionController::Base
|
||||||
rescue_from Mastodon::NotPermittedError, with: :forbidden
|
rescue_from Mastodon::NotPermittedError, with: :forbidden
|
||||||
rescue_from HTTP::Error, OpenSSL::SSL::SSLError, with: :internal_server_error
|
rescue_from HTTP::Error, OpenSSL::SSL::SSLError, with: :internal_server_error
|
||||||
rescue_from Mastodon::RaceConditionError, with: :service_unavailable
|
rescue_from Mastodon::RaceConditionError, with: :service_unavailable
|
||||||
|
rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests
|
||||||
|
|
||||||
before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?
|
before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?
|
||||||
before_action :require_functional!, if: :user_signed_in?
|
before_action :require_functional!, if: :user_signed_in?
|
||||||
|
@ -181,6 +182,10 @@ class ApplicationController < ActionController::Base
|
||||||
respond_with_error(503)
|
respond_with_error(503)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def too_many_requests
|
||||||
|
respond_with_error(429)
|
||||||
|
end
|
||||||
|
|
||||||
def single_user_mode?
|
def single_user_mode?
|
||||||
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.where('id > 0').exists?
|
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.where('id > 0').exists?
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,7 +21,7 @@ class AuthorizeInteractionsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
if @resource.is_a?(Account) && FollowService.new.call(current_account, @resource)
|
if @resource.is_a?(Account) && FollowService.new.call(current_account, @resource, with_rate_limit: true)
|
||||||
render :success
|
render :success
|
||||||
else
|
else
|
||||||
render :error
|
render :error
|
||||||
|
|
|
@ -3,6 +3,20 @@
|
||||||
module RateLimitHeaders
|
module RateLimitHeaders
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
class_methods do
|
||||||
|
def override_rate_limit_headers(method_name, options = {})
|
||||||
|
around_action(only: method_name, if: :current_account) do |_controller, block|
|
||||||
|
begin
|
||||||
|
block.call
|
||||||
|
ensure
|
||||||
|
rate_limiter = RateLimiter.new(current_account, options)
|
||||||
|
rate_limit_headers = rate_limiter.to_headers
|
||||||
|
response.headers.merge!(rate_limit_headers) unless response.headers['X-RateLimit-Remaining'].present? && rate_limit_headers['X-RateLimit-Remaining'].to_i > response.headers['X-RateLimit-Remaining'].to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
included do
|
included do
|
||||||
before_action :set_rate_limit_headers, if: :rate_limited_request?
|
before_action :set_rate_limit_headers, if: :rate_limited_request?
|
||||||
end
|
end
|
||||||
|
@ -44,7 +58,7 @@ module RateLimitHeaders
|
||||||
end
|
end
|
||||||
|
|
||||||
def api_throttle_data
|
def api_throttle_data
|
||||||
most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_, v| v[:limit] }
|
most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_, v| v[:limit] - v[:count] }
|
||||||
request.env['rack.attack.throttle_data'][most_limited_type]
|
request.env['rack.attack.throttle_data'][most_limited_type]
|
||||||
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
|
||||||
|
|
|
@ -29,6 +29,6 @@ class Settings::ImportsController < Settings::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def import_params
|
def import_params
|
||||||
params.require(:import).permit(:data, :type)
|
params.require(:import).permit(:data, :type, :mode)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,79 +9,8 @@ module Admin::ActionLogsHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def relevant_log_changes(log)
|
|
||||||
if log.target_type == 'CustomEmoji' && [:enable, :disable, :destroy].include?(log.action)
|
|
||||||
log.recorded_changes.slice('domain')
|
|
||||||
elsif log.target_type == 'CustomEmoji' && log.action == :update
|
|
||||||
log.recorded_changes.slice('domain', 'visible_in_picker')
|
|
||||||
elsif log.target_type == 'User' && [:promote, :demote].include?(log.action)
|
|
||||||
log.recorded_changes.slice('moderator', 'admin')
|
|
||||||
elsif log.target_type == 'User' && [:change_email].include?(log.action)
|
|
||||||
log.recorded_changes.slice('email', 'unconfirmed_email')
|
|
||||||
elsif log.target_type == 'DomainBlock'
|
|
||||||
log.recorded_changes.slice('severity', 'reject_media')
|
|
||||||
elsif log.target_type == 'Status' && log.action == :update
|
|
||||||
log.recorded_changes.slice('sensitive')
|
|
||||||
elsif log.target_type == 'Announcement' && log.action == :update
|
|
||||||
log.recorded_changes.slice('text', 'starts_at', 'ends_at', 'all_day')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def log_extra_attributes(hash)
|
|
||||||
safe_join(hash.to_a.map { |key, value| safe_join([content_tag(:span, key, class: 'diff-key'), '=', log_change(value)]) }, ' ')
|
|
||||||
end
|
|
||||||
|
|
||||||
def log_change(val)
|
|
||||||
return content_tag(:span, val, class: 'diff-neutral') unless val.is_a?(Array)
|
|
||||||
safe_join([content_tag(:span, val.first, class: 'diff-old'), content_tag(:span, val.last, class: 'diff-new')], '→')
|
|
||||||
end
|
|
||||||
|
|
||||||
def icon_for_log(log)
|
|
||||||
case log.target_type
|
|
||||||
when 'Account', 'User'
|
|
||||||
'user'
|
|
||||||
when 'CustomEmoji'
|
|
||||||
'file'
|
|
||||||
when 'Report'
|
|
||||||
'flag'
|
|
||||||
when 'DomainBlock'
|
|
||||||
'lock'
|
|
||||||
when 'DomainAllow'
|
|
||||||
'plus-circle'
|
|
||||||
when 'EmailDomainBlock'
|
|
||||||
'envelope'
|
|
||||||
when 'Status'
|
|
||||||
'pencil'
|
|
||||||
when 'AccountWarning'
|
|
||||||
'warning'
|
|
||||||
when 'Announcement'
|
|
||||||
'bullhorn'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def class_for_log_icon(log)
|
|
||||||
case log.action
|
|
||||||
when :enable, :unsuspend, :unsilence, :confirm, :promote, :resolve
|
|
||||||
'positive'
|
|
||||||
when :create
|
|
||||||
opposite_verbs?(log) ? 'negative' : 'positive'
|
|
||||||
when :update, :reset_password, :disable_2fa, :memorialize, :change_email
|
|
||||||
'neutral'
|
|
||||||
when :demote, :silence, :disable, :suspend, :remove_avatar, :remove_header, :reopen
|
|
||||||
'negative'
|
|
||||||
when :destroy
|
|
||||||
opposite_verbs?(log) ? 'positive' : 'negative'
|
|
||||||
else
|
|
||||||
''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def opposite_verbs?(log)
|
|
||||||
%w(DomainBlock EmailDomainBlock AccountWarning).include?(log.target_type)
|
|
||||||
end
|
|
||||||
|
|
||||||
def linkable_log_target(record)
|
def linkable_log_target(record)
|
||||||
case record.class.name
|
case record.class.name
|
||||||
when 'Account'
|
when 'Account'
|
||||||
|
@ -99,7 +28,7 @@ module Admin::ActionLogsHelper
|
||||||
when 'AccountWarning'
|
when 'AccountWarning'
|
||||||
link_to record.target_account.acct, admin_account_path(record.target_account_id)
|
link_to record.target_account.acct, admin_account_path(record.target_account_id)
|
||||||
when 'Announcement'
|
when 'Announcement'
|
||||||
link_to "##{record.id}", edit_admin_announcement_path(record.id)
|
link_to truncate(record.text), edit_admin_announcement_path(record.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -118,7 +47,7 @@ module Admin::ActionLogsHelper
|
||||||
I18n.t('admin.action_logs.deleted_status')
|
I18n.t('admin.action_logs.deleted_status')
|
||||||
end
|
end
|
||||||
when 'Announcement'
|
when 'Announcement'
|
||||||
"##{attributes['id']}"
|
truncate(attributes['text'])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,7 @@ module Admin::FilterHelper
|
||||||
InviteFilter::KEYS,
|
InviteFilter::KEYS,
|
||||||
RelationshipFilter::KEYS,
|
RelationshipFilter::KEYS,
|
||||||
AnnouncementFilter::KEYS,
|
AnnouncementFilter::KEYS,
|
||||||
|
Admin::ActionLogFilter::KEYS,
|
||||||
].flatten.freeze
|
].flatten.freeze
|
||||||
|
|
||||||
def filter_link_to(text, link_to_params, link_class_params = link_to_params)
|
def filter_link_to(text, link_to_params, link_class_params = link_to_params)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Admin::SettingsHelper
|
||||||
|
def site_upload_delete_hint(hint, var)
|
||||||
|
upload = SiteUpload.find_by(var: var.to_s)
|
||||||
|
return hint unless upload
|
||||||
|
|
||||||
|
link = link_to t('admin.site_uploads.delete'), admin_site_upload_path(upload), data: { method: :delete }
|
||||||
|
safe_join([hint, link], '<br/>'.html_safe)
|
||||||
|
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"]';
|
||||||
|
@ -32,6 +32,10 @@ delegate(document, '.media-spoiler-hide-button', 'click', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
delegate(document, '.filter-subset--with-select select', 'change', ({ target }) => {
|
||||||
|
target.form.submit();
|
||||||
|
});
|
||||||
|
|
||||||
const onDomainBlockSeverityChange = (target) => {
|
const onDomainBlockSeverityChange = (target) => {
|
||||||
const rejectMediaDiv = document.querySelector('.input.with_label.domain_block_reject_media');
|
const rejectMediaDiv = document.querySelector('.input.with_label.domain_block_reject_media');
|
||||||
const rejectReportsDiv = document.querySelector('.input.with_label.domain_block_reject_reports');
|
const rejectReportsDiv = document.querySelector('.input.with_label.domain_block_reject_reports');
|
||||||
|
|
|
@ -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 }) => {
|
||||||
|
@ -14,20 +14,6 @@ delegate(document, '.webapp-btn', 'click', ({ target, button }) => {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
delegate(document, '.status__content__spoiler-link', 'click', function() {
|
|
||||||
const contentEl = this.parentNode.parentNode.querySelector('.e-content');
|
|
||||||
|
|
||||||
if (contentEl.style.display === 'block') {
|
|
||||||
contentEl.style.display = 'none';
|
|
||||||
this.parentNode.style.marginBottom = 0;
|
|
||||||
} else {
|
|
||||||
contentEl.style.display = 'block';
|
|
||||||
this.parentNode.style.marginBottom = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
delegate(document, '.modal-button', 'click', e => {
|
delegate(document, '.modal-button', 'click', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
|
|
@ -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 }) => {
|
||||||
|
|
|
@ -370,6 +370,7 @@ export function fetchFollowersFail(id, error) {
|
||||||
type: FOLLOWERS_FETCH_FAIL,
|
type: FOLLOWERS_FETCH_FAIL,
|
||||||
id,
|
id,
|
||||||
error,
|
error,
|
||||||
|
skipNotFound: true,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -456,6 +457,7 @@ export function fetchFollowingFail(id, error) {
|
||||||
type: FOLLOWING_FETCH_FAIL,
|
type: FOLLOWING_FETCH_FAIL,
|
||||||
id,
|
id,
|
||||||
error,
|
error,
|
||||||
|
skipNotFound: true,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -545,6 +547,7 @@ export function fetchRelationshipsFail(error) {
|
||||||
type: RELATIONSHIPS_FETCH_FAIL,
|
type: RELATIONSHIPS_FETCH_FAIL,
|
||||||
error,
|
error,
|
||||||
skipLoading: true,
|
skipLoading: true,
|
||||||
|
skipNotFound: true,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,11 @@ export function showAlert(title = messages.unexpectedTitle, message = messages.u
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function showAlertForError(error) {
|
export function showAlertForError(error, skipNotFound = false) {
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
const { data, status, statusText, headers } = error.response;
|
const { data, status, statusText, headers } = error.response;
|
||||||
|
|
||||||
if (status === 404 || status === 410) {
|
if (skipNotFound && (status === 404 || status === 410)) {
|
||||||
// Skip these errors as they are reflected in the UI
|
// Skip these errors as they are reflected in the UI
|
||||||
return { type: ALERT_NOOP };
|
return { type: ALERT_NOOP };
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,12 +259,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)));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,4 +27,5 @@ export const fetchAccountIdentityProofsFail = (accountId, err) => ({
|
||||||
type: IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL,
|
type: IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL,
|
||||||
accountId,
|
accountId,
|
||||||
err,
|
err,
|
||||||
|
skipNotFound: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -165,6 +165,7 @@ export function expandTimelineFail(timeline, error, isLoadingMore) {
|
||||||
timeline,
|
timeline,
|
||||||
error,
|
error,
|
||||||
skipLoading: !isLoadingMore,
|
skipLoading: !isLoadingMore,
|
||||||
|
skipNotFound: timeline.startsWith('account:'),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -45,7 +45,7 @@ export default class IntersectionObserverArticle extends React.Component {
|
||||||
intersectionObserverWrapper.observe(
|
intersectionObserverWrapper.observe(
|
||||||
id,
|
id,
|
||||||
this.node,
|
this.node,
|
||||||
this.handleIntersection
|
this.handleIntersection,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.componentMounted = true;
|
this.componentMounted = true;
|
||||||
|
|
|
@ -23,7 +23,7 @@ const messages = defineMessages({
|
||||||
id: 'status.sensitive_toggle',
|
id: 'status.sensitive_toggle',
|
||||||
},
|
},
|
||||||
toggle_visible: {
|
toggle_visible: {
|
||||||
defaultMessage: 'Toggle visibility',
|
defaultMessage: 'Hide media',
|
||||||
id: 'media_gallery.toggle_visible',
|
id: 'media_gallery.toggle_visible',
|
||||||
},
|
},
|
||||||
warning: {
|
warning: {
|
||||||
|
|
|
@ -127,15 +127,7 @@ class Poll extends ImmutablePureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={option.get('title')}>
|
<li key={option.get('title')}>
|
||||||
{showResults && (
|
<label className={classNames('poll__option', { selectable: !showResults })}>
|
||||||
<Motion defaultStyle={{ width: 0 }} style={{ width: spring(percent, { stiffness: 180, damping: 12 }) }}>
|
|
||||||
{({ width }) =>
|
|
||||||
<span className={classNames('poll__chart', { leading })} style={{ width: `${width}%` }} />
|
|
||||||
}
|
|
||||||
</Motion>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<label className={classNames('poll__text', { selectable: !showResults })}>
|
|
||||||
<input
|
<input
|
||||||
name='vote-options'
|
name='vote-options'
|
||||||
type={poll.get('multiple') ? 'checkbox' : 'radio'}
|
type={poll.get('multiple') ? 'checkbox' : 'radio'}
|
||||||
|
@ -157,12 +149,26 @@ class Poll extends ImmutablePureComponent {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showResults && <span className='poll__number'>
|
{showResults && <span className='poll__number'>
|
||||||
{!!voted && <Icon id='check' className='poll__vote__mark' title={intl.formatMessage(messages.voted)} />}
|
|
||||||
{Math.round(percent)}%
|
{Math.round(percent)}%
|
||||||
</span>}
|
</span>}
|
||||||
|
|
||||||
<span dangerouslySetInnerHTML={{ __html: titleEmojified }} />
|
<span
|
||||||
|
className='poll__option__text'
|
||||||
|
dangerouslySetInnerHTML={{ __html: titleEmojified }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{!!voted && <span className='poll__voted'>
|
||||||
|
<Icon id='check' className='poll__voted__mark' title={intl.formatMessage(messages.voted)} />
|
||||||
|
</span>}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
{showResults && (
|
||||||
|
<Motion defaultStyle={{ width: 0 }} style={{ width: spring(percent, { stiffness: 180, damping: 12 }) }}>
|
||||||
|
{({ width }) =>
|
||||||
|
<span className={classNames('poll__chart', { leading })} style={{ width: `${width}%` }} />
|
||||||
|
}
|
||||||
|
</Motion>
|
||||||
|
)}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = () => {
|
||||||
|
|
|
@ -30,8 +30,8 @@ const messages = defineMessages({
|
||||||
report: { id: 'account.report', defaultMessage: 'Report @{name}' },
|
report: { id: 'account.report', defaultMessage: 'Report @{name}' },
|
||||||
share: { id: 'account.share', defaultMessage: 'Share @{name}\'s profile' },
|
share: { id: 'account.share', defaultMessage: 'Share @{name}\'s profile' },
|
||||||
media: { id: 'account.media', defaultMessage: 'Media' },
|
media: { id: 'account.media', defaultMessage: 'Media' },
|
||||||
blockDomain: { id: 'account.block_domain', defaultMessage: 'Hide everything from {domain}' },
|
blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
|
||||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
|
||||||
hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide boosts from @{name}' },
|
hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide boosts from @{name}' },
|
||||||
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },
|
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },
|
||||||
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
|
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
|
||||||
|
@ -40,7 +40,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' },
|
||||||
|
@ -136,7 +136,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 className='relationship-tag'><FormattedMessage id='account.muted' defaultMessage='Muted' /></span>);
|
info.push(<span 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 className='relationship-tag'><FormattedMessage id='account.domain_blocked' defaultMessage='Domain hidden' /></span>);
|
info.push(<span className='relationship-tag'><FormattedMessage id='account.domain_blocked' defaultMessage='Domain blocked' /></span>);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me !== account.get('id')) {
|
if (me !== account.get('id')) {
|
||||||
|
|
|
@ -199,8 +199,8 @@ class Audio extends React.PureComponent {
|
||||||
<div className='video-player__controls active'>
|
<div className='video-player__controls active'>
|
||||||
<div className='video-player__buttons-bar'>
|
<div className='video-player__buttons-bar'>
|
||||||
<div className='video-player__buttons left'>
|
<div className='video-player__buttons left'>
|
||||||
<button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
|
<button type='button' title={intl.formatMessage(paused ? messages.play : messages.pause)} aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
|
||||||
<button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
|
<button type='button' title={intl.formatMessage(muted ? messages.unmute : messages.mute)} aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
|
||||||
|
|
||||||
<div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
|
<div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ class Audio extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='video-player__buttons right'>
|
<div className='video-player__buttons right'>
|
||||||
<button type='button' aria-label={intl.formatMessage(messages.download)}>
|
<button type='button' title={intl.formatMessage(messages.download)} aria-label={intl.formatMessage(messages.download)}>
|
||||||
<a className='video-player__download__icon' href={this.props.src} download>
|
<a className='video-player__download__icon' href={this.props.src} download>
|
||||||
<Icon id={'download'} fixedWidth />
|
<Icon id={'download'} fixedWidth />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -66,7 +66,7 @@ class Blocks extends ImmutablePureComponent {
|
||||||
bindToDocument={!multiColumn}
|
bindToDocument={!multiColumn}
|
||||||
>
|
>
|
||||||
{accountIds.map(id =>
|
{accountIds.map(id =>
|
||||||
<AccountContainer key={id} id={id} />
|
<AccountContainer key={id} id={id} />,
|
||||||
)}
|
)}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
|
@ -81,18 +81,6 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
this.props.onChange(e.target.value);
|
this.props.onChange(e.target.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown = ({ ctrlKey, keyCode, metaKey, altKey }) => {
|
|
||||||
// We submit the status on control/meta + enter.
|
|
||||||
if (keyCode === 13 && (ctrlKey || metaKey)) {
|
|
||||||
this.handleSubmit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submit the status with secondary visibility on alt + enter.
|
|
||||||
if (keyCode === 13 && altKey) {
|
|
||||||
this.handleSecondarySubmit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSubmit = (overriddenVisibility = null) => {
|
handleSubmit = (overriddenVisibility = null) => {
|
||||||
const { textarea: { value }, uploadForm } = this;
|
const { textarea: { value }, uploadForm } = this;
|
||||||
const {
|
const {
|
||||||
|
@ -123,7 +111,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
// Submit unless there are media with missing descriptions
|
// Submit unless there are media with missing descriptions
|
||||||
if (mediaDescriptionConfirmation && onMediaDescriptionConfirm && media && media.some(item => !item.get('description'))) {
|
if (mediaDescriptionConfirmation && onMediaDescriptionConfirm && media && media.some(item => !item.get('description'))) {
|
||||||
const firstWithoutDescription = media.find(item => !item.get('description'));
|
const firstWithoutDescription = media.find(item => !item.get('description'));
|
||||||
onMediaDescriptionConfirm(this.context.router ? this.context.router.history : null, firstWithoutDescription.get('id'));
|
onMediaDescriptionConfirm(this.context.router ? this.context.router.history : null, firstWithoutDescription.get('id'), overriddenVisibility);
|
||||||
} else if (onSubmit) {
|
} else if (onSubmit) {
|
||||||
if (onChangeVisibility && overriddenVisibility) {
|
if (onChangeVisibility && overriddenVisibility) {
|
||||||
onChangeVisibility(overriddenVisibility);
|
onChangeVisibility(overriddenVisibility);
|
||||||
|
@ -171,10 +159,20 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the escape key is released, we focus the UI.
|
// When the escape key is released, we focus the UI.
|
||||||
handleKeyUp = ({ key }) => {
|
handleKeyUp = ({ key, ctrlKey, keyCode, metaKey, altKey }) => {
|
||||||
if (key === 'Escape') {
|
if (key === 'Escape') {
|
||||||
document.querySelector('.ui').parentElement.focus();
|
document.querySelector('.ui').parentElement.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We submit the status on control/meta + enter.
|
||||||
|
if (keyCode === 13 && (ctrlKey || metaKey)) {
|
||||||
|
this.handleSubmit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submit the status with secondary visibility on alt + enter.
|
||||||
|
if (keyCode === 13 && altKey) {
|
||||||
|
this.handleSecondarySubmit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets a reference to the textarea.
|
// Sets a reference to the textarea.
|
||||||
|
@ -307,7 +305,6 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
|
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
|
||||||
value={spoilerText}
|
value={spoilerText}
|
||||||
onChange={this.handleChangeSpoiler}
|
onChange={this.handleChangeSpoiler}
|
||||||
onKeyDown={this.handleKeyDown}
|
|
||||||
onKeyUp={this.handleKeyUp}
|
onKeyUp={this.handleKeyUp}
|
||||||
disabled={!spoiler}
|
disabled={!spoiler}
|
||||||
ref={this.handleRefSpoilerText}
|
ref={this.handleRefSpoilerText}
|
||||||
|
@ -328,9 +325,9 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
value={this.props.text}
|
value={this.props.text}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
|
onKeyUp={this.handleKeyUp}
|
||||||
suggestions={this.props.suggestions}
|
suggestions={this.props.suggestions}
|
||||||
onFocus={this.handleFocus}
|
onFocus={this.handleFocus}
|
||||||
onKeyDown={this.handleKeyDown}
|
|
||||||
onSuggestionsFetchRequested={onFetchSuggestions}
|
onSuggestionsFetchRequested={onFetchSuggestions}
|
||||||
onSuggestionsClearRequested={onClearSuggestions}
|
onSuggestionsClearRequested={onClearSuggestions}
|
||||||
onSuggestionSelected={this.onSuggestionSelected}
|
onSuggestionSelected={this.onSuggestionSelected}
|
||||||
|
|
|
@ -34,7 +34,7 @@ const messages = defineMessages({
|
||||||
id: 'content-type.change',
|
id: 'content-type.change',
|
||||||
},
|
},
|
||||||
direct_long: {
|
direct_long: {
|
||||||
defaultMessage: 'Post to mentioned users only',
|
defaultMessage: 'Visible for mentioned users only',
|
||||||
id: 'privacy.direct.long',
|
id: 'privacy.direct.long',
|
||||||
},
|
},
|
||||||
direct_short: {
|
direct_short: {
|
||||||
|
@ -66,7 +66,7 @@ const messages = defineMessages({
|
||||||
id: 'compose.content-type.plain',
|
id: 'compose.content-type.plain',
|
||||||
},
|
},
|
||||||
private_long: {
|
private_long: {
|
||||||
defaultMessage: 'Post to followers only',
|
defaultMessage: 'Visible for followers only',
|
||||||
id: 'privacy.private.long',
|
id: 'privacy.private.long',
|
||||||
},
|
},
|
||||||
private_short: {
|
private_short: {
|
||||||
|
@ -74,7 +74,7 @@ const messages = defineMessages({
|
||||||
id: 'privacy.private.short',
|
id: 'privacy.private.short',
|
||||||
},
|
},
|
||||||
public_long: {
|
public_long: {
|
||||||
defaultMessage: 'Post to public timelines',
|
defaultMessage: 'Visible for all, shown in public timelines',
|
||||||
id: 'privacy.public.long',
|
id: 'privacy.public.long',
|
||||||
},
|
},
|
||||||
public_short: {
|
public_short: {
|
||||||
|
@ -94,7 +94,7 @@ const messages = defineMessages({
|
||||||
id: 'advanced_options.threaded_mode.short',
|
id: 'advanced_options.threaded_mode.short',
|
||||||
},
|
},
|
||||||
unlisted_long: {
|
unlisted_long: {
|
||||||
defaultMessage: 'Do not show in public timelines',
|
defaultMessage: 'Visible for all, but not in public timelines',
|
||||||
id: 'privacy.unlisted.long',
|
id: 'privacy.unlisted.long',
|
||||||
},
|
},
|
||||||
unlisted_short: {
|
unlisted_short: {
|
||||||
|
|
|
@ -62,7 +62,7 @@ class Option extends React.PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
<label className='poll__text editable'>
|
<label className='poll__option editable'>
|
||||||
<span className={classNames('poll__input', { checkbox: isPollMultiple })} />
|
<span className={classNames('poll__input', { checkbox: isPollMultiple })} />
|
||||||
|
|
||||||
<AutosuggestInput
|
<AutosuggestInput
|
||||||
|
@ -143,6 +143,7 @@ class PollForm extends ImmutablePureComponent {
|
||||||
<option value='true'>{intl.formatMessage(messages.multiple_choices)}</option>
|
<option value='true'>{intl.formatMessage(messages.multiple_choices)}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
{/* eslint-disable-next-line jsx-a11y/no-onchange */}
|
||||||
<select value={expiresIn} onChange={this.handleSelectDuration}>
|
<select value={expiresIn} onChange={this.handleSelectDuration}>
|
||||||
<option value={300}>{intl.formatMessage(messages.minutes, { number: 5 })}</option>
|
<option value={300}>{intl.formatMessage(messages.minutes, { number: 5 })}</option>
|
||||||
<option value={1800}>{intl.formatMessage(messages.minutes, { number: 30 })}</option>
|
<option value={1800}>{intl.formatMessage(messages.minutes, { number: 30 })}</option>
|
||||||
|
|
|
@ -114,11 +114,16 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
dispatch(changeComposeVisibility(value));
|
dispatch(changeComposeVisibility(value));
|
||||||
},
|
},
|
||||||
|
|
||||||
onMediaDescriptionConfirm(routerHistory, mediaId) {
|
onMediaDescriptionConfirm(routerHistory, mediaId, overriddenVisibility = null) {
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
message: intl.formatMessage(messages.missingDescriptionMessage),
|
message: intl.formatMessage(messages.missingDescriptionMessage),
|
||||||
confirm: intl.formatMessage(messages.missingDescriptionConfirm),
|
confirm: intl.formatMessage(messages.missingDescriptionConfirm),
|
||||||
onConfirm: () => dispatch(submitCompose(routerHistory)),
|
onConfirm: () => {
|
||||||
|
if (overriddenVisibility) {
|
||||||
|
dispatch(changeComposeVisibility(overriddenVisibility));
|
||||||
|
};
|
||||||
|
dispatch(submitCompose(routerHistory));
|
||||||
|
},
|
||||||
secondary: intl.formatMessage(messages.missingDescriptionEdit),
|
secondary: intl.formatMessage(messages.missingDescriptionEdit),
|
||||||
onSecondary: () => dispatch(openModal('FOCAL_POINT', { id: mediaId })),
|
onSecondary: () => dispatch(openModal('FOCAL_POINT', { id: mediaId })),
|
||||||
onDoNotAsk: () => dispatch(changeLocalSetting(['confirm_missing_media_description'], false)),
|
onDoNotAsk: () => dispatch(changeLocalSetting(['confirm_missing_media_description'], false)),
|
||||||
|
|
|
@ -195,7 +195,7 @@ class Conversation extends ImmutablePureComponent {
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers}>
|
<HotKeys handlers={handlers}>
|
||||||
<div className={classNames('conversation focusable muted', { 'conversation--unread': unread })} tabIndex='0'>
|
<div className={classNames('conversation focusable muted', { 'conversation--unread': unread })} tabIndex='0'>
|
||||||
<div className='conversation__avatar'>
|
<div className='conversation__avatar' onClick={this.handleClick} role='presentation'>
|
||||||
<AvatarComposite accounts={accounts} size={48} />
|
<AvatarComposite accounts={accounts} size={48} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
import ScrollableList from 'flavours/glitch/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 => ({
|
||||||
|
@ -54,7 +54,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)}>
|
||||||
|
@ -67,7 +67,7 @@ class Blocks extends ImmutablePureComponent {
|
||||||
bindToDocument={!multiColumn}
|
bindToDocument={!multiColumn}
|
||||||
>
|
>
|
||||||
{domains.map(domain =>
|
{domains.map(domain =>
|
||||||
<DomainContainer key={domain} domain={domain} />
|
<DomainContainer key={domain} domain={domain} />,
|
||||||
)}
|
)}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
|
@ -88,7 +88,7 @@ class Favourites extends ImmutablePureComponent {
|
||||||
bindToDocument={!multiColumn}
|
bindToDocument={!multiColumn}
|
||||||
>
|
>
|
||||||
{accountIds.map(id =>
|
{accountIds.map(id =>
|
||||||
<AccountContainer key={id} id={id} withNote={false} />
|
<AccountContainer key={id} id={id} withNote={false} />,
|
||||||
)}
|
)}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { fetchFollowRequests, expandFollowRequests } from 'flavours/glitch/actio
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||||
|
import { me } from 'flavours/glitch/util/initial_state';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.follow_requests', defaultMessage: 'Follow requests' },
|
heading: { id: 'column.follow_requests', defaultMessage: 'Follow requests' },
|
||||||
|
@ -19,6 +20,8 @@ const messages = defineMessages({
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
accountIds: state.getIn(['user_lists', 'follow_requests', 'items']),
|
accountIds: state.getIn(['user_lists', 'follow_requests', 'items']),
|
||||||
hasMore: !!state.getIn(['user_lists', 'follow_requests', 'next']),
|
hasMore: !!state.getIn(['user_lists', 'follow_requests', 'next']),
|
||||||
|
locked: !!state.getIn(['accounts', me, 'locked']),
|
||||||
|
domain: state.getIn(['meta', 'domain']),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @connect(mapStateToProps)
|
export default @connect(mapStateToProps)
|
||||||
|
@ -30,6 +33,8 @@ class FollowRequests extends ImmutablePureComponent {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
hasMore: PropTypes.bool,
|
hasMore: PropTypes.bool,
|
||||||
accountIds: ImmutablePropTypes.list,
|
accountIds: ImmutablePropTypes.list,
|
||||||
|
locked: PropTypes.bool,
|
||||||
|
domain: PropTypes.string,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
@ -43,7 +48,7 @@ class FollowRequests extends ImmutablePureComponent {
|
||||||
}, 300, { leading: true });
|
}, 300, { leading: true });
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, accountIds, hasMore, multiColumn } = this.props;
|
const { intl, accountIds, hasMore, multiColumn, locked, domain } = this.props;
|
||||||
|
|
||||||
if (!accountIds) {
|
if (!accountIds) {
|
||||||
return (
|
return (
|
||||||
|
@ -54,6 +59,15 @@ class FollowRequests extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyMessage = <FormattedMessage id='empty_column.follow_requests' defaultMessage="You don't have any follow requests yet. When you receive one, it will show up here." />;
|
const emptyMessage = <FormattedMessage id='empty_column.follow_requests' defaultMessage="You don't have any follow requests yet. When you receive one, it will show up here." />;
|
||||||
|
const unlockedPrependMessage = locked ? null : (
|
||||||
|
<div className='follow_requests-unlocked_explanation'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='follow_requests.unlocked_explanation'
|
||||||
|
defaultMessage='Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.'
|
||||||
|
values={{ domain: domain }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column bindToDocument={!multiColumn} name='follow-requests' icon='user-plus' heading={intl.formatMessage(messages.heading)}>
|
<Column bindToDocument={!multiColumn} name='follow-requests' icon='user-plus' heading={intl.formatMessage(messages.heading)}>
|
||||||
|
@ -65,9 +79,10 @@ class FollowRequests extends ImmutablePureComponent {
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
bindToDocument={!multiColumn}
|
bindToDocument={!multiColumn}
|
||||||
|
prepend={unlockedPrependMessage}
|
||||||
>
|
>
|
||||||
{accountIds.map(id =>
|
{accountIds.map(id =>
|
||||||
<AccountAuthorizeContainer key={id} id={id} />
|
<AccountAuthorizeContainer key={id} id={id} />,
|
||||||
)}
|
)}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
|
@ -105,7 +105,7 @@ class Followers extends ImmutablePureComponent {
|
||||||
bindToDocument={!multiColumn}
|
bindToDocument={!multiColumn}
|
||||||
>
|
>
|
||||||
{accountIds.map(id =>
|
{accountIds.map(id =>
|
||||||
<AccountContainer key={id} id={id} withNote={false} />
|
<AccountContainer key={id} id={id} withNote={false} />,
|
||||||
)}
|
)}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
|
@ -105,7 +105,7 @@ class Following extends ImmutablePureComponent {
|
||||||
bindToDocument={!multiColumn}
|
bindToDocument={!multiColumn}
|
||||||
>
|
>
|
||||||
{accountIds.map(id =>
|
{accountIds.map(id =>
|
||||||
<AccountContainer key={id} id={id} withNote={false} />
|
<AccountContainer key={id} id={id} withNote={false} />,
|
||||||
)}
|
)}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
|
@ -95,6 +95,10 @@ class Content extends ImmutablePureComponent {
|
||||||
} else if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) {
|
} else if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) {
|
||||||
link.addEventListener('click', this.onHashtagClick.bind(this, link.text), false);
|
link.addEventListener('click', this.onHashtagClick.bind(this, link.text), false);
|
||||||
} else {
|
} else {
|
||||||
|
let status = this.props.announcement.get('statuses').find(item => link.href === item.get('url'));
|
||||||
|
if (status) {
|
||||||
|
link.addEventListener('click', this.onStatusClick.bind(this, status), false);
|
||||||
|
}
|
||||||
link.setAttribute('title', link.href);
|
link.setAttribute('title', link.href);
|
||||||
link.classList.add('unhandled-link');
|
link.classList.add('unhandled-link');
|
||||||
}
|
}
|
||||||
|
@ -120,6 +124,13 @@ class Content extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onStatusClick = (status, e) => {
|
||||||
|
if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.context.router.history.push(`/statuses/${status.get('id')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleEmojiMouseEnter = ({ target }) => {
|
handleEmojiMouseEnter = ({ target }) => {
|
||||||
target.src = target.getAttribute('data-original');
|
target.src = target.getAttribute('data-original');
|
||||||
}
|
}
|
||||||
|
@ -367,6 +378,14 @@ class Announcements extends ImmutablePureComponent {
|
||||||
index: 0,
|
index: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props, state) {
|
||||||
|
if (props.announcements.size > 0 && state.index >= props.announcements.size) {
|
||||||
|
return { index: props.announcements.size - 1 };
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this._markAnnouncementAsRead();
|
this._markAnnouncementAsRead();
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ class Lists extends ImmutablePureComponent {
|
||||||
bindToDocument={!multiColumn}
|
bindToDocument={!multiColumn}
|
||||||
>
|
>
|
||||||
{lists.map(list =>
|
{lists.map(list =>
|
||||||
<ColumnLink key={list.get('id')} to={`/timelines/list/${list.get('id')}`} icon='list-ul' text={list.get('title')} />
|
<ColumnLink key={list.get('id')} to={`/timelines/list/${list.get('id')}`} icon='list-ul' text={list.get('title')} />,
|
||||||
)}
|
)}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
|
@ -66,7 +66,7 @@ class Mutes extends ImmutablePureComponent {
|
||||||
bindToDocument={!multiColumn}
|
bindToDocument={!multiColumn}
|
||||||
>
|
>
|
||||||
{accountIds.map(id =>
|
{accountIds.map(id =>
|
||||||
<AccountContainer key={id} id={id} />
|
<AccountContainer key={id} id={id} />,
|
||||||
)}
|
)}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue