Compare commits

..

5 Commits

Author SHA1 Message Date
Surinna Curtis
920d25f8c9 Handle local_only param when creating statuses. 2017-12-17 05:12:01 +00:00
Surinna Curtis
578438b360 Specs for local-only of new statuses
Some of these should fail currently.
2017-12-17 05:12:01 +00:00
Surinna Curtis
358fd2121a Expose local_only? in REST::StatusSerializer 2017-12-16 21:50:22 +00:00
Surinna Curtis
cb11b0ee5a Add failing specs for local_only in API responses. 2017-12-16 21:47:29 +00:00
Surinna Curtis
bdaaddeff9 expect /api/v1/statuses to 403 for unauthed reqs for local-only statuses 2017-12-16 20:08:04 +00:00
1595 changed files with 20994 additions and 59335 deletions

View File

@@ -4,7 +4,6 @@
[ [
"env", "env",
{ {
"exclude": ["transform-async-to-generator", "transform-regenerator"],
"loose": true, "loose": true,
"modules": false, "modules": false,
"targets": { "targets": {

View File

@@ -1,193 +0,0 @@
version: 2
aliases:
- &defaults
docker:
- image: circleci/ruby:2.5.1-stretch-node
environment: &ruby_environment
BUNDLE_APP_CONFIG: ./.bundle/
DB_HOST: localhost
DB_USER: root
RAILS_ENV: test
PARALLEL_TEST_PROCESSORS: 4
ALLOW_NOPAM: true
CONTINUOUS_INTEGRATION: true
DISABLE_SIMPLECOV: true
working_directory: ~/projects/mastodon/
- &attach_workspace
attach_workspace:
at: ~/projects/
- &persist_to_workspace
persist_to_workspace:
root: ~/projects/
paths:
- ./mastodon/
- &restore_ruby_dependencies
restore_cache:
keys:
- v2-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-{{ checksum "Gemfile.lock" }}
- v2-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-
- v2-ruby-dependencies-
- &install_steps
steps:
- checkout
- *attach_workspace
- restore_cache:
keys:
- v1-node-dependencies-{{ checksum "yarn.lock" }}
- v1-node-dependencies-
- run: yarn install --frozen-lockfile
- save_cache:
key: v1-node-dependencies-{{ checksum "yarn.lock" }}
paths:
- ./node_modules/
- *persist_to_workspace
- &install_system_dependencies
run:
name: Install system dependencies
command: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev libprotobuf-dev protobuf-compiler
- &install_ruby_dependencies
steps:
- *attach_workspace
- *install_system_dependencies
- run: ruby -e 'puts RUBY_VERSION' | tee /tmp/.ruby-version
- *restore_ruby_dependencies
- run: bundle install --clean --jobs 16 --path ./vendor/bundle/ --retry 3 --with pam_authentication --without development production
- save_cache:
key: v2-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-{{ checksum "Gemfile.lock" }}
paths:
- ./.bundle/
- ./vendor/bundle/
- &test_steps
steps:
- *attach_workspace
- *install_system_dependencies
- run: sudo apt-get install -y ffmpeg
- run: ruby -e 'puts RUBY_VERSION' | tee /tmp/.ruby-version
- *restore_ruby_dependencies
- restore_cache:
keys:
- precompiled-assets-{{ .Branch }}-{{ .Revision }}
- precompiled-assets-{{ .Branch }}-
- precompiled-assets-
- run:
name: Prepare Tests
command: ./bin/rails parallel:create parallel:load_schema parallel:prepare
- run:
name: Run Tests
command: ./bin/retry bundle exec parallel_test ./spec/ --group-by filesize --type rspec
jobs:
install:
<<: *defaults
<<: *install_steps
install-ruby2.5:
<<: *defaults
<<: *install_ruby_dependencies
install-ruby2.4:
<<: *defaults
docker:
- image: circleci/ruby:2.4.4-stretch-node
environment: *ruby_environment
<<: *install_ruby_dependencies
build:
<<: *defaults
steps:
- *attach_workspace
- *install_system_dependencies
- run: ruby -e 'puts RUBY_VERSION' | tee /tmp/.ruby-version
- *restore_ruby_dependencies
- run: ./bin/rails assets:precompile
- save_cache:
key: precompiled-assets-{{ .Branch }}-{{ .Revision }}
paths:
- ./public/assets
- ./public/packs-test/
test-ruby2.5:
<<: *defaults
docker:
- image: circleci/ruby:2.5.1-stretch-node
environment: *ruby_environment
- image: circleci/postgres:10.3-alpine
environment:
POSTGRES_USER: root
- image: circleci/redis:4.0.9-alpine
<<: *test_steps
test-ruby2.4:
<<: *defaults
docker:
- image: circleci/ruby:2.4.4-stretch-node
environment: *ruby_environment
- image: circleci/postgres:10.3-alpine
environment:
POSTGRES_USER: root
- image: circleci/redis:4.0.9-alpine
<<: *test_steps
test-webui:
<<: *defaults
docker:
- image: circleci/node:8.11.1-stretch
steps:
- *attach_workspace
- run: ./bin/retry yarn test:jest
check-i18n:
<<: *defaults
steps:
- *attach_workspace
- run: ruby -e 'puts RUBY_VERSION' | tee /tmp/.ruby-version
- *restore_ruby_dependencies
- run: bundle exec i18n-tasks check-normalized
- run: bundle exec i18n-tasks unused
workflows:
version: 2
build-and-test:
jobs:
- install
- install-ruby2.5:
requires:
- install
- install-ruby2.4:
requires:
- install
- build:
requires:
- install-ruby2.5
- test-ruby2.5:
requires:
- install-ruby2.5
- build
- test-ruby2.4:
requires:
- install-ruby2.4
- build
- test-webui:
requires:
- install
- check-i18n:
requires:
- install-ruby2.5

View File

@@ -27,10 +27,8 @@ plugins:
enabled: true enabled: true
eslint: eslint:
enabled: true enabled: true
channel: eslint-4
rubocop: rubocop:
enabled: true enabled: true
channel: rubocop-0-54
scss-lint: scss-lint:
enabled: true enabled: true
exclude_patterns: exclude_patterns:

View File

@@ -11,4 +11,3 @@ vendor/bundle
*~ *~
postgres postgres
redis redis
elasticsearch

View File

@@ -13,29 +13,11 @@ DB_PORT=5432
DATABASE_URL=postgresql://$DATA_DB_USER:$DATA_DB_PASS@$DATA_DB_HOST/gonano DATABASE_URL=postgresql://$DATA_DB_USER:$DATA_DB_PASS@$DATA_DB_HOST/gonano
# Optional ElasticSearch configuration
ES_ENABLED=true
ES_HOST=$DATA_ELASTIC_HOST
ES_PORT=9200
# Optimizations
LD_PRELOAD=/data/lib/libjemalloc.so
# ImageMagick optimizations
MAGICK_TEMPORARY_PATH=/app/tmp
MAGICK_MEMORY_LIMIT=128MiB
MAGICK_MAP_LIMIT=64MiB
MAGICK_TIME_LIMIT=15
MAGICK_AREA_LIMIT=16MP
MAGICK_WIDTH_LIMIT=8KP
MAGICK_HEIGHT_LIMIT=8KP
# Federation # Federation
# Note: Changing LOCAL_DOMAIN at a later time will cause unwanted side effects, including breaking all existing federation. # Note: Changing LOCAL_DOMAIN or LOCAL_HTTPS at a later time will cause unwanted side effects.
# LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com. # LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com.
LOCAL_DOMAIN=${APP_NAME}.nanoapp.io LOCAL_DOMAIN=${APP_NAME}.nanoapp.io
LOCAL_HTTPS=false
# Changing LOCAL_HTTPS in production is no longer supported. (Mastodon will always serve https:// links)
# Use this only if you need to run mastodon on a different domain than the one used for federation. # Use this only if you need to run mastodon on a different domain than the one used for federation.
# You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md # You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md
@@ -49,6 +31,7 @@ LOCAL_DOMAIN=${APP_NAME}.nanoapp.io
# Application secrets # Application secrets
# Generate each with the `rake secret` task (`nanobox run bundle exec rake secret`) # Generate each with the `rake secret` task (`nanobox run bundle exec rake secret`)
PAPERCLIP_SECRET=$PAPERCLIP_SECRET
SECRET_KEY_BASE=$SECRET_KEY_BASE SECRET_KEY_BASE=$SECRET_KEY_BASE
OTP_SECRET=$OTP_SECRET OTP_SECRET=$OTP_SECRET
@@ -148,79 +131,9 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
# Cluster number setting for streaming API server. # Cluster number setting for streaming API server.
# If you comment out following line, cluster number will be `numOfCpuCores - 1`. # If you comment out following line, cluster number will be `numOfCpuCores - 1`.
# STREAMING_CLUSTER_NUM=1 STREAMING_CLUSTER_NUM=1
# Docker mastodon user # Docker mastodon user
# If you use Docker, you may want to assign UID/GID manually. # If you use Docker, you may want to assign UID/GID manually.
# UID=1000 # UID=1000
# GID=1000 # GID=1000
# LDAP authentication (optional)
# LDAP_ENABLED=true
# LDAP_HOST=localhost
# LDAP_PORT=389
# LDAP_METHOD=simple_tls
# LDAP_BASE=
# LDAP_BIND_DN=
# LDAP_PASSWORD=
# LDAP_UID=cn
# PAM authentication (optional)
# PAM authentication uses for the email generation the "email" pam variable
# and optional as fallback PAM_DEFAULT_SUFFIX
# The pam environment variable "email" is provided by:
# https://github.com/devkral/pam_email_extractor
# PAM_ENABLED=true
# Fallback Suffix for email address generation (nil by default)
# PAM_DEFAULT_SUFFIX=pam
# Name of the pam service (pam "auth" section is evaluated)
# PAM_DEFAULT_SERVICE=rpam
# Name of the pam service used for checking if an user can register (pam "account" section is evaluated) (nil (disabled) by default)
# PAM_CONTROLLED_SERVICE=rpam
# Global OAuth settings (optional) :
# If you have only one strategy, you may want to enable this
# OAUTH_REDIRECT_AT_SIGN_IN=true
# Optional CAS authentication (cf. omniauth-cas) :
# CAS_ENABLED=true
# CAS_URL=https://sso.myserver.com/
# CAS_HOST=sso.myserver.com/
# CAS_PORT=443
# CAS_SSL=true
# CAS_VALIDATE_URL=
# CAS_CALLBACK_URL=
# CAS_LOGOUT_URL=
# CAS_LOGIN_URL=
# CAS_UID_FIELD='user'
# CAS_CA_PATH=
# CAS_DISABLE_SSL_VERIFICATION=false
# CAS_UID_KEY='user'
# CAS_NAME_KEY='name'
# CAS_EMAIL_KEY='email'
# CAS_NICKNAME_KEY='nickname'
# CAS_FIRST_NAME_KEY='firstname'
# CAS_LAST_NAME_KEY='lastname'
# CAS_LOCATION_KEY='location'
# CAS_IMAGE_KEY='image'
# CAS_PHONE_KEY='phone'
# Optional SAML authentication (cf. omniauth-saml)
# SAML_ENABLED=true
# SAML_ACS_URL=
# SAML_ISSUER=http://localhost:3000/auth/auth/saml/callback
# SAML_IDP_SSO_TARGET_URL=https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO
# SAML_IDP_CERT=
# SAML_IDP_CERT_FINGERPRINT=
# SAML_NAME_IDENTIFIER_FORMAT=
# SAML_CERT=
# SAML_PRIVATE_KEY=
# SAML_SECURITY_WANT_ASSERTION_SIGNED=true
# SAML_SECURITY_WANT_ASSERTION_ENCRYPTED=true
# SAML_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true
# SAML_ATTRIBUTES_STATEMENTS_UID="urn:oid:0.9.2342.19200300.100.1.1"
# SAML_ATTRIBUTES_STATEMENTS_EMAIL="urn:oid:1.3.6.1.4.1.5923.1.1.1.6"
# SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.5.4.42"
# SAML_UID_ATTRIBUTE="urn:oid:0.9.2342.19200300.100.1.1"
# SAML_ATTRIBUTES_STATEMENTS_VERIFIED=
# SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL=

View File

@@ -9,17 +9,12 @@ DB_USER=postgres
DB_NAME=postgres DB_NAME=postgres
DB_PASS= DB_PASS=
DB_PORT=5432 DB_PORT=5432
# Optional ElasticSearch configuration
# ES_ENABLED=true
# ES_HOST=es
# ES_PORT=9200
# Federation # Federation
# Note: Changing LOCAL_DOMAIN at a later time will cause unwanted side effects, including breaking all existing federation. # Note: Changing LOCAL_DOMAIN or LOCAL_HTTPS at a later time will cause unwanted side effects.
# LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com. # LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com.
LOCAL_DOMAIN=example.com LOCAL_DOMAIN=example.com
LOCAL_HTTPS=true
# Changing LOCAL_HTTPS in production is no longer supported. (Mastodon will always serve https:// links)
# Use this only if you need to run mastodon on a different domain than the one used for federation. # Use this only if you need to run mastodon on a different domain than the one used for federation.
# You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md # You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md
@@ -33,6 +28,7 @@ LOCAL_DOMAIN=example.com
# Application secrets # Application secrets
# Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose) # Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
PAPERCLIP_SECRET=
SECRET_KEY_BASE= SECRET_KEY_BASE=
OTP_SECRET= OTP_SECRET=
@@ -81,17 +77,9 @@ SMTP_FROM_ADDRESS=notifications@example.com
# PAPERCLIP_ROOT_URL=/system # PAPERCLIP_ROOT_URL=/system
# Optional asset host for multi-server setups # Optional asset host for multi-server setups
# The asset host must allow cross origin request from WEB_DOMAIN or LOCAL_DOMAIN
# if WEB_DOMAIN is not set. For example, the server may have the
# following header field:
# Access-Control-Allow-Origin: https://example.com/
# CDN_HOST=https://assets.example.com # CDN_HOST=https://assets.example.com
# S3 (optional) # S3 (optional)
# The attachment host must allow cross origin request from WEB_DOMAIN or
# LOCAL_DOMAIN if WEB_DOMAIN is not set. For example, the server may have the
# following header field:
# Access-Control-Allow-Origin: https://192.168.1.123:9000/
# S3_ENABLED=true # S3_ENABLED=true
# S3_BUCKET= # S3_BUCKET=
# AWS_ACCESS_KEY_ID= # AWS_ACCESS_KEY_ID=
@@ -101,8 +89,6 @@ SMTP_FROM_ADDRESS=notifications@example.com
# S3_HOSTNAME=192.168.1.123:9000 # S3_HOSTNAME=192.168.1.123:9000
# S3 (Minio Config (optional) Please check Minio instance for details) # S3 (Minio Config (optional) Please check Minio instance for details)
# The attachment host must allow cross origin request - see the description
# above.
# S3_ENABLED=true # S3_ENABLED=true
# S3_BUCKET= # S3_BUCKET=
# AWS_ACCESS_KEY_ID= # AWS_ACCESS_KEY_ID=
@@ -114,15 +100,11 @@ SMTP_FROM_ADDRESS=notifications@example.com
# S3_SIGNATURE_VERSION= # S3_SIGNATURE_VERSION=
# Swift (optional) # Swift (optional)
# The attachment host must allow cross origin request - see the description
# above.
# SWIFT_ENABLED=true # SWIFT_ENABLED=true
# SWIFT_USERNAME= # SWIFT_USERNAME=
# For Keystone V3, the value for SWIFT_TENANT should be the project name # For Keystone V3, the value for SWIFT_TENANT should be the project name
# SWIFT_TENANT= # SWIFT_TENANT=
# SWIFT_PASSWORD= # SWIFT_PASSWORD=
# Some OpenStack V3 providers require PROJECT_ID (optional)
# SWIFT_PROJECT_ID=
# Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid # Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid
# issues with token rate-limiting during high load. # issues with token rate-limiting during high load.
# SWIFT_AUTH_URL= # SWIFT_AUTH_URL=
@@ -155,82 +137,3 @@ STREAMING_CLUSTER_NUM=1
# Maximum allowed character count # Maximum allowed character count
# MAX_TOOT_CHARS=500 # MAX_TOOT_CHARS=500
# LDAP authentication (optional)
# LDAP_ENABLED=true
# LDAP_HOST=localhost
# LDAP_PORT=389
# LDAP_METHOD=simple_tls
# LDAP_BASE=
# LDAP_BIND_DN=
# LDAP_PASSWORD=
# LDAP_UID=cn
# PAM authentication (optional)
# PAM authentication uses for the email generation the "email" pam variable
# and optional as fallback PAM_DEFAULT_SUFFIX
# The pam environment variable "email" is provided by:
# https://github.com/devkral/pam_email_extractor
# PAM_ENABLED=true
# Fallback email domain for email address generation (LOCAL_DOMAIN by default)
# PAM_EMAIL_DOMAIN=example.com
# Name of the pam service (pam "auth" section is evaluated)
# PAM_DEFAULT_SERVICE=rpam
# Name of the pam service used for checking if an user can register (pam "account" section is evaluated) (nil (disabled) by default)
# PAM_CONTROLLED_SERVICE=rpam
# Global OAuth settings (optional) :
# If you have only one strategy, you may want to enable this
# OAUTH_REDIRECT_AT_SIGN_IN=true
# Optional CAS authentication (cf. omniauth-cas) :
# CAS_ENABLED=true
# CAS_URL=https://sso.myserver.com/
# CAS_HOST=sso.myserver.com/
# CAS_PORT=443
# CAS_SSL=true
# CAS_VALIDATE_URL=
# CAS_CALLBACK_URL=
# CAS_LOGOUT_URL=
# CAS_LOGIN_URL=
# CAS_UID_FIELD='user'
# CAS_CA_PATH=
# CAS_DISABLE_SSL_VERIFICATION=false
# CAS_UID_KEY='user'
# CAS_NAME_KEY='name'
# CAS_EMAIL_KEY='email'
# CAS_NICKNAME_KEY='nickname'
# CAS_FIRST_NAME_KEY='firstname'
# CAS_LAST_NAME_KEY='lastname'
# CAS_LOCATION_KEY='location'
# CAS_IMAGE_KEY='image'
# CAS_PHONE_KEY='phone'
# Optional SAML authentication (cf. omniauth-saml)
# SAML_ENABLED=true
# SAML_ACS_URL=
# SAML_ISSUER=http://localhost:3000/auth/auth/saml/callback
# SAML_IDP_SSO_TARGET_URL=https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO
# SAML_IDP_CERT=
# SAML_IDP_CERT_FINGERPRINT=
# SAML_NAME_IDENTIFIER_FORMAT=
# SAML_CERT=
# SAML_PRIVATE_KEY=
# SAML_SECURITY_WANT_ASSERTION_SIGNED=true
# SAML_SECURITY_WANT_ASSERTION_ENCRYPTED=true
# SAML_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true
# SAML_ATTRIBUTES_STATEMENTS_UID="urn:oid:0.9.2342.19200300.100.1.1"
# SAML_ATTRIBUTES_STATEMENTS_EMAIL="urn:oid:1.3.6.1.4.1.5923.1.1.1.6"
# SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.16.840.1.113730.3.1.241"
# SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME="urn:oid:2.5.4.42"
# SAML_ATTRIBUTES_STATEMENTS_LAST_NAME="urn:oid:2.5.4.4"
# SAML_UID_ATTRIBUTE="urn:oid:0.9.2342.19200300.100.1.1"
# SAML_ATTRIBUTES_STATEMENTS_VERIFIED=
# SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL=
# Use HTTP proxy for outgoing request (optional)
# http_proxy=http://gateway.local:8118
# Access control for hidden service.
# ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
# If you use transparent proxy to access to hidden service, uncomment following for skipping private address check.
# HIDDEN_SERVICE_VIA_TRANSPARENT_PROXY=true

View File

@@ -1,9 +1,4 @@
# Node.js
NODE_ENV=test
# Federation # Federation
LOCAL_DOMAIN=cb6e6126.ngrok.io LOCAL_DOMAIN=cb6e6126.ngrok.io
LOCAL_HTTPS=true LOCAL_HTTPS=true
# test pam authentication OTP_SECRET=100c7faeef00caa29242f6b04156742bf76065771fd4117990c4282b8748ff3d99f8fdae97c982ab5bd2e6756a159121377cce4421f4a8ecd2d67bd7749a3fb4
PAM_ENABLED=true
PAM_DEFAULT_SERVICE=pam_test
PAM_CONTROLLED_SERVICE=pam_test_controlled

View File

@@ -7,23 +7,21 @@ env:
es6: true es6: true
jest: true jest: true
globals:
ATTACHMENT_HOST: false
parser: babel-eslint parser: babel-eslint
plugins: plugins:
- react - react
- jsx-a11y - jsx-a11y
- import - import
- promise
parserOptions: parserOptions:
sourceType: module sourceType: module
ecmaFeatures: ecmaFeatures:
experimentalObjectRestSpread: true arrowFunctions: true
jsx: true jsx: true
ecmaVersion: 2018 destructuring: true
modules: true
spread: true
settings: settings:
import/extensions: import/extensions:
@@ -116,43 +114,26 @@ rules:
react/self-closing-comp: error react/self-closing-comp: error
jsx-a11y/accessible-emoji: warn jsx-a11y/accessible-emoji: warn
jsx-a11y/alt-text: warn
jsx-a11y/anchor-has-content: warn jsx-a11y/anchor-has-content: warn
jsx-a11y/anchor-is-valid:
- warn
- components:
- Link
- NavLink
specialLink:
- to
aspect:
- noHref
- invalidHref
- preferButton
jsx-a11y/aria-activedescendant-has-tabindex: warn jsx-a11y/aria-activedescendant-has-tabindex: warn
jsx-a11y/aria-props: warn jsx-a11y/aria-props: warn
jsx-a11y/aria-proptypes: warn jsx-a11y/aria-proptypes: warn
jsx-a11y/aria-role: warn jsx-a11y/aria-role: warn
jsx-a11y/aria-unsupported-elements: warn jsx-a11y/aria-unsupported-elements: warn
jsx-a11y/heading-has-content: warn jsx-a11y/heading-has-content: warn
jsx-a11y/href-no-hash: warn
jsx-a11y/html-has-lang: warn jsx-a11y/html-has-lang: warn
jsx-a11y/iframe-has-title: warn jsx-a11y/iframe-has-title: warn
jsx-a11y/img-has-alt: warn
jsx-a11y/img-redundant-alt: warn jsx-a11y/img-redundant-alt: warn
jsx-a11y/interactive-supports-focus: warn
jsx-a11y/label-has-for: off jsx-a11y/label-has-for: off
jsx-a11y/mouse-events-have-key-events: warn jsx-a11y/mouse-events-have-key-events: warn
jsx-a11y/no-access-key: warn jsx-a11y/no-access-key: warn
jsx-a11y/no-distracting-elements: warn jsx-a11y/no-distracting-elements: warn
jsx-a11y/no-noninteractive-element-interactions:
- warn
- handlers:
- onClick
jsx-a11y/no-onchange: warn jsx-a11y/no-onchange: warn
jsx-a11y/no-redundant-roles: warn jsx-a11y/no-redundant-roles: warn
jsx-a11y/no-static-element-interactions: jsx-a11y/onclick-has-focus: warn
- warn jsx-a11y/onclick-has-role: warn
- handlers:
- onClick
jsx-a11y/role-has-required-aria-props: warn jsx-a11y/role-has-required-aria-props: warn
jsx-a11y/role-supports-aria-props: off jsx-a11y/role-supports-aria-props: off
jsx-a11y/scope: warn jsx-a11y/scope: warn
@@ -171,5 +152,3 @@ rules:
- "app/javascript/**/__tests__/**" - "app/javascript/**/__tests__/**"
import/no-unresolved: error import/no-unresolved: error
import/no-webpack-loader-syntax: error import/no-webpack-loader-syntax: error
promise/catch-or-return: error

View File

@@ -1,9 +1,3 @@
---
name: Bug Report
about: Create a report to help us improve
---
[Issue text goes here]. [Issue text goes here].
* * * * * * * *

View File

@@ -1,11 +0,0 @@
---
name: Feature Request
about: Suggest an idea for this project
---
[Issue text goes here].
* * * *
- [ ] I searched or browsed the repos other issues to ensure this is not a duplicate.

3
.gitignore vendored
View File

@@ -36,10 +36,9 @@ config/deploy/*
.vscode/ .vscode/
.idea/ .idea/
# Ignore postgres + redis + elasticsearch volume optionally created by docker-compose # Ignore postgres + redis volume optionally created by docker-compose
postgres postgres
redis redis
elasticsearch
# Ignore Apple files # Ignore Apple files
.DS_Store .DS_Store

View File

@@ -107,8 +107,5 @@ Style/RegexpLiteral:
Style/SymbolArray: Style/SymbolArray:
Enabled: false Enabled: false
Style/TrailingCommaInArrayLiteral: Style/TrailingCommaInLiteral:
EnforcedStyleForMultiline: 'comma'
Style/TrailingCommaInHashLiteral:
EnforcedStyleForMultiline: 'comma' EnforcedStyleForMultiline: 'comma'

View File

@@ -1 +1 @@
2.5.1 2.4.2

View File

@@ -3,12 +3,12 @@ cache:
bundler: true bundler: true
yarn: true yarn: true
directories: directories:
- node_modules - node_modules
- public/assets - public/assets
- public/packs-test - public/packs-test
- tmp/cache/babel-loader - tmp/cache/babel-loader
dist: trusty dist: trusty
sudo: false sudo: required
notifications: notifications:
email: false email: false
@@ -18,43 +18,42 @@ env:
- LOCAL_DOMAIN=cb6e6126.ngrok.io - LOCAL_DOMAIN=cb6e6126.ngrok.io
- LOCAL_HTTPS=true - LOCAL_HTTPS=true
- RAILS_ENV=test - RAILS_ENV=test
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
- PARALLEL_TEST_PROCESSORS=2 - PARALLEL_TEST_PROCESSORS=2
- ALLOW_NOPAM=true - "PATH=$HOME:$PATH"
addons: addons:
postgresql: 9.4 postgresql: 9.4
apt: apt:
sources: sources:
- trusty-media - trusty-media
- sourceline: deb https://dl.yarnpkg.com/debian/ stable main - sourceline: deb https://dl.yarnpkg.com/debian/ stable main
key_url: https://dl.yarnpkg.com/debian/pubkey.gpg key_url: https://dl.yarnpkg.com/debian/pubkey.gpg
packages: packages:
- ffmpeg - ffmpeg
- libicu-dev - libicu-dev
- libprotobuf-dev - libprotobuf-dev
- protobuf-compiler - protobuf-compiler
- yarn - yarn
rvm: rvm:
- 2.4.3 - 2.3.4
- 2.5.1 - 2.4.2
services: services:
- redis-server - redis-server
install: install:
- nvm install - nvm install
- bundle install --path=vendor/bundle --with pam_authentication --without development production --retry=3 --jobs=16 - bundle install --path=vendor/bundle --without development production --retry=3 --jobs=16
- yarn install - yarn install
# https://github.com/travis-ci/travis-ci/issues/9333
before_install:
- gem install bundler
before_script: before_script:
- travis_wait ./bin/rails parallel:create parallel:load_schema parallel:prepare assets:precompile - bundle exec rake parallel:create parallel:load_schema parallel:prepare
- bundle exec rails assets:precompile
- ln -s /usr/bin/x86_64-linux-gnu-g++-6 "$HOME/g++"
script: script:
- travis_retry bundle exec parallel_test spec/ --group-by filesize --type rspec - travis_retry bundle exec parallel_test spec/ --group-by filesize --type rspec
- yarn run test:jest - yarn test
- bundle exec i18n-tasks check-normalized && bundle exec i18n-tasks unused - bundle exec i18n-tasks check-normalized && bundle exec i18n-tasks unused

View File

@@ -1,450 +0,0 @@
Mastodon is available on [GitHub](https://github.com/tootsuite/mastodon)
and provided thanks to the work of the following contributors:
* [Gargron](https://github.com/Gargron)
* [ykzts](https://github.com/ykzts)
* [mjankowski](https://github.com/mjankowski)
* [akihikodaki](https://github.com/akihikodaki)
* [unarist](https://github.com/unarist)
* [yiskah](https://github.com/yiskah)
* [m4sk1n](https://github.com/m4sk1n)
* [nolanlawson](https://github.com/nolanlawson)
* [sorin-davidoi](https://github.com/sorin-davidoi)
* [abcang](https://github.com/abcang)
* [ThibG](https://github.com/ThibG)
* [lynlynlynx](https://github.com/lynlynlynx)
* [alpaca-tc](https://github.com/alpaca-tc)
* [nclm](https://github.com/nclm)
* [ineffyble](https://github.com/ineffyble)
* [jeroenpraat](https://github.com/jeroenpraat)
* [blackle](https://github.com/blackle)
* [Quent-in](https://github.com/Quent-in)
* [JantsoP](https://github.com/JantsoP)
* [nullkal](https://github.com/nullkal)
* [yookoala](https://github.com/yookoala)
* [ysksn](https://github.com/ysksn)
* [ashfurrow](https://github.com/ashfurrow)
* [eramdam](https://github.com/eramdam)
* [mayaeh](https://github.com/mayaeh)
* [zunda](https://github.com/zunda)
* [ticky](https://github.com/ticky)
* [masarakki](https://github.com/masarakki)
* [Wonderfall](https://github.com/Wonderfall)
* [matteoaquila](https://github.com/matteoaquila)
* [rkarabut](https://github.com/rkarabut)
* [stephenburgess8](https://github.com/stephenburgess8)
* [Kjwon15](https://github.com/Kjwon15)
* [Artoria2e5](https://github.com/Artoria2e5)
* [yukimochi](https://github.com/yukimochi)
* [marrus-sh](https://github.com/marrus-sh)
* [krainboltgreene](https://github.com/krainboltgreene)
* [renatolond](https://github.com/renatolond)
* [BoFFire](https://github.com/BoFFire)
* [clworld](https://github.com/clworld)
* [danhunsaker](https://github.com/danhunsaker)
* [patf](https://github.com/patf)
* [Quenty31](https://github.com/Quenty31)
* [MitarashiDango](https://github.com/MitarashiDango)
* [Aldarone](https://github.com/Aldarone)
* [JeanGauthier](https://github.com/JeanGauthier)
* [kschaper](https://github.com/kschaper)
* [takayamaki](https://github.com/takayamaki)
* [adbelle](https://github.com/adbelle)
* [evanminto](https://github.com/evanminto)
* [mabkenar](https://github.com/mabkenar)
* [MightyPork](https://github.com/MightyPork)
* [beatrix-bitrot](https://github.com/beatrix-bitrot)
* [yhirano55](https://github.com/yhirano55)
* [camponez](https://github.com/camponez)
* [aschmitz](https://github.com/aschmitz)
* [fpiesche](https://github.com/fpiesche)
* [gandaro](https://github.com/gandaro)
* [johnsudaar](https://github.com/johnsudaar)
* [trebmuh](https://github.com/trebmuh)
* [Sylvhem](https://github.com/Sylvhem)
* [lindwurm](https://github.com/lindwurm)
* [voidsatisfaction](https://github.com/voidsatisfaction)
* [neetshin](https://github.com/neetshin)
* [valentin2105](https://github.com/valentin2105)
* [hikari-no-yume](https://github.com/hikari-no-yume)
* [Angristan](https://github.com/Angristan)
* [seefood](https://github.com/seefood)
* [jackjennings](https://github.com/jackjennings)
* [hcmiya](https://github.com/hcmiya)
* [nightpool](https://github.com/nightpool)
* [salvadorpla](https://github.com/salvadorpla)
* [expenses](https://github.com/expenses)
* [walf443](https://github.com/walf443)
* [JoelQ](https://github.com/JoelQ)
* [mistydemeo](https://github.com/mistydemeo)
* [dunn](https://github.com/dunn)
* [xqus](https://github.com/xqus)
* [pfm-eyesightjp](https://github.com/pfm-eyesightjp)
* [fakenine](https://github.com/fakenine)
* [tsuwatch](https://github.com/tsuwatch)
* [victorhck](https://github.com/victorhck)
* [puckipedia](https://github.com/puckipedia)
* [contraexemplo](https://github.com/contraexemplo)
* [kazu9su](https://github.com/kazu9su)
* [Komic](https://github.com/Komic)
* [diomed](https://github.com/diomed)
* [rainyday](https://github.com/rainyday)
* [kadiix](https://github.com/kadiix)
* [kodacs](https://github.com/kodacs)
* [ProgVal](https://github.com/ProgVal)
* [sterdev](https://github.com/sterdev)
* [TheKinrar](https://github.com/TheKinrar)
* [AA4ch1](https://github.com/AA4ch1)
* [alexgleason](https://github.com/alexgleason)
* [cpytel](https://github.com/cpytel)
* [northerner](https://github.com/northerner)
* [hnrysmth](https://github.com/hnrysmth)
* [hugogameiro](https://github.com/hugogameiro)
* [JohnD28](https://github.com/JohnD28)
* [znz](https://github.com/znz)
* [Naouak](https://github.com/Naouak)
* [rtucker](https://github.com/rtucker)
* [reneklacan](https://github.com/reneklacan)
* [KScl](https://github.com/KScl)
* [SerCom-KC](https://github.com/SerCom-KC)
* [tcitworld](https://github.com/tcitworld)
* [geta6](https://github.com/geta6)
* [goofy-bz](https://github.com/goofy-bz)
* [happycoloredbanana](https://github.com/happycoloredbanana)
* [leopku](https://github.com/leopku)
* [SansPseudoFix](https://github.com/SansPseudoFix)
* [tomfhowe](https://github.com/tomfhowe)
* [noraworld](https://github.com/noraworld)
* [fvh-P](https://github.com/fvh-P)
* [178inaba](https://github.com/178inaba)
* [devkral](https://github.com/devkral)
* [alyssais](https://github.com/alyssais)
* [kodnaplakal](https://github.com/kodnaplakal)
* [stalker314314](https://github.com/stalker314314)
* [huertanix](https://github.com/huertanix)
* [genesixx](https://github.com/genesixx)
* [fhemberger](https://github.com/fhemberger)
* [halkeye](https://github.com/halkeye)
* [treby](https://github.com/treby)
* [d6rkaiz](https://github.com/d6rkaiz)
* [jpdevries](https://github.com/jpdevries)
* [rndm-stranger](https://github.com/rndm-stranger)
* [saper](https://github.com/saper)
* [nevillepark](https://github.com/nevillepark)
* [ornithocoder](https://github.com/ornithocoder)
* [pierreozoux](https://github.com/pierreozoux)
* [ramlmn](https://github.com/ramlmn)
* [harukasan](https://github.com/harukasan)
* [stamak](https://github.com/stamak)
* [Eychics](https://github.com/Eychics)
* [thor-the-norseman](https://github.com/thor-the-norseman)
* [0x70b1a5](https://github.com/0x70b1a5)
* [gled-rs](https://github.com/gled-rs)
* [R0ckweb](https://github.com/R0ckweb)
* [esetomo](https://github.com/esetomo)
* [foxiehkins](https://github.com/foxiehkins)
* [sdukhovni](https://github.com/sdukhovni)
* [unsmell](https://github.com/unsmell)
* [chriswmartin](https://github.com/chriswmartin)
* [vahnj](https://github.com/vahnj)
* [ikuradon](https://github.com/ikuradon)
* [AndreLewin](https://github.com/AndreLewin)
* [redtachyons](https://github.com/redtachyons)
* [thurloat](https://github.com/thurloat)
* [aaribaud](https://github.com/aaribaud)
* [estuans](https://github.com/estuans)
* [dissolve](https://github.com/dissolve)
* [PurpleBooth](https://github.com/PurpleBooth)
* [bradurani](https://github.com/bradurani)
* [wavebeem](https://github.com/wavebeem)
* [bruwalfas](https://github.com/bruwalfas)
* [foxsan48](https://github.com/foxsan48)
* [wchristian](https://github.com/wchristian)
* [muffinista](https://github.com/muffinista)
* [cdutson](https://github.com/cdutson)
* [farlistener](https://github.com/farlistener)
* [DavidLibeau](https://github.com/DavidLibeau)
* [SirCmpwn](https://github.com/SirCmpwn)
* [MasterGroosha](https://github.com/MasterGroosha)
* [Fjoerfoks](https://github.com/Fjoerfoks)
* [fmauNeko](https://github.com/fmauNeko)
* [gloaec](https://github.com/gloaec)
* [greysteil](https://github.com/greysteil)
* [unstabler](https://github.com/unstabler)
* [potato4d](https://github.com/potato4d)
* [h-izumi](https://github.com/h-izumi)
* [ErikXXon](https://github.com/ErikXXon)
* [ian-kelling](https://github.com/ian-kelling)
* [foozmeat](https://github.com/foozmeat)
* [jasonrhodes](https://github.com/jasonrhodes)
* [asm](https://github.com/asm)
* [jviide](https://github.com/jviide)
* [crakaC](https://github.com/crakaC)
* [tkbky](https://github.com/tkbky)
* [Kazhnuz](https://github.com/Kazhnuz)
* [alimony](https://github.com/alimony)
* [mig5](https://github.com/mig5)
* [ndarville](https://github.com/ndarville)
* [Abzol](https://github.com/Abzol)
* [xPaw](https://github.com/xPaw)
* [raymestalez](https://github.com/raymestalez)
* [sim6](https://github.com/sim6)
* [ekiru](https://github.com/ekiru)
* [Technowix](https://github.com/Technowix)
* [ThomasLeister](https://github.com/ThomasLeister)
* [mcat-ee](https://github.com/mcat-ee)
* [tototoshi](https://github.com/tototoshi)
* [VirtuBox](https://github.com/VirtuBox)
* [kaniini](https://github.com/kaniini)
* [vayan](https://github.com/vayan)
* [yannicka](https://github.com/yannicka)
* [ikasoumen](https://github.com/ikasoumen)
* [zacanger](https://github.com/zacanger)
* [amazedkoumei](https://github.com/amazedkoumei)
* [anon5r](https://github.com/anon5r)
* [codl](https://github.com/codl)
* [barzamin](https://github.com/barzamin)
* [fhalna](https://github.com/fhalna)
* [haoyayoi](https://github.com/haoyayoi)
* [ik11235](https://github.com/ik11235)
* [kawax](https://github.com/kawax)
* [007lva](https://github.com/007lva)
* [matsurai25](https://github.com/matsurai25)
* [mecab](https://github.com/mecab)
* [nicobz25](https://github.com/nicobz25)
* [oliverkeeble](https://github.com/oliverkeeble)
* [pinfort](https://github.com/pinfort)
* [rbaumert](https://github.com/rbaumert)
* [usagi-f](https://github.com/usagi-f)
* [vidarlee](https://github.com/vidarlee)
* [vjackson725](https://github.com/vjackson725)
* [wxcafe](https://github.com/wxcafe)
* [rinsuki](https://github.com/rinsuki)
* [cygnan](https://github.com/cygnan)
* [Awea](https://github.com/Awea)
* [halcy](https://github.com/halcy)
* [bounshi](https://github.com/bounshi)
* [8398a7](https://github.com/8398a7)
* [857b](https://github.com/857b)
* [unascribed](https://github.com/unascribed)
* [Aguay-val](https://github.com/Aguay-val)
* [knu](https://github.com/knu)
* [alxrcs](https://github.com/alxrcs)
* [console-cowboy](https://github.com/console-cowboy)
* [pointlessone](https://github.com/pointlessone)
* [a2](https://github.com/a2)
* [0xa](https://github.com/0xa)
* [virtualpain](https://github.com/virtualpain)
* [sapphirus](https://github.com/sapphirus)
* [amandavisconti](https://github.com/amandavisconti)
* [ameliavoncat](https://github.com/ameliavoncat)
* [ilpianista](https://github.com/ilpianista)
* [andydrop](https://github.com/andydrop)
* [schas002](https://github.com/schas002)
* [jumbosushi](https://github.com/jumbosushi)
* [ayumin](https://github.com/ayumin)
* [BaptisteGelez](https://github.com/BaptisteGelez)
* [bzg](https://github.com/bzg)
* [benediktg](https://github.com/benediktg)
* [blakebarnett](https://github.com/blakebarnett)
* [bradj](https://github.com/bradj)
* [brycied00d](https://github.com/brycied00d)
* [carlosjs23](https://github.com/carlosjs23)
* [cgxxx](https://github.com/cgxxx)
* [chrisheninger](https://github.com/chrisheninger)
* [chris-martin](https://github.com/chris-martin)
* [DoubleMalt](https://github.com/DoubleMalt)
* [Moosh-be](https://github.com/Moosh-be)
* [Motoma](https://github.com/Motoma)
* [chriswk](https://github.com/chriswk)
* [csu](https://github.com/csu)
* [kklleemm](https://github.com/kklleemm)
* [monsterpit-daggertooth](https://github.com/monsterpit-daggertooth)
* [watilde](https://github.com/watilde)
* [daprice](https://github.com/daprice)
* [dar5hak](https://github.com/dar5hak)
* [kant](https://github.com/kant)
* [singingwolfboy](https://github.com/singingwolfboy)
* [davidcelis](https://github.com/davidcelis)
* [yipdw](https://github.com/yipdw)
* [debanshuk](https://github.com/debanshuk)
* [dblandin](https://github.com/dblandin)
* [aranaur](https://github.com/aranaur)
* [d3vgru](https://github.com/d3vgru)
* [Elizafox](https://github.com/Elizafox)
* [ericblade](https://github.com/ericblade)
* [mikoim](https://github.com/mikoim)
* [siuying](https://github.com/siuying)
* [hattori6789](https://github.com/hattori6789)
* [algernon](https://github.com/algernon)
* [Fastbyte01](https://github.com/Fastbyte01)
* [myfreeweb](https://github.com/myfreeweb)
* [gfaivre](https://github.com/gfaivre)
* [Fiaxhs](https://github.com/Fiaxhs)
* [reedcourty](https://github.com/reedcourty)
* [anneau](https://github.com/anneau)
* [HellPie](https://github.com/HellPie)
* [Habu-Kagumba](https://github.com/Habu-Kagumba)
* [hinaloe](https://github.com/hinaloe)
* [suzukaze](https://github.com/suzukaze)
* [Hiromi-Kai](https://github.com/Hiromi-Kai)
* [musashino205](https://github.com/musashino205)
* [iwaim](https://github.com/iwaim)
* [valrus](https://github.com/valrus)
* [IMcD23](https://github.com/IMcD23)
* [yi0713](https://github.com/yi0713)
* [immae](https://github.com/immae)
* [iblech](https://github.com/iblech)
* [jack-michaud](https://github.com/jack-michaud)
* [Floppy](https://github.com/Floppy)
* [loomchild](https://github.com/loomchild)
* [docjkl](https://github.com/docjkl)
* [TrollDecker](https://github.com/TrollDecker)
* [jmontane](https://github.com/jmontane)
* [jonathanklee](https://github.com/jonathanklee)
* [jguerder](https://github.com/jguerder)
* [Jehops](https://github.com/Jehops)
* [joshuap](https://github.com/joshuap)
* [Tiwy57](https://github.com/Tiwy57)
* [xuv](https://github.com/xuv)
* [Jnsll](https://github.com/Jnsll)
* [j0k3r](https://github.com/j0k3r)
* [KEINOS](https://github.com/KEINOS)
* [futoase](https://github.com/futoase)
* [abjectio](https://github.com/abjectio)
* [mkody](https://github.com/mkody)
* [connyduck](https://github.com/connyduck)
* [k0ta0uchi](https://github.com/k0ta0uchi)
* [KrzysiekJ](https://github.com/KrzysiekJ)
* [leowzukw](https://github.com/leowzukw)
* [lmorchard](https://github.com/lmorchard)
* [cacheflow](https://github.com/cacheflow)
* [ldidry](https://github.com/ldidry)
* [jemus42](https://github.com/jemus42)
* [lfuelling](https://github.com/lfuelling)
* [Grabacr07](https://github.com/Grabacr07)
* [mistermantas](https://github.com/mistermantas)
* [wirehack7](https://github.com/wirehack7)
* [marvinkopf](https://github.com/marvinkopf)
* [otsune](https://github.com/otsune)
* [m-blc](https://github.com/m-blc)
* [matt-auckland](https://github.com/matt-auckland)
* [mattjmattj](https://github.com/mattjmattj)
* [mtparet](https://github.com/mtparet)
* [maximeborges](https://github.com/maximeborges)
* [minacle](https://github.com/minacle)
* [michaeljdeeb](https://github.com/michaeljdeeb)
* [Themimitoof](https://github.com/Themimitoof)
* [cyweo](https://github.com/cyweo)
* [M1dgard](https://github.com/M1dgard)
* [mike-burns](https://github.com/mike-burns)
* [verymilan](https://github.com/verymilan)
* [milmazz](https://github.com/milmazz)
* [Mnkai](https://github.com/Mnkai)
* [mitchhentges](https://github.com/mitchhentges)
* [moritzheiber](https://github.com/moritzheiber)
* [mouse-reeve](https://github.com/mouse-reeve)
* [lae](https://github.com/lae)
* [Nanamachi](https://github.com/Nanamachi)
* [ngerakines](https://github.com/ngerakines)
* [vonneudeck](https://github.com/vonneudeck)
* [Ninetailed](https://github.com/Ninetailed)
* [k24](https://github.com/k24)
* [noiob](https://github.com/noiob)
* [kwaio](https://github.com/kwaio)
* [norayr](https://github.com/norayr)
* [joyeusenoelle](https://github.com/joyeusenoelle)
* [OlivierNicole](https://github.com/OlivierNicole)
* [Otakan951](https://github.com/Otakan951)
* [fahy](https://github.com/fahy)
* [Pangoraw](https://github.com/Pangoraw)
* [pwoolcoc](https://github.com/pwoolcoc)
* [peterkeen](https://github.com/peterkeen)
* [petzah](https://github.com/petzah)
* [ignisf](https://github.com/ignisf)
* [rfwatson](https://github.com/rfwatson)
* [rfreebern](https://github.com/rfreebern)
* [sylph01](https://github.com/sylph01)
* [staticsafe](https://github.com/staticsafe)
* [snwh](https://github.com/snwh)
* [skoji](https://github.com/skoji)
* [ScienJus](https://github.com/ScienJus)
* [larkinscott](https://github.com/larkinscott)
* [imolein](https://github.com/imolein)
* [blinry](https://github.com/blinry)
* [Noiwex](https://github.com/Noiwex)
* [yuki764](https://github.com/yuki764)
* [shnjp](https://github.com/shnjp)
* [ernix](https://github.com/ernix)
* [rosylilly](https://github.com/rosylilly)
* [shouko](https://github.com/shouko)
* [sossii](https://github.com/sossii)
* [StefOfficiel](https://github.com/StefOfficiel)
* [svetlik](https://github.com/svetlik)
* [dereckson](https://github.com/dereckson)
* [theboss](https://github.com/theboss)
* [takp](https://github.com/takp)
* [tkusano](https://github.com/tkusano)
* [TheInventrix](https://github.com/TheInventrix)
* [shug0](https://github.com/shug0)
* [Fortyseven](https://github.com/Fortyseven)
* [tobypinder](https://github.com/tobypinder)
* [tomosm](https://github.com/tomosm)
* [TomoyaShibata](https://github.com/TomoyaShibata)
* [TrashMacNugget](https://github.com/TrashMacNugget)
* [treyssatvincent](https://github.com/treyssatvincent)
* [optikfluffel](https://github.com/optikfluffel)
* [vmincev](https://github.com/vmincev)
* [waldyrious](https://github.com/waldyrious)
* [tahnok](https://github.com/tahnok)
* [YDrogen](https://github.com/YDrogen)
* [YOSHIOKAEiichiro](https://github.com/YOSHIOKAEiichiro)
* [S-YOU](https://github.com/S-YOU)
* [YaQ00](https://github.com/YaQ00)
* [yanakend](https://github.com/yanakend)
* [orzFly](https://github.com/orzFly)
* [chansuke](https://github.com/chansuke)
* [yuntan](https://github.com/yuntan)
* [LogicalDash](https://github.com/LogicalDash)
* [ZiiX](https://github.com/ZiiX)
* [benklop](https://github.com/benklop)
* [caasi](https://github.com/caasi)
* [caesarologia](https://github.com/caesarologia)
* [chrolis](https://github.com/chrolis)
* [cormojs](https://github.com/cormojs)
* [cpsdqs](https://github.com/cpsdqs)
* [d0p1s4m4](https://github.com/d0p1s4m4)
* [evilny0](https://github.com/evilny0)
* [febrezo](https://github.com/febrezo)
* [fsubal](https://github.com/fsubal)
* [dikky1218](https://github.com/dikky1218)
* [gentarok](https://github.com/gentarok)
* [hakoai](https://github.com/hakoai)
* [chaosbunker](https://github.com/chaosbunker)
* [isati](https://github.com/isati)
* [jkap](https://github.com/jkap)
* [jirayudech](https://github.com/jirayudech)
* [jukper](https://github.com/jukper)
* [karlyeurl](https://github.com/karlyeurl)
* [kedamaDQ](https://github.com/kedamaDQ)
* [kuro5hin](https://github.com/kuro5hin)
* [maxypy](https://github.com/maxypy)
* [marcus-herrmann](https://github.com/marcus-herrmann)
* [mshrtkch](https://github.com/mshrtkch)
* [muan](https://github.com/muan)
* [rch850](https://github.com/rch850)
* [roikale](https://github.com/roikale)
* [rysiekpl](https://github.com/rysiekpl)
* [saturday06](https://github.com/saturday06)
* [scriptjunkie](https://github.com/scriptjunkie)
* [seekr](https://github.com/seekr)
* [syui](https://github.com/syui)
* [tackeyy](https://github.com/tackeyy)
* [tmyt](https://github.com/tmyt)
* [utam0k](https://github.com/utam0k)
* [vpzomtrrfrt](https://github.com/vpzomtrrfrt)
* [walfie](https://github.com/walfie)
* [y-temp4](https://github.com/y-temp4)
* [ymmtmdk](https://github.com/ymmtmdk)
This document is provided for informational purposes only. Since it is only updated once per release, the version you are looking at may be currently out of date. To see the full list of contributors, consider looking at the [git history](https://github.com/tootsuite/mastodon/graphs/contributors) instead.

View File

@@ -83,9 +83,4 @@ It is expected that you have a working development environment set up (see back-
If the JavaScript or CSS assets won't compile due to a syntax error, it's a good sign that the pull request isn't ready for submission yet. If the JavaScript or CSS assets won't compile due to a syntax error, it's a good sign that the pull request isn't ready for submission yet.
## Translate
You can contribute to translating Mastodon via Weblate at [weblate.joinmastodon.org](https://weblate.joinmastodon.org/).
[![Mastodon translation statistics by language](https://weblate.joinmastodon.org/widgets/mastodon/-/multi-auto.svg)](https://weblate.joinmastodon.org/)
</blockquote> </blockquote>

View File

@@ -1,12 +1,10 @@
FROM ruby:2.4.4-alpine3.6 FROM ruby:2.4.2-alpine3.6
LABEL maintainer="https://github.com/tootsuite/mastodon" \ LABEL maintainer="https://github.com/tootsuite/mastodon" \
description="Your self-hosted, globally interconnected microblogging community" description="A GNU Social-compatible microblogging server"
ARG UID=991 ENV UID=991 GID=991 \
ARG GID=991 RAILS_SERVE_STATIC_FILES=true \
ENV RAILS_SERVE_STATIC_FILES=true \
RAILS_ENV=production NODE_ENV=production RAILS_ENV=production NODE_ENV=production
ARG YARN_VERSION=1.3.2 ARG YARN_VERSION=1.3.2
@@ -40,8 +38,8 @@ RUN apk -U upgrade \
nodejs \ nodejs \
nodejs-npm \ nodejs-npm \
protobuf \ protobuf \
su-exec \
tini \ tini \
tzdata \
&& update-ca-certificates \ && update-ca-certificates \
&& mkdir -p /tmp/src /opt \ && mkdir -p /tmp/src /opt \
&& wget -O yarn.tar.gz "https://github.com/yarnpkg/yarn/releases/download/v$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \ && wget -O yarn.tar.gz "https://github.com/yarnpkg/yarn/releases/download/v$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
@@ -63,26 +61,18 @@ RUN apk -U upgrade \
&& rm -rf /tmp/* /var/cache/apk/* && rm -rf /tmp/* /var/cache/apk/*
COPY Gemfile Gemfile.lock package.json yarn.lock .yarnclean /mastodon/ COPY Gemfile Gemfile.lock package.json yarn.lock .yarnclean /mastodon/
COPY stack-fix.c /lib
RUN gcc -shared -fPIC /lib/stack-fix.c -o /lib/stack-fix.so
RUN rm /lib/stack-fix.c
RUN bundle config build.nokogiri --with-iconv-lib=/usr/local/lib --with-iconv-include=/usr/local/include \ RUN bundle config build.nokogiri --with-iconv-lib=/usr/local/lib --with-iconv-include=/usr/local/include \
&& bundle install -j$(getconf _NPROCESSORS_ONLN) --deployment --without test development \ && bundle install -j$(getconf _NPROCESSORS_ONLN) --deployment --without test development \
&& yarn --pure-lockfile \ && yarn --pure-lockfile \
&& yarn cache clean && yarn cache clean
RUN addgroup -g ${GID} mastodon && adduser -h /mastodon -s /bin/sh -D -G mastodon -u ${UID} mastodon \
&& mkdir -p /mastodon/public/system /mastodon/public/assets /mastodon/public/packs \
&& chown -R mastodon:mastodon /mastodon/public
COPY . /mastodon COPY . /mastodon
RUN chown -R mastodon:mastodon /mastodon COPY docker_entrypoint.sh /usr/local/bin/run
RUN chmod +x /usr/local/bin/run
VOLUME /mastodon/public/system /mastodon/public/assets /mastodon/public/packs VOLUME /mastodon/public/system /mastodon/public/assets /mastodon/public/packs
USER mastodon ENTRYPOINT ["/usr/local/bin/run"]
ENV LD_PRELOAD=/lib/stack-fix.so
ENTRYPOINT ["/sbin/tini", "--"]

121
Gemfile
View File

@@ -1,122 +1,99 @@
# frozen_string_literal: true # frozen_string_literal: true
source 'https://rubygems.org' source 'https://rubygems.org'
ruby '>= 2.3.0', '< 2.6.0' ruby '>= 2.3.0', '< 2.5.0'
gem 'pkg-config', '~> 1.3' gem 'pkg-config', '~> 1.2'
gem 'puma', '~> 3.11' gem 'puma', '~> 3.10'
gem 'rails', '~> 5.2.0' gem 'rails', '~> 5.1.4'
gem 'uglifier', '~> 3.2'
gem 'hamlit-rails', '~> 0.2' gem 'hamlit-rails', '~> 0.2'
gem 'pg', '~> 1.0' gem 'pg', '~> 0.20'
gem 'pghero', '~> 2.1' gem 'pghero', '~> 1.7'
gem 'dotenv-rails', '~> 2.2', '< 2.3' gem 'dotenv-rails', '~> 2.2'
gem 'aws-sdk-s3', '~> 1.9', require: false gem 'aws-sdk', '~> 2.10', require: false
gem 'fog-core', '~> 1.45' gem 'fog-core', '~> 1.45'
gem 'fog-local', '~> 0.5', require: false gem 'fog-local', '~> 0.4', require: false
gem 'fog-openstack', '~> 0.1', require: false gem 'fog-openstack', '~> 0.1', require: false
gem 'paperclip', '~> 6.0' gem 'paperclip', '~> 5.1'
gem 'paperclip-av-transcoder', '~> 0.6' gem 'paperclip-av-transcoder', '~> 0.6'
gem 'streamio-ffmpeg', '~> 3.0' gem 'posix-spawn'
gem 'active_model_serializers', '~> 0.10' gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.5' gem 'addressable', '~> 2.5'
gem 'bootsnap', '~> 1.3' gem 'bootsnap'
gem 'browser' gem 'browser'
gem 'charlock_holmes', '~> 0.7.6' gem 'charlock_holmes', '~> 0.7.5'
gem 'iso-639' gem 'iso-639'
gem 'chewy', '~> 5.0'
gem 'cld3', '~> 3.2.0' gem 'cld3', '~> 3.2.0'
gem 'devise', '~> 4.4' gem 'devise', '~> 4.2'
gem 'devise-two-factor', '~> 3.0' gem 'devise-two-factor', '~> 3.0'
gem 'doorkeeper', '~> 4.2'
group :pam_authentication, optional: true do
gem 'devise_pam_authenticatable2', '~> 9.1'
end
gem 'net-ldap', '~> 0.10'
gem 'omniauth-cas', '~> 1.1'
gem 'omniauth-saml', '~> 1.10'
gem 'omniauth', '~> 1.2'
gem 'doorkeeper', '~> 4.2', '< 4.3'
gem 'fast_blank', '~> 1.0' gem 'fast_blank', '~> 1.0'
gem 'fastimage' gem 'goldfinger', '~> 2.0'
gem 'goldfinger', '~> 2.1'
gem 'hiredis', '~> 0.6' gem 'hiredis', '~> 0.6'
gem 'redis-namespace', '~> 1.5' gem 'redis-namespace', '~> 1.5'
gem 'html2text'
gem 'htmlentities', '~> 4.3' gem 'htmlentities', '~> 4.3'
gem 'http', '~> 3.2' gem 'http', '~> 2.2'
gem 'http_accept_language', '~> 2.1' gem 'http_accept_language', '~> 2.1'
gem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2' gem 'httplog', '~> 0.99'
gem 'httplog', '~> 1.0'
gem 'idn-ruby', require: 'idn' gem 'idn-ruby', require: 'idn'
gem 'kaminari', '~> 1.1' gem 'kaminari', '~> 1.1'
gem 'link_header', '~> 0.0' gem 'link_header', '~> 0.0'
gem 'mime-types', '~> 3.1', require: 'mime/types/columnar' gem 'mime-types', '~> 3.1'
gem 'nokogiri', '~> 1.8' gem 'nokogiri', '~> 1.8'
gem 'nsa', '~> 0.2' gem 'nsa', '~> 0.2'
gem 'oj', '~> 3.5' gem 'oj', '~> 3.3'
gem 'ostatus2', '~> 2.0' gem 'ostatus2', '~> 2.0'
gem 'ox', '~> 2.9' gem 'ox', '~> 2.8'
gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
gem 'pundit', '~> 1.1' gem 'pundit', '~> 1.1'
gem 'premailer-rails' gem 'rack-attack', '~> 5.0'
gem 'rack-attack', '~> 5.2' gem 'rack-cors', '~> 0.4', require: 'rack/cors'
gem 'rack-cors', '~> 1.0', require: 'rack/cors'
gem 'rack-timeout', '~> 0.4' gem 'rack-timeout', '~> 0.4'
gem 'rails-i18n', '~> 5.1' gem 'rails-i18n', '~> 5.0'
gem 'rails-settings-cached', '~> 0.6' gem 'rails-settings-cached', '~> 0.6'
gem 'redis', '~> 4.0', require: ['redis', 'redis/connection/hiredis'] gem 'redis', '~> 3.3', require: ['redis', 'redis/connection/hiredis']
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock' gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'rqrcode', '~> 0.10' gem 'rqrcode', '~> 0.10'
gem 'ruby-progressbar', '~> 1.4' gem 'ruby-oembed', '~> 0.12', require: 'oembed'
gem 'sanitize', '~> 4.6' gem 'sanitize', '~> 4.4'
gem 'sidekiq', '~> 5.1' gem 'sidekiq', '~> 5.0'
gem 'sidekiq-scheduler', '~> 2.2' gem 'sidekiq-scheduler', '~> 2.1'
gem 'sidekiq-unique-jobs', '~> 5.0' gem 'sidekiq-unique-jobs', '~> 5.0'
gem 'sidekiq-bulk', '~>0.1.1' gem 'sidekiq-bulk', '~>0.1.1'
gem 'simple-navigation', '~> 4.0' gem 'simple-navigation', '~> 4.0'
gem 'simple_form', '~> 4.0' gem 'simple_form', '~> 3.4'
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie' gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
gem 'stoplight', '~> 2.1.3' gem 'strong_migrations'
gem 'strong_migrations', '~> 0.2'
gem 'tty-command', '~> 0.8', require: false
gem 'tty-prompt', '~> 0.16', require: false
gem 'twitter-text', '~> 1.14' gem 'twitter-text', '~> 1.14'
gem 'tzinfo-data', '~> 1.2018' gem 'tzinfo-data', '~> 1.2017'
gem 'webpacker', '~> 3.4' gem 'webpacker', '~> 3.0'
gem 'webpush' gem 'webpush'
gem 'json-ld', '~> 2.2' gem 'json-ld-preloaded', '~> 2.2.1'
gem 'rdf-normalize', '~> 0.3' gem 'rdf-normalize', '~> 0.3.1'
group :development, :test do group :development, :test do
gem 'fabrication', '~> 2.20' gem 'fabrication', '~> 2.18'
gem 'fuubar', '~> 2.2' gem 'fuubar', '~> 2.2'
gem 'i18n-tasks', '~> 0.9', require: false gem 'i18n-tasks', '~> 0.9', require: false
gem 'pry-byebug', '~> 3.6'
gem 'pry-rails', '~> 0.3' gem 'pry-rails', '~> 0.3'
gem 'rspec-rails', '~> 3.7' gem 'rspec-rails', '~> 3.7'
end end
group :production, :test do
gem 'private_address_check', '~> 0.4.1'
end
group :test do group :test do
gem 'capybara', '~> 2.18' gem 'capybara', '~> 2.15'
gem 'climate_control', '~> 0.2' gem 'climate_control', '~> 0.2'
gem 'faker', '~> 1.8' gem 'faker', '~> 1.7'
gem 'microformats', '~> 4.0' gem 'microformats', '~> 4.0'
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.16', require: false gem 'simplecov', '~> 0.14', require: false
gem 'webmock', '~> 3.3' gem 'webmock', '~> 3.0'
gem 'parallel_tests', '~> 2.21' gem 'parallel_tests', '~> 2.17'
end end
group :development do group :development do
@@ -124,25 +101,21 @@ group :development do
gem 'annotate', '~> 2.7' gem 'annotate', '~> 2.7'
gem 'better_errors', '~> 2.4' gem 'better_errors', '~> 2.4'
gem 'binding_of_caller', '~> 0.7' gem 'binding_of_caller', '~> 0.7'
gem 'bullet', '~> 5.7' gem 'bullet', '~> 5.5'
gem 'letter_opener', '~> 1.4' gem 'letter_opener', '~> 1.4'
gem 'letter_opener_web', '~> 1.3' gem 'letter_opener_web', '~> 1.3'
gem 'memory_profiler' gem 'rubocop', require: false
gem 'rubocop', '~> 0.55', require: false gem 'brakeman', '~> 4.0', require: false
gem 'brakeman', '~> 4.2', require: false
gem 'bundler-audit', '~> 0.6', require: false gem 'bundler-audit', '~> 0.6', require: false
gem 'scss_lint', '~> 0.57', require: false gem 'scss_lint', '~> 0.55', require: false
gem 'capistrano', '~> 3.10' gem 'capistrano', '~> 3.10'
gem 'capistrano-rails', '~> 1.3' gem 'capistrano-rails', '~> 1.3'
gem 'capistrano-rbenv', '~> 2.1' gem 'capistrano-rbenv', '~> 2.1'
gem 'capistrano-yarn', '~> 2.0' gem 'capistrano-yarn', '~> 2.0'
gem 'derailed_benchmarks'
gem 'stackprof'
end end
group :production do group :production do
gem 'lograge', '~> 0.10' gem 'lograge', '~> 0.7'
gem 'redis-rails', '~> 5.0' gem 'redis-rails', '~> 5.0'
end end

View File

@@ -1,39 +1,25 @@
GIT
remote: https://github.com/rtomayko/posix-spawn
revision: 58465d2e213991f8afb13b984854a49fcdcc980c
ref: 58465d2e213991f8afb13b984854a49fcdcc980c
specs:
posix-spawn (0.3.13)
GIT
remote: https://github.com/tmm1/http_parser.rb
revision: 54b17ba8c7d8d20a16dfc65d1775241833219cf2
ref: 54b17ba8c7d8d20a16dfc65d1775241833219cf2
specs:
http_parser.rb (0.6.1)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (5.2.0) actioncable (5.1.4)
actionpack (= 5.2.0) actionpack (= 5.1.4)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (~> 0.6.1)
actionmailer (5.2.0) actionmailer (5.1.4)
actionpack (= 5.2.0) actionpack (= 5.1.4)
actionview (= 5.2.0) actionview (= 5.1.4)
activejob (= 5.2.0) activejob (= 5.1.4)
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.0) actionpack (5.1.4)
actionview (= 5.2.0) actionview (= 5.1.4)
activesupport (= 5.2.0) activesupport (= 5.1.4)
rack (~> 2.0) rack (~> 2.0)
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.0) actionview (5.1.4)
activesupport (= 5.2.0) activesupport (= 5.1.4)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.4) erubi (~> 1.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
@@ -44,71 +30,60 @@ 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.5.4) active_record_query_trace (1.5.4)
activejob (5.2.0) activejob (5.1.4)
activesupport (= 5.2.0) activesupport (= 5.1.4)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (5.2.0) activemodel (5.1.4)
activesupport (= 5.2.0) activesupport (= 5.1.4)
activerecord (5.2.0) activerecord (5.1.4)
activemodel (= 5.2.0) activemodel (= 5.1.4)
activesupport (= 5.2.0) activesupport (= 5.1.4)
arel (>= 9.0) arel (~> 8.0)
activestorage (5.2.0) activesupport (5.1.4)
actionpack (= 5.2.0)
activerecord (= 5.2.0)
marcel (~> 0.3.1)
activesupport (5.2.0)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2) i18n (~> 0.7)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
addressable (2.5.2) addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0) public_suffix (>= 2.0.2, < 4.0)
airbrussh (1.3.0) airbrussh (1.3.0)
sshkit (>= 1.6.1, != 1.7.0) sshkit (>= 1.6.1, != 1.7.0)
annotate (2.7.3) annotate (2.7.2)
activerecord (>= 3.2, < 6.0) activerecord (>= 3.2, < 6.0)
rake (>= 10.4, < 13.0) rake (>= 10.4, < 13.0)
arel (9.0.0) arel (8.0.0)
ast (2.4.0) ast (2.3.0)
attr_encrypted (3.1.0) attr_encrypted (3.0.3)
encryptor (~> 3.0.0) encryptor (~> 3.0.0)
av (0.9.0) av (0.9.0)
cocaine (~> 0.5.3) cocaine (~> 0.5.3)
aws-partitions (1.80.0) aws-sdk (2.10.100)
aws-sdk-core (3.19.0) aws-sdk-resources (= 2.10.100)
aws-partitions (~> 1.0) aws-sdk-core (2.10.100)
aws-sigv4 (~> 1.0) aws-sigv4 (~> 1.0)
jmespath (~> 1.0) jmespath (~> 1.0)
aws-sdk-kms (1.5.0) aws-sdk-resources (2.10.100)
aws-sdk-core (~> 3) aws-sdk-core (= 2.10.100)
aws-sigv4 (~> 1.0)
aws-sdk-s3 (1.9.1)
aws-sdk-core (~> 3)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.0)
aws-sigv4 (1.0.2) aws-sigv4 (1.0.2)
bcrypt (3.1.11) bcrypt (3.1.11)
benchmark-ips (2.7.2)
better_errors (2.4.0) better_errors (2.4.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)
binding_of_caller (0.8.0) binding_of_caller (0.7.3)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
bootsnap (1.3.0) bootsnap (1.1.5)
msgpack (~> 1.0) msgpack (~> 1.0)
brakeman (4.2.1) brakeman (4.0.1)
browser (2.5.3) browser (2.5.2)
builder (3.2.3) builder (3.2.3)
bullet (5.7.5) bullet (5.6.1)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
uniform_notifier (~> 1.11.0) uniform_notifier (~> 1.10.0)
bundler-audit (0.6.0) bundler-audit (0.6.0)
bundler (~> 1.2) bundler (~> 1.2)
thor (~> 0.18) thor (~> 0.18)
byebug (10.0.2) capistrano (3.10.0)
capistrano (3.10.2)
airbrussh (>= 1.0.0) airbrussh (>= 1.0.0)
i18n i18n
rake (>= 10.0.0) rake (>= 10.0.0)
@@ -124,22 +99,18 @@ GEM
sshkit (~> 1.3) sshkit (~> 1.3)
capistrano-yarn (2.0.2) capistrano-yarn (2.0.2)
capistrano (~> 3.0) capistrano (~> 3.0)
capybara (2.18.0) capybara (2.16.1)
addressable addressable
mini_mime (>= 0.1.3) mini_mime (>= 0.1.3)
nokogiri (>= 1.3.3) nokogiri (>= 1.3.3)
rack (>= 1.0.0) rack (>= 1.0.0)
rack-test (>= 0.5.4) rack-test (>= 0.5.4)
xpath (>= 2.0, < 4.0) xpath (~> 2.0)
case_transform (0.2) case_transform (0.2)
activesupport activesupport
charlock_holmes (0.7.6) charlock_holmes (0.7.5)
chewy (5.0.0) chunky_png (1.3.8)
activesupport (>= 4.0) cld3 (3.2.1)
elasticsearch (>= 2.0.0)
elasticsearch-dsl
chunky_png (1.3.10)
cld3 (3.2.2)
ffi (>= 1.1.0, < 1.10.0) ffi (>= 1.1.0, < 1.10.0)
climate_control (0.2.0) climate_control (0.2.0)
cocaine (0.5.8) cocaine (0.5.8)
@@ -150,69 +121,45 @@ GEM
connection_pool (2.2.1) connection_pool (2.2.1)
crack (0.4.3) crack (0.4.3)
safe_yaml (~> 1.0.0) safe_yaml (~> 1.0.0)
crass (1.0.4) crass (1.0.3)
css_parser (1.6.0)
addressable
debug_inspector (0.0.3) debug_inspector (0.0.3)
derailed_benchmarks (1.3.4) devise (4.3.0)
benchmark-ips (~> 2)
get_process_mem (~> 0)
heapy (~> 0)
memory_profiler (~> 0)
rack (>= 1)
rake (> 10, < 13)
thor (~> 0.19)
devise (4.4.3)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0, < 6.0) railties (>= 4.1.0, < 5.2)
responders responders
warden (~> 1.2.3) warden (~> 1.2.3)
devise-two-factor (3.0.3) devise-two-factor (3.0.2)
activesupport (< 5.3) activesupport (< 5.2)
attr_encrypted (>= 1.3, < 4, != 2) attr_encrypted (>= 1.3, < 4, != 2)
devise (~> 4.0) devise (~> 4.0)
railties (< 5.3) railties (< 5.2)
rotp (~> 2.0) rotp (~> 2.0)
devise_pam_authenticatable2 (9.1.0)
devise (>= 4.0.0)
rpam2 (~> 4.0)
diff-lcs (1.3) diff-lcs (1.3)
docile (1.3.0) docile (1.1.5)
domain_name (0.5.20180417) domain_name (0.5.20170404)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
doorkeeper (4.2.6) doorkeeper (4.2.6)
railties (>= 4.2) railties (>= 4.2)
dotenv (2.2.2) dotenv (2.2.1)
dotenv-rails (2.2.2) dotenv-rails (2.2.1)
dotenv (= 2.2.2) dotenv (= 2.2.1)
railties (>= 3.2, < 6.0) railties (>= 3.2, < 5.2)
easy_translate (0.5.1) easy_translate (0.5.0)
json
thread thread
thread_safe thread_safe
elasticsearch (6.0.2)
elasticsearch-api (= 6.0.2)
elasticsearch-transport (= 6.0.2)
elasticsearch-api (6.0.2)
multi_json
elasticsearch-dsl (0.1.5)
elasticsearch-transport (6.0.2)
faraday
multi_json
encryptor (3.0.0) encryptor (3.0.0)
equatable (0.5.0) erubi (1.7.0)
erubi (1.7.1) et-orbi (1.0.8)
et-orbi (1.1.0)
tzinfo tzinfo
excon (0.62.0) excon (0.59.0)
fabrication (2.20.1) execjs (2.7.0)
faker (1.8.7) fabrication (2.18.0)
i18n (>= 0.7) faker (1.8.4)
faraday (0.15.0) i18n (~> 0.5)
multipart-post (>= 1.2, < 3)
fast_blank (1.0.0) fast_blank (1.0.0)
fastimage (2.1.1) ffi (1.9.18)
ffi (1.9.23)
fog-core (1.45.0) fog-core (1.45.0)
builder builder
excon (~> 0.58) excon (~> 0.58)
@@ -220,25 +167,24 @@ GEM
fog-json (1.0.2) fog-json (1.0.2)
fog-core (~> 1.0) fog-core (~> 1.0)
multi_json (~> 1.10) multi_json (~> 1.10)
fog-local (0.5.0) fog-local (0.4.0)
fog-core (>= 1.27, < 3.0) fog-core (~> 1.27)
fog-openstack (0.1.25) fog-openstack (0.1.22)
fog-core (~> 1.40) fog-core (>= 1.40)
fog-json (>= 1.0) fog-json (>= 1.0)
ipaddress (>= 0.8) ipaddress (>= 0.8)
formatador (0.2.5) formatador (0.2.5)
fuubar (2.3.1) fuubar (2.2.0)
rspec-core (~> 3.0) rspec-core (~> 3.0)
ruby-progressbar (~> 1.4) ruby-progressbar (~> 1.4)
get_process_mem (0.2.1)
globalid (0.4.1) globalid (0.4.1)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
goldfinger (2.1.0) goldfinger (2.0.1)
addressable (~> 2.5) addressable (~> 2.5)
http (~> 3.0) http (~> 2.2)
nokogiri (~> 1.8) nokogiri (~> 1.8)
oj (~> 3.0) oj (~> 3.0)
hamlit (2.8.8) hamlit (2.8.5)
temple (>= 0.8.0) temple (>= 0.8.0)
thor thor
tilt tilt
@@ -250,47 +196,47 @@ GEM
hamster (3.0.0) hamster (3.0.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
hashdiff (0.3.7) hashdiff (0.3.7)
hashie (3.5.7)
heapy (0.1.3)
highline (1.7.10) highline (1.7.10)
hiredis (0.6.1) hiredis (0.6.1)
hitimes (1.2.6)
hkdf (0.3.0) hkdf (0.3.0)
html2text (0.2.1)
nokogiri (~> 1.6)
htmlentities (4.3.4) htmlentities (4.3.4)
http (3.2.0) http (2.2.2)
addressable (~> 2.3) addressable (~> 2.3)
http-cookie (~> 1.0) http-cookie (~> 1.0)
http-form_data (~> 2.0) http-form_data (~> 1.0.1)
http_parser.rb (~> 0.6.0) http_parser.rb (~> 0.6.0)
http-cookie (1.0.3) http-cookie (1.0.3)
domain_name (~> 0.5) domain_name (~> 0.5)
http-form_data (2.1.0) http-form_data (1.0.3)
http_accept_language (2.1.1) http_accept_language (2.1.1)
httplog (1.0.2) http_parser.rb (0.6.0)
colorize (~> 0.8) httplog (0.99.7)
rack (>= 1.0) colorize
i18n (1.0.1) rack
i18n (0.9.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n-tasks (0.9.21) i18n-tasks (0.9.19)
activesupport (>= 4.0.2) activesupport (>= 4.0.2)
ast (>= 2.1.0) ast (>= 2.1.0)
easy_translate (>= 0.5.1) easy_translate (>= 0.5.0)
erubi erubi
highline (>= 1.7.3) highline (>= 1.7.3)
i18n i18n
parser (>= 2.2.3.0) parser (>= 2.2.3.0)
rainbow (>= 2.2.2, < 4.0) rainbow (~> 2.2)
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.2.8)
jmespath (1.4.0) jmespath (1.3.1)
json (2.1.0) json (2.1.0)
json-ld (2.2.1) json-ld (2.1.7)
multi_json (~> 1.12) multi_json (~> 1.12)
rdf (>= 2.2.8, < 4.0) rdf (~> 2.2, >= 2.2.8)
json-ld-preloaded (2.2.2)
json-ld (~> 2.1, >= 2.1.5)
multi_json (~> 1.11)
rdf (~> 2.2)
jsonapi-renderer (0.2.0) jsonapi-renderer (0.2.0)
jwt (2.1.0) jwt (2.1.0)
kaminari (1.1.1) kaminari (1.1.1)
@@ -307,28 +253,25 @@ GEM
kaminari-core (1.1.1) kaminari-core (1.1.1)
launchy (2.4.3) launchy (2.4.3)
addressable (~> 2.3) addressable (~> 2.3)
letter_opener (1.6.0) letter_opener (1.4.1)
launchy (~> 2.2) launchy (~> 2.2)
letter_opener_web (1.3.4) letter_opener_web (1.3.1)
actionmailer (>= 3.2) actionmailer (>= 3.2)
letter_opener (~> 1.0) letter_opener (~> 1.0)
railties (>= 3.2) railties (>= 3.2)
link_header (0.0.8) link_header (0.0.8)
lograge (0.10.0) lograge (0.7.1)
actionpack (>= 4) actionpack (>= 4, < 5.2)
activesupport (>= 4) activesupport (>= 4, < 5.2)
railties (>= 4) railties (>= 4, < 5.2)
request_store (~> 1.0) request_store (~> 1.0)
loofah (2.2.2) loofah (2.1.1)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.7.0) mail (2.7.0)
mini_mime (>= 0.1.1) mini_mime (>= 0.1.1)
marcel (0.3.2) mario-redis-lock (1.2.0)
mimemagic (~> 0.3.2) redis (~> 3, >= 3.0.5)
mario-redis-lock (1.2.1)
redis (>= 3.0.5)
memory_profiler (0.9.10)
method_source (0.9.0) method_source (0.9.0)
microformats (4.0.7) microformats (4.0.7)
json json
@@ -339,107 +282,82 @@ GEM
mimemagic (0.3.2) mimemagic (0.3.2)
mini_mime (1.0.0) mini_mime (1.0.0)
mini_portile2 (2.3.0) mini_portile2 (2.3.0)
minitest (5.11.3) minitest (5.10.3)
msgpack (1.2.4) msgpack (1.1.0)
multi_json (1.13.1) multi_json (1.12.2)
multipart-post (2.0.0)
necromancer (0.4.0)
net-ldap (0.16.1)
net-scp (1.2.1) net-scp (1.2.1)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
net-ssh (4.2.0) net-ssh (4.2.0)
nio4r (2.3.0) nio4r (2.1.0)
nokogiri (1.8.2) nokogiri (1.8.1)
mini_portile2 (~> 2.3.0) mini_portile2 (~> 2.3.0)
nokogumbo (1.5.0) nokogumbo (1.4.13)
nokogiri nokogiri
nsa (0.2.4) nsa (0.2.4)
activesupport (>= 4.2, < 6) activesupport (>= 4.2, < 6)
concurrent-ruby (~> 1.0.0) concurrent-ruby (~> 1.0.0)
sidekiq (>= 3.5.0) sidekiq (>= 3.5.0)
statsd-ruby (~> 1.2.0) statsd-ruby (~> 1.2.0)
oj (3.5.1) oj (3.3.9)
omniauth (1.8.1) openssl (2.0.6)
hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.6.2, < 3)
omniauth-cas (1.1.1)
addressable (~> 2.3)
nokogiri (~> 1.5)
omniauth (~> 1.2)
omniauth-saml (1.10.0)
omniauth (~> 1.3, >= 1.3.2)
ruby-saml (~> 1.7)
orm_adapter (0.5.0) orm_adapter (0.5.0)
ostatus2 (2.0.3) ostatus2 (2.0.1)
addressable (~> 2.5) addressable (~> 2.4)
http (~> 3.0) http (~> 2.0)
nokogiri (~> 1.8) nokogiri (~> 1.6)
ox (2.9.2) openssl (~> 2.0)
paperclip (6.0.0) ox (2.8.2)
paperclip (5.1.0)
activemodel (>= 4.2.0) activemodel (>= 4.2.0)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
cocaine (~> 0.5.5)
mime-types mime-types
mimemagic (~> 0.3.0) mimemagic (~> 0.3.0)
terrapin (~> 0.6.0)
paperclip-av-transcoder (0.6.4) paperclip-av-transcoder (0.6.4)
av (~> 0.9.0) av (~> 0.9.0)
paperclip (>= 2.5.2) paperclip (>= 2.5.2)
parallel (1.12.1) parallel (1.12.0)
parallel_tests (2.21.3) parallel_tests (2.19.0)
parallel parallel
parser (2.5.1.0) parser (2.4.0.2)
ast (~> 2.4.0) ast (~> 2.3)
pastel (0.7.2) pg (0.21.0)
equatable (~> 0.5.0) pghero (1.7.0)
tty-color (~> 0.4.0)
pg (1.0.0)
pghero (2.1.0)
activerecord activerecord
pkg-config (1.3.0) pkg-config (1.2.8)
posix-spawn (0.3.13)
powerpack (0.1.1) powerpack (0.1.1)
premailer (1.11.1)
addressable
css_parser (>= 1.6.0)
htmlentities (>= 4.0.0)
premailer-rails (1.10.2)
actionmailer (>= 3, < 6)
premailer (~> 1.7, >= 1.7.9)
private_address_check (0.4.1)
pry (0.11.3) pry (0.11.3)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.9.0) method_source (~> 0.9.0)
pry-byebug (3.6.0)
byebug (~> 10.0)
pry (~> 0.10)
pry-rails (0.3.6) pry-rails (0.3.6)
pry (>= 0.10.4) pry (>= 0.10.4)
public_suffix (3.0.2) public_suffix (3.0.1)
puma (3.11.4) puma (3.11.0)
pundit (1.1.0) pundit (1.1.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
rack (2.0.4) rack (2.0.3)
rack-attack (5.2.0) rack-attack (5.0.1)
rack rack
rack-cors (1.0.2) rack-cors (0.4.1)
rack-protection (2.0.1) rack-protection (2.0.0)
rack rack
rack-proxy (0.6.4) rack-proxy (0.6.2)
rack rack
rack-test (1.0.0) rack-test (0.8.2)
rack (>= 1.0, < 3) rack (>= 1.0, < 3)
rack-timeout (0.4.2) rack-timeout (0.4.2)
rails (5.2.0) rails (5.1.4)
actioncable (= 5.2.0) actioncable (= 5.1.4)
actionmailer (= 5.2.0) actionmailer (= 5.1.4)
actionpack (= 5.2.0) actionpack (= 5.1.4)
actionview (= 5.2.0) actionview (= 5.1.4)
activejob (= 5.2.0) activejob (= 5.1.4)
activemodel (= 5.2.0) activemodel (= 5.1.4)
activerecord (= 5.2.0) activerecord (= 5.1.4)
activestorage (= 5.2.0) activesupport (= 5.1.4)
activesupport (= 5.2.0)
bundler (>= 1.3.0) bundler (>= 1.3.0)
railties (= 5.2.0) railties (= 5.1.4)
sprockets-rails (>= 2.0.0) sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.2) rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1) actionpack (~> 5.x, >= 5.0.1)
@@ -448,30 +366,31 @@ GEM
rails-dom-testing (2.0.3) rails-dom-testing (2.0.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.0.4) rails-html-sanitizer (1.0.3)
loofah (~> 2.2, >= 2.2.2) loofah (~> 2.0)
rails-i18n (5.1.1) rails-i18n (5.0.4)
i18n (>= 0.7, < 2) i18n (~> 0.7)
railties (>= 5.0, < 6) railties (~> 5.0)
rails-settings-cached (0.6.6) rails-settings-cached (0.6.6)
rails (>= 4.2.0) rails (>= 4.2.0)
railties (5.2.0) railties (5.1.4)
actionpack (= 5.2.0) actionpack (= 5.1.4)
activesupport (= 5.2.0) activesupport (= 5.1.4)
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (3.0.0) rainbow (2.2.2)
rake (12.3.1) rake
rb-fsevent (0.10.3) rake (12.3.0)
rb-fsevent (0.10.2)
rb-inotify (0.9.10) rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2) ffi (>= 0.5.0, < 2)
rdf (3.0.2) rdf (2.2.12)
hamster (~> 3.0) hamster (~> 3.0)
link_header (~> 0.0, >= 0.0.8) link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.3.3) rdf-normalize (0.3.2)
rdf (>= 2.2, < 4.0) rdf (~> 2.0)
redis (4.0.1) redis (3.3.5)
redis-actionpack (5.0.2) redis-actionpack (5.0.2)
actionpack (>= 4.0, < 6) actionpack (>= 4.0, < 6)
redis-rack (>= 1, < 3) redis-rack (>= 1, < 3)
@@ -481,25 +400,23 @@ GEM
redis-store (>= 1.3, < 2) redis-store (>= 1.3, < 2)
redis-namespace (1.6.0) redis-namespace (1.6.0)
redis (>= 3.0.4) redis (>= 3.0.4)
redis-rack (2.0.4) redis-rack (2.0.3)
rack (>= 1.5, < 3) rack (>= 1.5, < 3)
redis-store (>= 1.2, < 2) redis-store (>= 1.2, < 2)
redis-rails (5.0.2) redis-rails (5.0.2)
redis-actionpack (>= 5.0, < 6) redis-actionpack (>= 5.0, < 6)
redis-activesupport (>= 5.0, < 6) redis-activesupport (>= 5.0, < 6)
redis-store (>= 1.2, < 2) redis-store (>= 1.2, < 2)
redis-store (1.5.0) redis-store (1.4.1)
redis (>= 2.2, < 5) redis (>= 2.2, < 5)
request_store (1.4.1) request_store (1.3.2)
rack (>= 1.4)
responders (2.4.0) responders (2.4.0)
actionpack (>= 4.2.0, < 5.3) actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 5.3) railties (>= 4.2.0, < 5.3)
rotp (2.1.2) rotp (2.1.2)
rpam2 (4.0.2)
rqrcode (0.10.1) rqrcode (0.10.1)
chunky_png (~> 1.0) chunky_png (~> 1.0)
rspec-core (3.7.1) rspec-core (3.7.0)
rspec-support (~> 3.7.0) rspec-support (~> 3.7.0)
rspec-expectations (3.7.0) rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
@@ -518,41 +435,40 @@ GEM
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.7.1) rspec-support (3.7.0)
rubocop (0.55.0) rubocop (0.51.0)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 2.5) parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1) powerpack (~> 0.1)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 3.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1) unicode-display_width (~> 1.0, >= 1.0.1)
ruby-oembed (0.12.0)
ruby-progressbar (1.9.0) ruby-progressbar (1.9.0)
ruby-saml (1.7.2)
nokogiri (>= 1.5.10)
rufus-scheduler (3.4.2) rufus-scheduler (3.4.2)
et-orbi (~> 1.0) et-orbi (~> 1.0)
safe_yaml (1.0.4) safe_yaml (1.0.4)
sanitize (4.6.4) sanitize (4.5.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
nokogumbo (~> 1.4) nokogumbo (~> 1.4.1)
sass (3.5.6) sass (3.5.3)
sass-listen (~> 4.0.0) sass-listen (~> 4.0.0)
sass-listen (4.0.0) sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4) rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7) rb-inotify (~> 0.9, >= 0.9.7)
scss_lint (0.57.0) scss_lint (0.56.0)
rake (>= 0.9, < 13) rake (>= 0.9, < 13)
sass (~> 3.5.5) sass (~> 3.5.3)
sidekiq (5.1.3) sidekiq (5.0.5)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0) connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0) rack-protection (>= 1.5.0)
redis (>= 3.3.5, < 5) redis (>= 3.3.4, < 5)
sidekiq-bulk (0.1.1) sidekiq-bulk (0.1.1)
activesupport activesupport
sidekiq sidekiq
sidekiq-scheduler (2.2.1) sidekiq-scheduler (2.1.10)
redis (>= 3, < 5) redis (>= 3, < 5)
rufus-scheduler (~> 3.2) rufus-scheduler (~> 3.2)
sidekiq (>= 3) sidekiq (>= 3)
@@ -562,11 +478,11 @@ GEM
thor (~> 0) thor (~> 0)
simple-navigation (4.0.5) simple-navigation (4.0.5)
activesupport (>= 2.3.2) activesupport (>= 2.3.2)
simple_form (4.0.0) simple_form (3.5.0)
actionpack (> 4) actionpack (> 4, < 5.2)
activemodel (> 4) activemodel (> 4, < 5.2)
simplecov (0.16.1) simplecov (0.15.1)
docile (~> 1.1) docile (~> 1.1.0)
json (>= 1.8, < 3) json (>= 1.8, < 3)
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.2) simplecov-html (0.10.2)
@@ -577,72 +493,50 @@ GEM
actionpack (>= 4.0) actionpack (>= 4.0)
activesupport (>= 4.0) activesupport (>= 4.0)
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
sshkit (1.16.0) sshkit (1.15.1)
net-scp (>= 1.1.2) net-scp (>= 1.1.2)
net-ssh (>= 2.8.0) net-ssh (>= 2.8.0)
stackprof (0.2.11)
statsd-ruby (1.2.1) statsd-ruby (1.2.1)
stoplight (2.1.3) strong_migrations (0.1.9)
streamio-ffmpeg (3.0.2)
multi_json (~> 1.8)
strong_migrations (0.2.2)
activerecord (>= 3.2.0) activerecord (>= 3.2.0)
temple (0.8.0) temple (0.8.0)
terminal-table (1.8.0) terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1) unicode-display_width (~> 1.1, >= 1.1.1)
terrapin (0.6.0)
climate_control (>= 0.0.3, < 1.0)
thor (0.20.0) thor (0.20.0)
thread (0.2.2) thread (0.2.2)
thread_safe (0.3.6) thread_safe (0.3.6)
tilt (2.0.8) tilt (2.0.8)
timers (4.1.2)
hitimes
tty-color (0.4.2)
tty-command (0.8.0)
pastel (~> 0.7.0)
tty-cursor (0.5.0)
tty-prompt (0.16.0)
necromancer (~> 0.4.0)
pastel (~> 0.7.0)
timers (~> 4.0)
tty-cursor (~> 0.5.0)
tty-reader (~> 0.2.0)
tty-reader (0.2.0)
tty-cursor (~> 0.5.0)
tty-screen (~> 0.6.4)
wisper (~> 2.0.0)
tty-screen (0.6.4)
twitter-text (1.14.7) twitter-text (1.14.7)
unf (~> 0.1.0) unf (~> 0.1.0)
tzinfo (1.2.5) tzinfo (1.2.4)
thread_safe (~> 0.1) thread_safe (~> 0.1)
tzinfo-data (1.2018.4) tzinfo-data (1.2017.3)
tzinfo (>= 1.0.0) tzinfo (>= 1.0.0)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.5) unf_ext (0.0.7.4)
unicode-display_width (1.3.2) unicode-display_width (1.3.0)
uniform_notifier (1.11.0) uniform_notifier (1.10.0)
warden (1.2.7) warden (1.2.7)
rack (>= 1.0) rack (>= 1.0)
webmock (3.3.0) webmock (3.1.1)
addressable (>= 2.3.6) addressable (>= 2.3.6)
crack (>= 0.3.2) crack (>= 0.3.2)
hashdiff hashdiff
webpacker (3.4.3) webpacker (3.0.2)
activesupport (>= 4.2) activesupport (>= 4.2)
rack-proxy (>= 0.6.1) rack-proxy (>= 0.6.1)
railties (>= 4.2) railties (>= 4.2)
webpush (0.3.3) webpush (0.3.3)
hkdf (~> 0.2) hkdf (~> 0.2)
jwt (~> 2.0) jwt (~> 2.0)
websocket-driver (0.7.0) websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3) websocket-extensions (0.1.3)
wisper (2.0.0) xpath (2.1.0)
xpath (3.0.0) nokogiri (~> 1.3)
nokogiri (~> 1.8)
PLATFORMS PLATFORMS
ruby ruby
@@ -652,121 +546,103 @@ DEPENDENCIES
active_record_query_trace (~> 1.5) active_record_query_trace (~> 1.5)
addressable (~> 2.5) addressable (~> 2.5)
annotate (~> 2.7) annotate (~> 2.7)
aws-sdk-s3 (~> 1.9) aws-sdk (~> 2.10)
better_errors (~> 2.4) better_errors (~> 2.4)
binding_of_caller (~> 0.7) binding_of_caller (~> 0.7)
bootsnap (~> 1.3) bootsnap
brakeman (~> 4.2) brakeman (~> 4.0)
browser browser
bullet (~> 5.7) bullet (~> 5.5)
bundler-audit (~> 0.6) bundler-audit (~> 0.6)
capistrano (~> 3.10) capistrano (~> 3.10)
capistrano-rails (~> 1.3) capistrano-rails (~> 1.3)
capistrano-rbenv (~> 2.1) capistrano-rbenv (~> 2.1)
capistrano-yarn (~> 2.0) capistrano-yarn (~> 2.0)
capybara (~> 2.18) capybara (~> 2.15)
charlock_holmes (~> 0.7.6) charlock_holmes (~> 0.7.5)
chewy (~> 5.0)
cld3 (~> 3.2.0) cld3 (~> 3.2.0)
climate_control (~> 0.2) climate_control (~> 0.2)
derailed_benchmarks devise (~> 4.2)
devise (~> 4.4)
devise-two-factor (~> 3.0) devise-two-factor (~> 3.0)
devise_pam_authenticatable2 (~> 9.1) doorkeeper (~> 4.2)
doorkeeper (~> 4.2, < 4.3) dotenv-rails (~> 2.2)
dotenv-rails (~> 2.2, < 2.3) fabrication (~> 2.18)
fabrication (~> 2.20) faker (~> 1.7)
faker (~> 1.8)
fast_blank (~> 1.0) fast_blank (~> 1.0)
fastimage
fog-core (~> 1.45) fog-core (~> 1.45)
fog-local (~> 0.5) fog-local (~> 0.4)
fog-openstack (~> 0.1) fog-openstack (~> 0.1)
fuubar (~> 2.2) fuubar (~> 2.2)
goldfinger (~> 2.1) goldfinger (~> 2.0)
hamlit-rails (~> 0.2) hamlit-rails (~> 0.2)
hiredis (~> 0.6) hiredis (~> 0.6)
html2text
htmlentities (~> 4.3) htmlentities (~> 4.3)
http (~> 3.2) http (~> 2.2)
http_accept_language (~> 2.1) http_accept_language (~> 2.1)
http_parser.rb (~> 0.6)! httplog (~> 0.99)
httplog (~> 1.0)
i18n-tasks (~> 0.9) i18n-tasks (~> 0.9)
idn-ruby idn-ruby
iso-639 iso-639
json-ld (~> 2.2) json-ld-preloaded (~> 2.2.1)
kaminari (~> 1.1) kaminari (~> 1.1)
letter_opener (~> 1.4) letter_opener (~> 1.4)
letter_opener_web (~> 1.3) letter_opener_web (~> 1.3)
link_header (~> 0.0) link_header (~> 0.0)
lograge (~> 0.10) lograge (~> 0.7)
mario-redis-lock (~> 1.2) mario-redis-lock (~> 1.2)
memory_profiler
microformats (~> 4.0) microformats (~> 4.0)
mime-types (~> 3.1) mime-types (~> 3.1)
net-ldap (~> 0.10)
nokogiri (~> 1.8) nokogiri (~> 1.8)
nsa (~> 0.2) nsa (~> 0.2)
oj (~> 3.5) oj (~> 3.3)
omniauth (~> 1.2)
omniauth-cas (~> 1.1)
omniauth-saml (~> 1.10)
ostatus2 (~> 2.0) ostatus2 (~> 2.0)
ox (~> 2.9) ox (~> 2.8)
paperclip (~> 6.0) paperclip (~> 5.1)
paperclip-av-transcoder (~> 0.6) paperclip-av-transcoder (~> 0.6)
parallel_tests (~> 2.21) parallel_tests (~> 2.17)
pg (~> 1.0) pg (~> 0.20)
pghero (~> 2.1) pghero (~> 1.7)
pkg-config (~> 1.3) pkg-config (~> 1.2)
posix-spawn! posix-spawn
premailer-rails
private_address_check (~> 0.4.1)
pry-byebug (~> 3.6)
pry-rails (~> 0.3) pry-rails (~> 0.3)
puma (~> 3.11) puma (~> 3.10)
pundit (~> 1.1) pundit (~> 1.1)
rack-attack (~> 5.2) rack-attack (~> 5.0)
rack-cors (~> 1.0) rack-cors (~> 0.4)
rack-timeout (~> 0.4) rack-timeout (~> 0.4)
rails (~> 5.2.0) rails (~> 5.1.4)
rails-controller-testing (~> 1.0) rails-controller-testing (~> 1.0)
rails-i18n (~> 5.1) rails-i18n (~> 5.0)
rails-settings-cached (~> 0.6) rails-settings-cached (~> 0.6)
rdf-normalize (~> 0.3) rdf-normalize (~> 0.3.1)
redis (~> 4.0) redis (~> 3.3)
redis-namespace (~> 1.5) redis-namespace (~> 1.5)
redis-rails (~> 5.0) redis-rails (~> 5.0)
rqrcode (~> 0.10) rqrcode (~> 0.10)
rspec-rails (~> 3.7) rspec-rails (~> 3.7)
rspec-sidekiq (~> 3.0) rspec-sidekiq (~> 3.0)
rubocop (~> 0.55) rubocop
ruby-progressbar (~> 1.4) ruby-oembed (~> 0.12)
sanitize (~> 4.6) sanitize (~> 4.4)
scss_lint (~> 0.57) scss_lint (~> 0.55)
sidekiq (~> 5.1) sidekiq (~> 5.0)
sidekiq-bulk (~> 0.1.1) sidekiq-bulk (~> 0.1.1)
sidekiq-scheduler (~> 2.2) sidekiq-scheduler (~> 2.1)
sidekiq-unique-jobs (~> 5.0) sidekiq-unique-jobs (~> 5.0)
simple-navigation (~> 4.0) simple-navigation (~> 4.0)
simple_form (~> 4.0) simple_form (~> 3.4)
simplecov (~> 0.16) simplecov (~> 0.14)
sprockets-rails (~> 3.2) sprockets-rails (~> 3.2)
stackprof strong_migrations
stoplight (~> 2.1.3)
streamio-ffmpeg (~> 3.0)
strong_migrations (~> 0.2)
tty-command (~> 0.8)
tty-prompt (~> 0.16)
twitter-text (~> 1.14) twitter-text (~> 1.14)
tzinfo-data (~> 1.2018) tzinfo-data (~> 1.2017)
webmock (~> 3.3) uglifier (~> 3.2)
webpacker (~> 3.4) webmock (~> 3.0)
webpacker (~> 3.0)
webpush webpush
RUBY VERSION RUBY VERSION
ruby 2.5.0p0 ruby 2.4.2p198
BUNDLED WITH BUNDLED WITH
1.16.1 1.16.0

View File

@@ -1,4 +1,4 @@
web: env PORT=3000 bundle exec puma -C config/puma.rb web: PORT=3000 bundle exec puma -C config/puma.rb
sidekiq: env PORT=3000 bundle exec sidekiq sidekiq: PORT=3000 bundle exec sidekiq
stream: env PORT=4000 yarn run start stream: PORT=4000 yarn run start
webpack: ./bin/webpack-dev-server --listen-host 0.0.0.0 webpack: ./bin/webpack-dev-server --listen-host 0.0.0.0

5
Vagrantfile vendored
View File

@@ -39,7 +39,6 @@ sudo apt-get install \
libidn11-dev \ libidn11-dev \
libprotobuf-dev \ libprotobuf-dev \
libreadline-dev \ libreadline-dev \
libpam0g-dev \
-y -y
# Install rvm # Install rvm
@@ -49,7 +48,7 @@ curl -sSL https://raw.githubusercontent.com/rvm/rvm/stable/binscripts/rvm-instal
source /home/vagrant/.rvm/scripts/rvm source /home/vagrant/.rvm/scripts/rvm
# Install Ruby # Install Ruby
rvm reinstall ruby-$RUBY_VERSION --disable-binary rvm install ruby-$RUBY_VERSION
# Configure database # Configure database
sudo -u postgres createuser -U postgres vagrant -s sudo -u postgres createuser -U postgres vagrant -s
@@ -80,7 +79,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/trusty64"
config.vm.provider :virtualbox do |vb| config.vm.provider :virtualbox do |vb|
vb.name = "mastodon" vb.name = "mastodon"

View File

@@ -1,61 +0,0 @@
# frozen_string_literal: true
class StatusesIndex < Chewy::Index
settings index: { refresh_interval: '15m' }, analysis: {
filter: {
english_stop: {
type: 'stop',
stopwords: '_english_',
},
english_stemmer: {
type: 'stemmer',
language: 'english',
},
english_possessive_stemmer: {
type: 'stemmer',
language: 'possessive_english',
},
},
analyzer: {
content: {
tokenizer: 'uax_url_email',
filter: %w(
english_possessive_stemmer
lowercase
asciifolding
cjk_width
english_stop
english_stemmer
),
},
},
}
define_type ::Status.without_reblogs do
crutch :mentions do |collection|
data = ::Mention.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id)
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
end
crutch :favourites do |collection|
data = ::Favourite.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id)
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
end
crutch :reblogs do |collection|
data = ::Status.where(reblog_of_id: collection.map(&:id)).pluck(:reblog_of_id, :account_id)
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
end
root date_detection: false do
field :account_id, type: 'long'
field :text, type: 'text', value: ->(status) { [status.spoiler_text, Formatter.instance.plaintext(status)].join("\n\n") } do
field :stemmed, type: 'text', analyzer: 'content'
end
field :searchable_by, type: 'long', value: ->(status, crutches) { status.searchable_by(crutches) }
field :created_at, type: 'date'
end
end
end

View File

@@ -36,7 +36,7 @@ class AboutController < ApplicationController
def initial_state_params def initial_state_params
{ {
settings: { known_fediverse: Setting.show_known_fediverse_at_about_page }, settings: {},
token: current_session&.token, token: current_session&.token,
} }
end end

View File

@@ -1,11 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class AccountsController < ApplicationController class AccountsController < ApplicationController
PAGE_SIZE = 20
include AccountControllerConcern include AccountControllerConcern
include SignatureVerification
before_action :set_cache_headers
def show def show
respond_to do |format| respond_to do |format|
@@ -19,31 +16,21 @@ class AccountsController < ApplicationController
end end
@pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses? @pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses?
@statuses = filtered_status_page(params) @statuses = filtered_statuses.paginate_by_max_id(20, params[:max_id], params[:since_id])
@statuses = cache_collection(@statuses, Status) @statuses = cache_collection(@statuses, Status)
@next_url = next_url unless @statuses.empty?
unless @statuses.empty?
@older_url = older_url if @statuses.last.id > filtered_statuses.last.id
@newer_url = newer_url if @statuses.first.id < filtered_statuses.first.id
end
end end
format.atom do format.atom do
@entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]) @entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id])
render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? })) render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? }))
end end
format.rss do
@statuses = cache_collection(default_statuses.without_reblogs.without_replies.limit(PAGE_SIZE), Status)
render xml: RSS::AccountSerializer.render(@account, @statuses)
end
format.json do format.json do
skip_session! render json: @account,
serializer: ActivityPub::ActorSerializer,
render_cached_json(['activitypub', 'actor', @account.cache_key], content_type: 'application/activity+json') do adapter: ActivityPub::Adapter,
ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter) content_type: 'application/activity+json'
end
end end
end end
end end
@@ -81,22 +68,13 @@ class AccountsController < ApplicationController
@account = Account.find_local!(params[:username]) @account = Account.find_local!(params[:username])
end end
def older_url def next_url
::Rails.logger.info("older: max_id #{@statuses.last.id}, url #{pagination_url(max_id: @statuses.last.id)}")
pagination_url(max_id: @statuses.last.id)
end
def newer_url
pagination_url(min_id: @statuses.first.id)
end
def pagination_url(max_id: nil, min_id: nil)
if media_requested? if media_requested?
short_account_media_url(@account, max_id: max_id, min_id: min_id) short_account_media_url(@account, max_id: @statuses.last.id)
elsif replies_requested? elsif replies_requested?
short_account_with_replies_url(@account, max_id: max_id, min_id: min_id) short_account_with_replies_url(@account, max_id: @statuses.last.id)
else else
short_account_url(@account, max_id: max_id, min_id: min_id) short_account_url(@account, max_id: @statuses.last.id)
end end
end end
@@ -107,12 +85,4 @@ class AccountsController < ApplicationController
def replies_requested? def replies_requested?
request.path.ends_with?('/with_replies') request.path.ends_with?('/with_replies')
end end
def filtered_status_page(params)
if params[:min_id].present?
filtered_statuses.paginate_by_min_id(PAGE_SIZE, params[:min_id]).reverse
else
filtered_statuses.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]).to_a
end
end
end end

View File

@@ -1,57 +0,0 @@
# frozen_string_literal: true
class ActivityPub::CollectionsController < Api::BaseController
include SignatureVerification
before_action :set_account
before_action :set_size
before_action :set_statuses
def show
render json: collection_presenter,
serializer: ActivityPub::CollectionSerializer,
adapter: ActivityPub::Adapter,
content_type: 'application/activity+json',
skip_activities: true
end
private
def set_account
@account = Account.find_local!(params[:account_username])
end
def set_statuses
@statuses = scope_for_collection
@statuses = cache_collection(@statuses, Status)
end
def set_size
case params[:id]
when 'featured'
@account.pinned_statuses.count
else
raise ActiveRecord::NotFound
end
end
def scope_for_collection
case params[:id]
when 'featured'
@account.statuses.permitted_for(@account, signed_request_account).tap do |scope|
scope.merge!(@account.pinned_statuses)
end
else
raise ActiveRecord::NotFound
end
end
def collection_presenter
ActivityPub::CollectionPresenter.new(
id: account_collection_url(@account, params[:id]),
type: :ordered,
size: @size,
items: @statuses
)
end
end

View File

@@ -11,7 +11,7 @@ class ActivityPub::InboxesController < Api::BaseController
process_payload process_payload
head 202 head 202
else else
render plain: signature_verification_failure_reason, status: 401 [signature_verification_failure_reason, 401]
end end
end end
@@ -28,7 +28,7 @@ class ActivityPub::InboxesController < Api::BaseController
def upgrade_account def upgrade_account
if signed_request_account.ostatus? if signed_request_account.ostatus?
signed_request_account.update(last_webfingered_at: nil) signed_request_account.update(last_webfingered_at: nil)
ResolveAccountWorker.perform_async(signed_request_account.acct) ResolveRemoteAccountWorker.perform_async(signed_request_account.acct)
end end
Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id) if signed_request_account.subscribed? Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id) if signed_request_account.subscribed?

View File

@@ -1,15 +1,13 @@
# frozen_string_literal: true # frozen_string_literal: true
class ActivityPub::OutboxesController < Api::BaseController class ActivityPub::OutboxesController < Api::BaseController
LIMIT = 20
include SignatureVerification
before_action :set_account before_action :set_account
before_action :set_statuses
def show def show
render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json' @statuses = @account.statuses.permitted_for(@account, current_account).paginate_by_max_id(20, params[:max_id], params[:since_id])
@statuses = cache_collection(@statuses, Status)
render json: outbox_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end end
private private
@@ -19,47 +17,11 @@ class ActivityPub::OutboxesController < Api::BaseController
end end
def outbox_presenter def outbox_presenter
if page_requested? ActivityPub::CollectionPresenter.new(
ActivityPub::CollectionPresenter.new( id: account_outbox_url(@account),
id: account_outbox_url(@account, page_params), type: :ordered,
type: :ordered, size: @account.statuses_count,
part_of: account_outbox_url(@account), items: @statuses
prev: prev_page, )
next: next_page,
items: @statuses
)
else
ActivityPub::CollectionPresenter.new(
id: account_outbox_url(@account),
type: :ordered,
size: @account.statuses_count,
first: account_outbox_url(@account, page: true),
last: account_outbox_url(@account, page: true, min_id: 0)
)
end
end
def next_page
account_outbox_url(@account, page: true, max_id: @statuses.last.id) if @statuses.size == LIMIT
end
def prev_page
account_outbox_url(@account, page: true, min_id: @statuses.first.id) unless @statuses.empty?
end
def set_statuses
return unless page_requested?
@statuses = @account.statuses.permitted_for(@account, signed_request_account)
@statuses = params[:min_id].present? ? @statuses.paginate_by_min_id(LIMIT, params[:min_id]).reverse : @statuses.paginate_by_max_id(LIMIT, params[:max_id])
@statuses = cache_collection(@statuses, Status)
end
def page_requested?
params[:page] == 'true'
end
def page_params
{ page: true, max_id: params[:max_id], min_id: params[:min_id] }.compact
end end
end end

View File

@@ -2,7 +2,7 @@
module Admin module Admin
class AccountsController < BaseController class AccountsController < BaseController
before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :remove_avatar, :enable, :disable, :memorialize] before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :enable, :disable, :memorialize]
before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload] before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload]
before_action :require_local_account!, only: [:enable, :disable, :memorialize] before_action :require_local_account!, only: [:enable, :disable, :memorialize]
@@ -60,17 +60,6 @@ module Admin
redirect_to admin_account_path(@account.id) redirect_to admin_account_path(@account.id)
end end
def remove_avatar
authorize @account, :remove_avatar?
@account.avatar = nil
@account.save!
log_action :remove_avatar, @account.user
redirect_to admin_account_path(@account.id)
end
private private
def set_account def set_account

View File

@@ -12,7 +12,6 @@ module Admin
def set_pack def set_pack
use_pack 'admin' use_pack 'admin'
use_pack 'public'
end end
end end
end end

View File

@@ -1,49 +0,0 @@
# frozen_string_literal: true
module Admin
class ChangeEmailsController < BaseController
before_action :set_account
before_action :require_local_account!
def show
authorize @user, :change_email?
end
def update
authorize @user, :change_email?
new_email = resource_params.fetch(:unconfirmed_email)
if new_email != @user.email
@user.update!(
unconfirmed_email: new_email,
# Regenerate the confirmation token:
confirmation_token: nil
)
log_action :change_email, @user
@user.send_confirmation_instructions
end
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.change_email.changed_msg')
end
private
def set_account
@account = Account.find(params[:account_id])
@user = @account.user
end
def require_local_account!
redirect_to admin_account_path(@account.id) unless @account.local? && @account.user.present?
end
def resource_params
params.require(:user).permit(
:unconfirmed_email
)
end
end
end

View File

@@ -3,7 +3,6 @@
module Admin module Admin
class ConfirmationsController < BaseController class ConfirmationsController < BaseController
before_action :set_user before_action :set_user
before_action :check_confirmation, only: [:resend]
def create def create
authorize @user, :confirm? authorize @user, :confirm?
@@ -12,28 +11,10 @@ module Admin
redirect_to admin_accounts_path redirect_to admin_accounts_path
end end
def resend
authorize @user, :confirm?
@user.resend_confirmation_instructions
log_action :confirm, @user
flash[:notice] = I18n.t('admin.accounts.resend_confirmation.success')
redirect_to admin_accounts_path
end
private private
def set_user def set_user
@user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) @user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
end end
def check_confirmation
if @user.confirmed?
flash[:error] = I18n.t('admin.accounts.resend_confirmation.already_confirmed')
redirect_to admin_accounts_path
end
end
end end
end end

View File

@@ -3,7 +3,6 @@
module Admin module Admin
class CustomEmojisController < BaseController class CustomEmojisController < BaseController
before_action :set_custom_emoji, except: [:index, :new, :create] before_action :set_custom_emoji, except: [:index, :new, :create]
before_action :set_filter_params
def index def index
authorize :custom_emoji, :index? authorize :custom_emoji, :index?
@@ -33,26 +32,23 @@ module Admin
if @custom_emoji.update(resource_params) if @custom_emoji.update(resource_params)
log_action :update, @custom_emoji log_action :update, @custom_emoji
flash[:notice] = I18n.t('admin.custom_emojis.updated_msg') redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.updated_msg')
else else
flash[:alert] = I18n.t('admin.custom_emojis.update_failed_msg') redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.update_failed_msg')
end end
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end end
def destroy def destroy
authorize @custom_emoji, :destroy? authorize @custom_emoji, :destroy?
@custom_emoji.destroy! @custom_emoji.destroy!
log_action :destroy, @custom_emoji log_action :destroy, @custom_emoji
flash[:notice] = I18n.t('admin.custom_emojis.destroyed_msg') redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.destroyed_msg')
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end end
def copy def copy
authorize @custom_emoji, :copy? authorize @custom_emoji, :copy?
emoji = CustomEmoji.find_or_initialize_by(domain: nil, emoji = CustomEmoji.find_or_initialize_by(domain: nil, shortcode: @custom_emoji.shortcode)
shortcode: @custom_emoji.shortcode)
emoji.image = @custom_emoji.image emoji.image = @custom_emoji.image
if emoji.save if emoji.save
@@ -62,23 +58,21 @@ module Admin
flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg') flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg')
end end
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params) redirect_to admin_custom_emojis_path(page: params[:page])
end end
def enable def enable
authorize @custom_emoji, :enable? authorize @custom_emoji, :enable?
@custom_emoji.update!(disabled: false) @custom_emoji.update!(disabled: false)
log_action :enable, @custom_emoji log_action :enable, @custom_emoji
flash[:notice] = I18n.t('admin.custom_emojis.enabled_msg') redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.enabled_msg')
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end end
def disable def disable
authorize @custom_emoji, :disable? authorize @custom_emoji, :disable?
@custom_emoji.update!(disabled: true) @custom_emoji.update!(disabled: true)
log_action :disable, @custom_emoji log_action :disable, @custom_emoji
flash[:notice] = I18n.t('admin.custom_emojis.disabled_msg') redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.disabled_msg')
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end end
private private
@@ -87,10 +81,6 @@ module Admin
@custom_emoji = CustomEmoji.find(params[:id]) @custom_emoji = CustomEmoji.find(params[:id])
end end
def set_filter_params
@filter_params = filter_params.to_hash.symbolize_keys
end
def resource_params def resource_params
params.require(:custom_emoji).permit(:shortcode, :image, :visible_in_picker) params.require(:custom_emoji).permit(:shortcode, :image, :visible_in_picker)
end end

View File

@@ -1,56 +0,0 @@
# frozen_string_literal: true
module Admin
class ReportNotesController < BaseController
before_action :set_report_note, only: [:destroy]
def create
authorize ReportNote, :create?
@report_note = current_account.report_notes.new(resource_params)
@report = @report_note.report
if @report_note.save
if params[:create_and_resolve]
@report.resolve!(current_account)
log_action :resolve, @report
redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')
return
end
if params[:create_and_unresolve]
@report.unresolve!
log_action :reopen, @report
end
redirect_to admin_report_path(@report), notice: I18n.t('admin.report_notes.created_msg')
else
@report_notes = @report.notes.latest
@report_history = @report.history
@form = Form::StatusBatch.new
render template: 'admin/reports/show'
end
end
def destroy
authorize @report_note, :destroy?
@report_note.destroy!
redirect_to admin_report_path(@report_note.report_id), notice: I18n.t('admin.report_notes.destroyed_msg')
end
private
def resource_params
params.require(:report_note).permit(
:content,
:report_id
)
end
def set_report_note
@report_note = ReportNote.find(params[:id])
end
end
end

View File

@@ -3,16 +3,31 @@
module Admin module Admin
class ReportedStatusesController < BaseController class ReportedStatusesController < BaseController
before_action :set_report before_action :set_report
before_action :set_status, only: [:update, :destroy]
def create def create
authorize :status, :update? authorize :status, :update?
@form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account, action: action_from_button)) @form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account))
flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
redirect_to admin_report_path(@report) redirect_to admin_report_path(@report)
end end
def update
authorize @status, :update?
@status.update!(status_params)
log_action :update, @status
redirect_to admin_report_path(@report)
end
def destroy
authorize @status, :destroy?
RemovalWorker.perform_async(@status.id)
log_action :destroy, @status
render json: @status
end
private private
def status_params def status_params
@@ -20,21 +35,15 @@ module Admin
end end
def form_status_batch_params def form_status_batch_params
params.require(:form_status_batch).permit(status_ids: []) params.require(:form_status_batch).permit(:action, status_ids: [])
end
def action_from_button
if params[:nsfw_on]
'nsfw_on'
elsif params[:nsfw_off]
'nsfw_off'
elsif params[:delete]
'delete'
end
end end
def set_report def set_report
@report = Report.find(params[:report_id]) @report = Report.find(params[:report_id])
end end
def set_status
@status = @report.statuses.find(params[:id])
end
end end
end end

View File

@@ -11,61 +11,45 @@ module Admin
def show def show
authorize @report, :show? authorize @report, :show?
@form = Form::StatusBatch.new
@report_note = @report.notes.new
@report_notes = (@report.notes.latest + @report.history).sort_by(&:created_at)
@form = Form::StatusBatch.new
end end
def update def update
authorize @report, :update? authorize @report, :update?
process_report process_report
redirect_to admin_report_path(@report)
if @report.action_taken?
redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')
else
redirect_to admin_report_path(@report)
end
end end
private private
def process_report def process_report
case params[:outcome].to_s case params[:outcome].to_s
when 'assign_to_self'
@report.update!(assigned_account_id: current_account.id)
log_action :assigned_to_self, @report
when 'unassign'
@report.update!(assigned_account_id: nil)
log_action :unassigned, @report
when 'reopen'
@report.unresolve!
log_action :reopen, @report
when 'resolve' when 'resolve'
@report.resolve!(current_account) @report.update!(action_taken_by_current_attributes)
log_action :resolve, @report log_action :resolve, @report
when 'suspend' when 'suspend'
Admin::SuspensionWorker.perform_async(@report.target_account.id) Admin::SuspensionWorker.perform_async(@report.target_account.id)
log_action :resolve, @report log_action :resolve, @report
log_action :suspend, @report.target_account log_action :suspend, @report.target_account
resolve_all_target_account_reports resolve_all_target_account_reports
when 'silence' when 'silence'
@report.target_account.update!(silenced: true) @report.target_account.update!(silenced: true)
log_action :resolve, @report log_action :resolve, @report
log_action :silence, @report.target_account log_action :silence, @report.target_account
resolve_all_target_account_reports resolve_all_target_account_reports
else else
raise ActiveRecord::RecordNotFound raise ActiveRecord::RecordNotFound
end end
@report.reload end
def action_taken_by_current_attributes
{ action_taken: true, action_taken_by_account_id: current_account.id }
end end
def resolve_all_target_account_reports def resolve_all_target_account_reports
unresolved_reports_for_target_account.update_all(action_taken: true, action_taken_by_account_id: current_account.id) unresolved_reports_for_target_account.update_all(
action_taken_by_current_attributes
)
end end
def unresolved_reports_for_target_account def unresolved_reports_for_target_account

View File

@@ -16,11 +16,7 @@ module Admin
show_staff_badge show_staff_badge
bootstrap_timeline_accounts bootstrap_timeline_accounts
thumbnail thumbnail
hero
min_invite_role min_invite_role
activity_api_enabled
peers_api_enabled
show_known_fediverse_at_about_page
).freeze ).freeze
BOOLEAN_SETTINGS = %w( BOOLEAN_SETTINGS = %w(
@@ -28,14 +24,10 @@ module Admin
open_deletion open_deletion
timeline_preview timeline_preview
show_staff_badge show_staff_badge
activity_api_enabled
peers_api_enabled
show_known_fediverse_at_about_page
).freeze ).freeze
UPLOAD_SETTINGS = %w( UPLOAD_SETTINGS = %w(
thumbnail thumbnail
hero
).freeze ).freeze
def edit def edit

View File

@@ -5,13 +5,14 @@ module Admin
helper_method :current_params helper_method :current_params
before_action :set_account before_action :set_account
before_action :set_status, only: [:update, :destroy]
PER_PAGE = 20 PER_PAGE = 20
def index def index
authorize :status, :index? authorize :status, :index?
@statuses = @account.statuses.where(visibility: [:public, :unlisted]) @statuses = @account.statuses
if params[:media] if params[:media]
account_media_status_ids = @account.media_attachments.attached.reorder(nil).select(:status_id).distinct account_media_status_ids = @account.media_attachments.attached.reorder(nil).select(:status_id).distinct
@@ -25,18 +26,40 @@ module Admin
def create def create
authorize :status, :update? authorize :status, :update?
@form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account, action: action_from_button)) @form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account))
flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
redirect_to admin_account_statuses_path(@account.id, current_params) redirect_to admin_account_statuses_path(@account.id, current_params)
end end
def update
authorize @status, :update?
@status.update!(status_params)
log_action :update, @status
redirect_to admin_account_statuses_path(@account.id, current_params)
end
def destroy
authorize @status, :destroy?
RemovalWorker.perform_async(@status.id)
log_action :destroy, @status
render json: @status
end
private private
def status_params
params.require(:status).permit(:sensitive)
end
def form_status_batch_params def form_status_batch_params
params.require(:form_status_batch).permit(:action, status_ids: []) params.require(:form_status_batch).permit(:action, status_ids: [])
end end
def set_status
@status = @account.statuses.find(params[:id])
end
def set_account def set_account
@account = Account.find(params[:account_id]) @account = Account.find(params[:account_id])
end end
@@ -49,15 +72,5 @@ module Admin
page: page > 1 && page, page: page > 1 && page,
}.select { |_, value| value.present? } }.select { |_, value| value.present? }
end end
def action_from_button
if params[:nsfw_on]
'nsfw_on'
elsif params[:nsfw_off]
'nsfw_off'
elsif params[:delete]
'delete'
end
end
end end
end end

View File

@@ -6,8 +6,8 @@ class Api::BaseController < ApplicationController
include RateLimitHeaders include RateLimitHeaders
skip_before_action :verify_authenticity_token
skip_before_action :store_current_location skip_before_action :store_current_location
protect_from_forgery with: :null_session
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e| rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
render json: { error: e.to_s }, status: 422 render json: { error: e.to_s }, status: 422
@@ -51,10 +51,6 @@ class Api::BaseController < ApplicationController
[params[:limit].to_i.abs, default_limit * 2].min [params[:limit].to_i.abs, default_limit * 2].min
end end
def truthy_param?(key)
ActiveModel::Type::Boolean.new.cast(params[key])
end
def current_resource_owner def current_resource_owner
@current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token @current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
end end
@@ -66,10 +62,8 @@ class Api::BaseController < ApplicationController
end end
def require_user! def require_user!
if current_user && !current_user.disabled? if current_user
set_user_activity set_user_activity
elsif current_user
render json: { error: 'Your login is currently disabled' }, status: 403
else else
render json: { error: 'This method requires an authenticated user' }, status: 422 render json: { error: 'This method requires an authenticated user' }, status: 422
end end

View File

@@ -1,8 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::SalmonController < Api::BaseController class Api::SalmonController < Api::BaseController
include SignatureVerification
before_action :set_account before_action :set_account
respond_to :txt respond_to :txt
@@ -11,7 +9,7 @@ class Api::SalmonController < Api::BaseController
process_salmon process_salmon
head 202 head 202
elsif payload.present? elsif payload.present?
render plain: signature_verification_failure_reason, status: 401 [signature_verification_failure_reason, 401]
else else
head 400 head 400
end end

View File

@@ -13,7 +13,6 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
def update def update
@account = current_account @account = current_account
UpdateAccountService.new.call(@account, account_params, raise_error: true) UpdateAccountService.new.call(@account, account_params, raise_error: true)
UserSettingsDecorator.new(current_user).update(user_settings_params) if user_settings_params
ActivityPub::UpdateDistributionWorker.perform_async(@account.id) ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
render json: @account, serializer: REST::CredentialAccountSerializer render json: @account, serializer: REST::CredentialAccountSerializer
end end
@@ -21,17 +20,6 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
private private
def account_params def account_params
params.permit(:display_name, :note, :avatar, :header, :locked, :bot, fields_attributes: [:name, :value]) params.permit(:display_name, :note, :avatar, :header)
end
def user_settings_params
return nil unless params.key?(:source)
source_params = params.require(:source)
{
'setting_default_privacy' => source_params.fetch(:privacy, @account.user.setting_default_privacy),
'setting_default_sensitive' => source_params.fetch(:sensitive, @account.user.setting_default_sensitive),
}
end end
end end

View File

@@ -19,8 +19,6 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
end end
def load_accounts def load_accounts
return [] if @account.user_hides_network? && current_account.id != @account.id
default_accounts.merge(paginated_follows).to_a default_accounts.merge(paginated_follows).to_a
end end
@@ -65,6 +63,6 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
end end

View File

@@ -19,8 +19,6 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
end end
def load_accounts def load_accounts
return [] if @account.user_hides_network? && current_account.id != @account.id
default_accounts.merge(paginated_follows).to_a default_accounts.merge(paginated_follows).to_a
end end
@@ -65,6 +63,6 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
end end

View File

@@ -10,7 +10,7 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController
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
# we requested them, so return the "right" order to the requestor. # we requested them, so return the "right" order to the requestor.
@accounts = accounts.index_by(&:id).values_at(*account_ids).compact @accounts = accounts.index_by(&:id).values_at(*account_ids)
render json: @accounts, each_serializer: REST::RelationshipSerializer, relationships: relationships render json: @accounts, each_serializer: REST::RelationshipSerializer, relationships: relationships
end end
@@ -21,6 +21,6 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController
end end
def account_ids def account_ids
Array(params[:id]).map(&:to_i) @_account_ids ||= Array(params[:id]).map(&:to_i)
end end
end end

View File

@@ -22,4 +22,8 @@ class Api::V1::Accounts::SearchController < Api::BaseController
following: truthy_param?(:following) following: truthy_param?(:following)
) )
end end
def truthy_param?(key)
params[key] == 'true'
end
end end

View File

@@ -27,17 +27,19 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
end end
def account_statuses def account_statuses
statuses = truthy_param?(:pinned) ? pinned_scope : permitted_account_statuses default_statuses.tap do |statuses|
statuses = statuses.paginate_by_max_id( statuses.merge!(only_media_scope) if params[:only_media]
statuses.merge!(pinned_scope) if params[:pinned]
statuses.merge!(no_replies_scope) if params[:exclude_replies]
end
end
def default_statuses
permitted_account_statuses.paginate_by_max_id(
limit_param(DEFAULT_STATUSES_LIMIT), limit_param(DEFAULT_STATUSES_LIMIT),
params[:max_id], params[:max_id],
params[:since_id] params[:since_id]
) )
statuses.merge!(only_media_scope) if truthy_param?(:only_media)
statuses.merge!(no_replies_scope) if truthy_param?(:exclude_replies)
statuses
end end
def permitted_account_statuses def permitted_account_statuses
@@ -49,13 +51,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
end end
def account_media_status_ids def account_media_status_ids
# `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids. @account.media_attachments.attached.reorder(nil).select(:status_id).distinct
# Also, Avoid getting slow by not narrowing down by `statuses.account_id`.
# When narrowing down by `statuses.account_id`, `index_statuses_20180106` will be used
# and the table will be joined by `Merge Semi Join`, so the query will be slow.
Status.joins(:media_attachments).merge(@account.media_attachments).permitted_for(@account, current_account)
.paginate_by_max_id(limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], params[:since_id])
.reorder(id: :desc).distinct(:id).pluck(:id)
end end
def pinned_scope def pinned_scope
@@ -67,7 +63,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit, :only_media, :exclude_replies).permit(:limit, :only_media, :exclude_replies).merge(core_params) params.permit(:limit, :only_media, :exclude_replies).merge(core_params)
end end
def insert_pagination_headers def insert_pagination_headers

View File

@@ -5,7 +5,6 @@ class Api::V1::AccountsController < Api::BaseController
before_action -> { doorkeeper_authorize! :follow }, only: [:follow, :unfollow, :block, :unblock, :mute, :unmute] before_action -> { doorkeeper_authorize! :follow }, only: [:follow, :unfollow, :block, :unblock, :mute, :unmute]
before_action :require_user!, except: [:show] before_action :require_user!, except: [:show]
before_action :set_account before_action :set_account
before_action :check_account_suspension, only: [:show]
respond_to :json respond_to :json
@@ -14,9 +13,9 @@ class Api::V1::AccountsController < Api::BaseController
end end
def follow def follow
FollowService.new.call(current_user.account, @account.acct, reblogs: truthy_param?(:reblogs)) FollowService.new.call(current_user.account, @account.acct, reblogs: params[:reblogs])
options = @account.locked? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } } options = @account.locked? ? {} : { following_map: { @account.id => { reblogs: params[:reblogs] } }, requested_map: { @account.id => false } }
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(options) render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(options)
end end
@@ -27,7 +26,7 @@ class Api::V1::AccountsController < Api::BaseController
end end
def mute def mute
MuteService.new.call(current_user.account, @account, notifications: truthy_param?(:notifications)) MuteService.new.call(current_user.account, @account, notifications: params[:notifications])
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
end end
@@ -55,8 +54,4 @@ class Api::V1::AccountsController < Api::BaseController
def relationships(**options) def relationships(**options)
AccountRelationshipsPresenter.new([@account.id], current_user.account_id, options) AccountRelationshipsPresenter.new([@account.id], current_user.account_id, options)
end end
def check_account_suspension
gone if @account.suspended?
end
end end

View File

@@ -57,6 +57,6 @@ class Api::V1::BlocksController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
end end

View File

@@ -1,71 +0,0 @@
# frozen_string_literal: true
class Api::V1::BookmarksController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }
before_action :require_user!
after_action :insert_pagination_headers
respond_to :json
def index
@statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
end
private
def load_statuses
cached_bookmarks
end
def cached_bookmarks
cache_collection(
Status.reorder(nil).joins(:bookmarks).merge(results),
Status
)
end
def results
@_results ||= account_bookmarks.paginate_by_max_id(
limit_param(DEFAULT_STATUSES_LIMIT),
params[:max_id],
params[:since_id]
)
end
def account_bookmarks
current_account.bookmarks
end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path
if records_continue?
api_v1_bookmarks_url pagination_params(max_id: pagination_max_id)
end
end
def prev_path
unless results.empty?
api_v1_bookmarks_url pagination_params(since_id: pagination_since_id)
end
end
def pagination_max_id
results.last.id
end
def pagination_since_id
results.first.id
end
def records_continue?
results.size == limit_param(DEFAULT_STATUSES_LIMIT)
end
def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params)
end
end

View File

@@ -15,8 +15,7 @@ class Api::V1::DomainBlocksController < Api::BaseController
end end
def create def create
current_account.block_domain!(domain_block_params[:domain]) BlockDomainFromAccountService.new.call(current_account, domain_block_params[:domain])
AfterAccountDomainBlockWorker.perform_async(current_account.id, domain_block_params[:domain])
render_empty render_empty
end end
@@ -68,7 +67,7 @@ class Api::V1::DomainBlocksController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
def domain_block_params def domain_block_params

View File

@@ -66,6 +66,6 @@ class Api::V1::FavouritesController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
end end

View File

@@ -71,6 +71,6 @@ class Api::V1::FollowRequestsController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
end end

View File

@@ -1,36 +0,0 @@
# frozen_string_literal: true
class Api::V1::Instances::ActivityController < Api::BaseController
before_action :require_enabled_api!
respond_to :json
def show
render_cached_json('api:v1:instances:activity:show', expires_in: 1.day) { activity }
end
private
def activity
weeks = []
12.times do |i|
day = i.weeks.ago.to_date
week_id = day.cweek
week = Date.commercial(day.cwyear, week_id)
weeks << {
week: week.to_time.to_i.to_s,
statuses: Redis.current.get("activity:statuses:local:#{week_id}") || '0',
logins: Redis.current.pfcount("activity:logins:#{week_id}").to_s,
registrations: Redis.current.get("activity:accounts:local:#{week_id}") || '0',
}
end
weeks
end
def require_enabled_api!
head 404 unless Setting.activity_api_enabled
end
end

View File

@@ -1,17 +0,0 @@
# frozen_string_literal: true
class Api::V1::Instances::PeersController < Api::BaseController
before_action :require_enabled_api!
respond_to :json
def index
render_cached_json('api:v1:instances:peers:index', expires_in: 1.day) { Account.remote.domains }
end
private
def require_enabled_api!
head 404 unless Setting.peers_api_enabled
end
end

View File

@@ -88,7 +88,7 @@ class Api::V1::Lists::AccountsController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
def unlimited? def unlimited?

View File

@@ -27,7 +27,7 @@ class Api::V1::MediaController < Api::BaseController
private private
def media_params def media_params
params.permit(:file, :description, :focus) params.permit(:file, :description)
end end
def file_type_error def file_type_error

View File

@@ -76,6 +76,6 @@ class Api::V1::MutesController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
end end

View File

@@ -91,6 +91,6 @@ class Api::V1::NotificationsController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit, :exclude_types).permit(:limit, exclude_types: []).merge(core_params) params.permit(:limit, exclude_types: []).merge(core_params)
end end
end end

View File

@@ -1,56 +0,0 @@
# frozen_string_literal: true
class Api::V1::Push::SubscriptionsController < Api::BaseController
before_action -> { doorkeeper_authorize! :push }
before_action :require_user!
before_action :set_web_push_subscription
def create
@web_subscription&.destroy!
@web_subscription = ::Web::PushSubscription.create!(
endpoint: subscription_params[:endpoint],
key_p256dh: subscription_params[:keys][:p256dh],
key_auth: subscription_params[:keys][:auth],
data: data_params,
user_id: current_user.id,
access_token_id: doorkeeper_token.id
)
render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer
end
def show
raise ActiveRecord::RecordNotFound if @web_subscription.nil?
render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer
end
def update
raise ActiveRecord::RecordNotFound if @web_subscription.nil?
@web_subscription.update!(data: data_params)
render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer
end
def destroy
@web_subscription&.destroy!
render_empty
end
private
def set_web_push_subscription
@web_subscription = ::Web::PushSubscription.find_by(access_token_id: doorkeeper_token.id)
end
def subscription_params
params.require(:subscription).permit(:endpoint, keys: [:auth, :p256dh])
end
def data_params
return {} if params[:data].blank?
params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention])
end
end

View File

@@ -13,14 +13,14 @@ class Api::V1::ReportsController < Api::BaseController
end end
def create def create
@report = ReportService.new.call( @report = current_account.reports.create!(
current_account, target_account: reported_account,
reported_account,
status_ids: reported_status_ids, status_ids: reported_status_ids,
comment: report_params[:comment], comment: report_params[:comment]
forward: report_params[:forward]
) )
User.staff.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later }
render json: @report, serializer: REST::ReportSerializer render json: @report, serializer: REST::ReportSerializer
end end
@@ -39,6 +39,6 @@ class Api::V1::ReportsController < Api::BaseController
end end
def report_params def report_params
params.permit(:account_id, :comment, :forward, status_ids: []) params.permit(:account_id, :comment, status_ids: [])
end end
end end

View File

@@ -33,8 +33,12 @@ class Api::V1::SearchController < Api::BaseController
SearchService.new.call( SearchService.new.call(
params[:q], params[:q],
RESULTS_LIMIT, RESULTS_LIMIT,
truthy_param?(:resolve), resolving_search?,
current_account current_account
) )
end end
def resolving_search?
params[:resolve] == 'true'
end
end end

View File

@@ -1,39 +0,0 @@
# frozen_string_literal: true
class Api::V1::Statuses::BookmarksController < Api::BaseController
include Authorization
before_action -> { doorkeeper_authorize! :write }
before_action :require_user!
respond_to :json
def create
@status = bookmarked_status
render json: @status, serializer: REST::StatusSerializer
end
def destroy
@status = requested_status
@bookmarks_map = { @status.id => false }
bookmark = Bookmark.find_by!(account: current_user.account, status: @status)
bookmark.destroy!
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_user&.account_id, bookmarks_map: @bookmarks_map)
end
private
def bookmarked_status
authorize_with current_user.account, requested_status, :show?
bookmark = Bookmark.find_or_create_by!(account: current_user.account, status: requested_status)
bookmark.status.reload
end
def requested_status
Status.find(params[:status_id])
end
end

View File

@@ -77,6 +77,6 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
end end

View File

@@ -11,18 +11,12 @@ class Api::V1::Statuses::PinsController < Api::BaseController
def create def create
StatusPin.create!(account: current_account, status: @status) StatusPin.create!(account: current_account, status: @status)
distribute_add_activity!
render json: @status, serializer: REST::StatusSerializer render json: @status, serializer: REST::StatusSerializer
end end
def destroy def destroy
pin = StatusPin.find_by(account: current_account, status: @status) pin = StatusPin.find_by(account: current_account, status: @status)
pin&.destroy!
if pin
pin.destroy!
distribute_remove_activity!
end
render json: @status, serializer: REST::StatusSerializer render json: @status, serializer: REST::StatusSerializer
end end
@@ -31,24 +25,4 @@ class Api::V1::Statuses::PinsController < Api::BaseController
def set_status def set_status
@status = Status.find(params[:status_id]) @status = Status.find(params[:status_id])
end end
def distribute_add_activity!
json = ActiveModelSerializers::SerializableResource.new(
@status,
serializer: ActivityPub::AddSerializer,
adapter: ActivityPub::Adapter
).as_json
ActivityPub::RawDistributionWorker.perform_async(Oj.dump(json), current_account.id)
end
def distribute_remove_activity!
json = ActiveModelSerializers::SerializableResource.new(
@status,
serializer: ActivityPub::RemoveSerializer,
adapter: ActivityPub::Adapter
).as_json
ActivityPub::RawDistributionWorker.perform_async(Oj.dump(json), current_account.id)
end
end end

View File

@@ -74,6 +74,6 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
end end

View File

@@ -10,12 +10,6 @@ class Api::V1::StatusesController < Api::BaseController
respond_to :json respond_to :json
# This API was originally unlimited, pagination cannot be introduced without
# breaking backwards-compatibility. Arbitrarily high number to cover most
# conversations as quasi-unlimited, it would be too much work to render more
# than this anyway
CONTEXT_LIMIT = 4_096
def show def show
cached = Rails.cache.read(@status.cache_key) cached = Rails.cache.read(@status.cache_key)
@status = cached unless cached.nil? @status = cached unless cached.nil?
@@ -23,8 +17,8 @@ class Api::V1::StatusesController < Api::BaseController
end end
def context def context
ancestors_results = @status.in_reply_to_id.nil? ? [] : @status.ancestors(CONTEXT_LIMIT, current_account) ancestors_results = @status.in_reply_to_id.nil? ? [] : @status.ancestors(current_account)
descendants_results = @status.descendants(CONTEXT_LIMIT, current_account) descendants_results = @status.descendants(current_account)
loaded_ancestors = cache_collection(ancestors_results, Status) loaded_ancestors = cache_collection(ancestors_results, Status)
loaded_descendants = cache_collection(descendants_results, Status) loaded_descendants = cache_collection(descendants_results, Status)
@@ -48,6 +42,7 @@ class Api::V1::StatusesController < Api::BaseController
@status = PostStatusService.new.call(current_user.account, @status = PostStatusService.new.call(current_user.account,
status_params[:status], status_params[:status],
status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]), status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]),
local_only: status_params[:local_only],
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],
@@ -78,11 +73,11 @@ class Api::V1::StatusesController < Api::BaseController
end end
def status_params def status_params
params.permit(:status, :in_reply_to_id, :sensitive, :spoiler_text, :visibility, media_ids: []) params.permit(:status, :in_reply_to_id, :local_only, :sensitive, :spoiler_text, :visibility, media_ids: [])
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
def authorize_if_got_token def authorize_if_got_token

View File

@@ -23,18 +23,15 @@ class Api::V1::Timelines::DirectController < Api::BaseController
end end
def direct_statuses def direct_statuses
direct_timeline_statuses direct_timeline_statuses.paginate_by_max_id(
limit_param(DEFAULT_STATUSES_LIMIT),
params[:max_id],
params[:since_id]
)
end end
def direct_timeline_statuses def direct_timeline_statuses
# this query requires built in pagination. Status.as_direct_timeline(current_account)
Status.as_direct_timeline(
current_account,
limit_param(DEFAULT_STATUSES_LIMIT),
params[:max_id],
params[:since_id],
true # returns array of cache_ids object
)
end end
def insert_pagination_headers def insert_pagination_headers

View File

@@ -9,11 +9,7 @@ class Api::V1::Timelines::HomeController < Api::BaseController
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),
status: regeneration_in_progress? ? 206 : 200
end end
private private
@@ -43,7 +39,7 @@ class Api::V1::Timelines::HomeController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:local, :limit).permit(:local, :limit).merge(core_params) params.permit(:local, :limit).merge(core_params)
end end
def next_path def next_path
@@ -61,8 +57,4 @@ class Api::V1::Timelines::HomeController < Api::BaseController
def pagination_since_id def pagination_since_id
@statuses.first.id @statuses.first.id
end end
def regeneration_in_progress?
Redis.current.exists("account:#{current_account.id}:regeneration")
end
end end

View File

@@ -45,7 +45,7 @@ class Api::V1::Timelines::ListController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.permit(:limit).merge(core_params)
end end
def next_path def next_path

View File

@@ -21,23 +21,15 @@ class Api::V1::Timelines::PublicController < Api::BaseController
end end
def public_statuses def public_statuses
statuses = public_timeline_statuses.paginate_by_max_id( public_timeline_statuses.paginate_by_max_id(
limit_param(DEFAULT_STATUSES_LIMIT), limit_param(DEFAULT_STATUSES_LIMIT),
params[:max_id], params[:max_id],
params[:since_id] params[:since_id]
) )
if truthy_param?(:only_media)
# `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids.
status_ids = statuses.joins(:media_attachments).distinct(:id).pluck(:id)
statuses.where(id: status_ids)
else
statuses
end
end end
def public_timeline_statuses def public_timeline_statuses
Status.as_public_timeline(current_account, truthy_param?(:local)) Status.as_public_timeline(current_account, params[:local])
end end
def insert_pagination_headers def insert_pagination_headers
@@ -45,7 +37,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:local, :limit, :only_media).permit(:local, :limit, :only_media).merge(core_params) params.permit(:local, :limit).merge(core_params)
end end
def next_path def next_path

View File

@@ -29,24 +29,16 @@ class Api::V1::Timelines::TagController < Api::BaseController
if @tag.nil? if @tag.nil?
[] []
else else
statuses = tag_timeline_statuses.paginate_by_max_id( tag_timeline_statuses.paginate_by_max_id(
limit_param(DEFAULT_STATUSES_LIMIT), limit_param(DEFAULT_STATUSES_LIMIT),
params[:max_id], params[:max_id],
params[:since_id] params[:since_id]
) )
if truthy_param?(:only_media)
# `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids.
status_ids = statuses.joins(:media_attachments).distinct(:id).pluck(:id)
statuses.where(id: status_ids)
else
statuses
end
end end
end end
def tag_timeline_statuses def tag_timeline_statuses
Status.as_tag_timeline(@tag, current_account, truthy_param?(:local)) Status.as_tag_timeline(@tag, current_account, params[:local])
end end
def insert_pagination_headers def insert_pagination_headers
@@ -54,7 +46,7 @@ class Api::V1::Timelines::TagController < Api::BaseController
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:local, :limit, :only_media).permit(:local, :limit, :only_media).merge(core_params) params.permit(:local, :limit).merge(core_params)
end end
def next_path def next_path

View File

@@ -1,8 +0,0 @@
# frozen_string_literal: true
class Api::V2::SearchController < Api::V1::SearchController
def index
@search = Search.new(search)
render json: @search, serializer: REST::V2::SearchSerializer
end
end

View File

@@ -1,9 +0,0 @@
# frozen_string_literal: true
class Api::Web::BaseController < Api::BaseController
protect_from_forgery with: :exception
rescue_from ActionController::InvalidAuthenticityToken do
render json: { error: "Can't verify CSRF token authenticity." }, status: 422
end
end

View File

@@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::Web::EmbedsController < Api::Web::BaseController class Api::Web::EmbedsController < Api::BaseController
respond_to :json respond_to :json
before_action :require_user! before_action :require_user!
@@ -9,12 +9,9 @@ class Api::Web::EmbedsController < Api::Web::BaseController
status = StatusFinder.new(params[:url]).status status = StatusFinder.new(params[:url]).status
render json: status, serializer: OEmbedSerializer, width: 400 render json: status, serializer: OEmbedSerializer, width: 400
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
oembed = FetchOEmbedService.new.call(params[:url]) oembed = OEmbed::Providers.get(params[:url])
render json: Oj.dump(oembed.fields)
if oembed rescue OEmbed::NotFound
render json: oembed render json: {}, status: :not_found
else
render json: {}, status: :not_found
end
end end
end end

View File

@@ -1,11 +1,14 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::Web::PushSubscriptionsController < Api::Web::BaseController class Api::Web::PushSubscriptionsController < Api::BaseController
respond_to :json respond_to :json
before_action :require_user! before_action :require_user!
def create def create
params.require(:subscription).require(:endpoint)
params.require(:subscription).require(:keys).require([:auth, :p256dh])
active_session = current_session active_session = current_session
unless active_session.web_push_subscription.nil? unless active_session.web_push_subscription.nil?
@@ -25,38 +28,27 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
}, },
} }
data.deep_merge!(data_params) if params[:data] data.deep_merge!(params[:data]) if params[:data]
web_subscription = ::Web::PushSubscription.create!( web_subscription = ::Web::PushSubscription.create!(
endpoint: subscription_params[:endpoint], endpoint: params[:subscription][:endpoint],
key_p256dh: subscription_params[:keys][:p256dh], key_p256dh: params[:subscription][:keys][:p256dh],
key_auth: subscription_params[:keys][:auth], key_auth: params[:subscription][:keys][:auth],
data: data, data: data
user_id: active_session.user_id,
access_token_id: active_session.access_token_id
) )
active_session.update!(web_push_subscription: web_subscription) active_session.update!(web_push_subscription: web_subscription)
render json: web_subscription, serializer: REST::WebPushSubscriptionSerializer render json: web_subscription.as_payload
end end
def update def update
params.require([:id]) params.require([:id, :data])
web_subscription = ::Web::PushSubscription.find(params[:id]) web_subscription = ::Web::PushSubscription.find(params[:id])
web_subscription.update!(data: data_params)
render json: web_subscription, serializer: REST::WebPushSubscriptionSerializer web_subscription.update!(data: params[:data])
end
private render json: web_subscription.as_payload
def subscription_params
@subscription_params ||= params.require(:subscription).permit(:endpoint, keys: [:auth, :p256dh])
end
def data_params
@data_params ||= params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention])
end end
end end

View File

@@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::Web::SettingsController < Api::Web::BaseController class Api::Web::SettingsController < Api::BaseController
respond_to :json respond_to :json
before_action :require_user! before_action :require_user!

View File

@@ -9,19 +9,16 @@ class ApplicationController < ActionController::Base
include Localized include Localized
include UserTrackingConcern include UserTrackingConcern
include SessionTrackingConcern
helper_method :current_account helper_method :current_account
helper_method :current_session helper_method :current_session
helper_method :current_flavour helper_method :current_flavour
helper_method :current_skin helper_method :current_skin
helper_method :single_user_mode? helper_method :single_user_mode?
helper_method :use_seamless_external_login?
rescue_from ActionController::RoutingError, with: :not_found rescue_from ActionController::RoutingError, with: :not_found
rescue_from ActiveRecord::RecordNotFound, with: :not_found rescue_from ActiveRecord::RecordNotFound, with: :not_found
rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity
rescue_from ActionController::UnknownFormat, with: :not_acceptable
rescue_from Mastodon::NotPermittedError, with: :forbidden rescue_from Mastodon::NotPermittedError, with: :forbidden
before_action :store_current_location, except: :raise_not_found, unless: :devise_controller? before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?
@@ -34,19 +31,19 @@ class ApplicationController < ActionController::Base
private private
def https_enabled? def https_enabled?
Rails.env.production? Rails.env.production? && ENV['LOCAL_HTTPS'] == 'true'
end end
def store_current_location def store_current_location
store_location_for(:user, request.url) unless request.format == :json store_location_for(:user, request.url)
end end
def require_admin! def require_admin!
forbidden unless current_user&.admin? redirect_to root_path unless current_user&.admin?
end end
def require_staff! def require_staff!
forbidden unless current_user&.staff? redirect_to root_path unless current_user&.staff?
end end
def check_suspension def check_suspension
@@ -144,18 +141,10 @@ class ApplicationController < ActionController::Base
respond_with_error(422) respond_with_error(422)
end end
def not_acceptable
respond_with_error(406)
end
def single_user_mode? def single_user_mode?
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.exists? @single_user_mode ||= Rails.configuration.x.single_user_mode && Account.exists?
end end
def use_seamless_external_login?
Devise.pam_authentication || Devise.ldap_authentication
end
def current_account def current_account
@current_account ||= current_user.try(:account) @current_account ||= current_user.try(:account)
end end
@@ -203,31 +192,8 @@ class ApplicationController < ActionController::Base
format.any { head code } format.any { head code }
format.html do format.html do
set_locale set_locale
use_pack 'error'
render "errors/#{code}", layout: 'error', status: code render "errors/#{code}", layout: 'error', status: code
end end
end end
end end
def render_cached_json(cache_key, **options)
options[:expires_in] ||= 3.minutes
cache_key = cache_key.join(':') if cache_key.is_a?(Enumerable)
cache_public = options.key?(:public) ? options.delete(:public) : true
content_type = options.delete(:content_type) || 'application/json'
data = Rails.cache.fetch(cache_key, { raw: true }.merge(options)) do
yield.to_json
end
expires_in options[:expires_in], public: cache_public
render json: data, content_type: content_type
end
def set_cache_headers
response.headers['Vary'] = 'Accept'
end
def skip_session!
request.session_options[:skip] = true
end
end end

View File

@@ -2,35 +2,17 @@
class Auth::ConfirmationsController < Devise::ConfirmationsController class Auth::ConfirmationsController < Devise::ConfirmationsController
layout 'auth' layout 'auth'
before_action :set_user, only: [:finish_signup]
before_action :set_pack before_action :set_pack
def show
super do |user|
BootstrapTimelineWorker.perform_async(user.account_id) if user.errors.empty?
end
end
private private
def set_pack def set_pack
use_pack 'auth' use_pack 'auth'
end end
# GET/PATCH /users/:id/finish_signup
def finish_signup
return unless request.patch? && params[:user]
if @user.update(user_params)
@user.skip_reconfirmation!
sign_in(@user, bypass: true)
redirect_to root_path, notice: I18n.t('devise.confirmations.send_instructions')
else
@show_errors = true
end
end
private
def set_user
@user = current_user
end
def user_params
params.require(:user).permit(:email)
end
end end

View File

@@ -1,33 +0,0 @@
# frozen_string_literal: true
class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token
def self.provides_callback_for(provider)
provider_id = provider.to_s.chomp '_oauth2'
define_method provider do
@user = User.find_for_oauth(request.env['omniauth.auth'], current_user)
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: provider_id.capitalize) if is_navigational_format?
else
session["devise.#{provider}_data"] = request.env['omniauth.auth']
redirect_to new_user_registration_url
end
end
end
Devise.omniauth_configs.each_key do |provider|
provides_callback_for provider
end
def after_sign_in_path_for(resource)
if resource.email_verified?
root_path
else
finish_signup_path
end
end
end

View File

@@ -15,11 +15,6 @@ class Auth::RegistrationsController < Devise::RegistrationsController
protected protected
def update_resource(resource, params)
params[:password] = nil if Devise.pam_authentication && resource.encrypted_password.blank?
super
end
def build_resource(hash = nil) def build_resource(hash = nil)
super(hash) super(hash)
@@ -43,10 +38,6 @@ class Auth::RegistrationsController < Devise::RegistrationsController
new_user_session_path new_user_session_path
end end
def after_update_path_for(_resource)
edit_user_registration_path
end
def check_enabled_registrations def check_enabled_registrations
redirect_to root_path if single_user_mode? || !allowed_registrations? redirect_to root_path if single_user_mode? || !allowed_registrations?
end end

View File

@@ -8,16 +8,8 @@ class Auth::SessionsController < Devise::SessionsController
skip_before_action :require_no_authentication, only: [:create] skip_before_action :require_no_authentication, only: [:create]
skip_before_action :check_suspension, only: [:destroy] skip_before_action :check_suspension, only: [:destroy]
prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create] prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create]
prepend_before_action :set_pack
before_action :set_instance_presenter, only: [:new] before_action :set_instance_presenter, only: [:new]
before_action :set_pack
def new
Devise.omniauth_configs.each do |provider, config|
return redirect_to(omniauth_authorize_path(resource_name, provider)) if config.strategy.redirect_at_sign_in
end
super
end
def create def create
super do |resource| super do |resource|
@@ -37,11 +29,7 @@ class Auth::SessionsController < Devise::SessionsController
if session[:otp_user_id] if session[:otp_user_id]
User.find(session[:otp_user_id]) User.find(session[:otp_user_id])
elsif user_params[:email] elsif user_params[:email]
if use_seamless_external_login? && Devise.check_at_sign && user_params[:email].index('@').nil? User.find_for_authentication(email: user_params[:email])
User.joins(:account).find_by(accounts: { username: user_params[:email] })
else
User.find_for_authentication(email: user_params[:email])
end
end end
end end
@@ -59,14 +47,6 @@ class Auth::SessionsController < Devise::SessionsController
end end
end end
def after_sign_out_path_for(_resource_or_scope)
Devise.omniauth_configs.each_value do |config|
return root_path if config.strategy.redirect_at_sign_in
end
super
end
def two_factor_enabled? def two_factor_enabled?
find_user.try(:otp_required_for_login?) find_user.try(:otp_required_for_login?)
end end

View File

@@ -5,7 +5,6 @@ class AuthorizeFollowsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action :set_pack before_action :set_pack
before_action :set_body_classes
def show def show
@account = located_account || render(:error) @account = located_account || render(:error)
@@ -46,7 +45,7 @@ class AuthorizeFollowsController < ApplicationController
end end
def account_from_remote_follow def account_from_remote_follow
ResolveAccountService.new.call(acct_without_prefix) ResolveRemoteAccountService.new.call(acct_without_prefix)
end end
def acct_param_is_url? def acct_param_is_url?
@@ -64,8 +63,4 @@ class AuthorizeFollowsController < ApplicationController
def acct_params def acct_params
params.fetch(:acct, '') params.fetch(:acct, '')
end end
def set_body_classes
@body_classes = 'modal-layout'
end
end end

View File

@@ -17,11 +17,11 @@ module Localized
end end
def default_locale def default_locale
if ENV['DEFAULT_LOCALE'].present? request_locale || env_locale || I18n.default_locale
I18n.default_locale end
else
request_locale || I18n.default_locale def env_locale
end ENV['DEFAULT_LOCALE']
end end
def request_locale def request_locale
@@ -29,14 +29,12 @@ module Localized
end end
def preferred_locale def preferred_locale
http_accept_language.preferred_language_from(available_locales) http_accept_language.preferred_language_from([env_locale]) ||
http_accept_language.preferred_language_from(I18n.available_locales)
end end
def compatible_locale def compatible_locale
http_accept_language.compatible_language_from(available_locales) http_accept_language.compatible_language_from([env_locale]) ||
end http_accept_language.compatible_language_from(I18n.available_locales)
def available_locales
I18n.available_locales.reverse
end end
end end

View File

@@ -1,21 +0,0 @@
# frozen_string_literal: true
module RemoteAccountControllerConcern
extend ActiveSupport::Concern
included do
layout 'public'
before_action :set_account
before_action :check_account_suspension
end
private
def set_account
@account = Account.find_remote!(params[:acct])
end
def check_account_suspension
gone if @account.suspended?
end
end

View File

@@ -1,22 +0,0 @@
# frozen_string_literal: true
module SessionTrackingConcern
extend ActiveSupport::Concern
UPDATE_SIGN_IN_HOURS = 24
included do
before_action :set_session_activity
end
private
def set_session_activity
return unless session_needs_update?
current_session.touch
end
def session_needs_update?
!current_session.nil? && current_session.updated_at < UPDATE_SIGN_IN_HOURS.hours.ago
end
end

View File

@@ -1,11 +0,0 @@
# frozen_string_literal: true
module SignatureAuthentication
extend ActiveSupport::Concern
include SignatureVerification
def current_account
super || signed_request_account
end
end

View File

@@ -107,12 +107,14 @@ module SignatureVerification
def incompatible_signature?(signature_params) def incompatible_signature?(signature_params)
signature_params['keyId'].blank? || signature_params['keyId'].blank? ||
signature_params['signature'].blank? signature_params['signature'].blank? ||
signature_params['algorithm'].blank? ||
signature_params['algorithm'] != 'rsa-sha256'
end end
def account_from_key_id(key_id) def account_from_key_id(key_id)
if key_id.start_with?('acct:') if key_id.start_with?('acct:')
ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, '')) ResolveRemoteAccountService.new.call(key_id.gsub(/\Aacct:/, ''))
elsif !ActivityPub::TagManager.instance.local_uri?(key_id) elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
account = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account) account = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account)
account ||= ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false) account ||= ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false)

View File

@@ -3,6 +3,7 @@
module UserTrackingConcern module UserTrackingConcern
extend ActiveSupport::Concern extend ActiveSupport::Concern
REGENERATE_FEED_DAYS = 14
UPDATE_SIGN_IN_HOURS = 24 UPDATE_SIGN_IN_HOURS = 24
included do included do
@@ -13,10 +14,24 @@ module UserTrackingConcern
def set_user_activity def set_user_activity
return unless user_needs_sign_in_update? return unless user_needs_sign_in_update?
# Mark as signed-in today
current_user.update_tracked_fields!(request) current_user.update_tracked_fields!(request)
# Regenerate feed if needed
regenerate_feed! if user_needs_feed_update?
end end
def user_needs_sign_in_update? def user_needs_sign_in_update?
user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_HOURS.hours.ago) user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_HOURS.hours.ago)
end end
def user_needs_feed_update?
current_user.last_sign_in_at < REGENERATE_FEED_DAYS.days.ago
end
def regenerate_feed!
Redis.current.setnx("account:#{current_user.account_id}:regeneration", true) == 1 && Redis.current.expire("account:#{current_user.account_id}:regeneration", 3_600 * 24)
RegenerationWorker.perform_async(current_user.account_id)
end
end end

View File

@@ -2,16 +2,14 @@
class EmojisController < ApplicationController class EmojisController < ApplicationController
before_action :set_emoji before_action :set_emoji
before_action :set_cache_headers
def show def show
respond_to do |format| respond_to do |format|
format.json do format.json do
skip_session! render json: @emoji,
serializer: ActivityPub::EmojiSerializer,
render_cached_json(['activitypub', 'emoji', @emoji.cache_key], content_type: 'application/activity+json') do adapter: ActivityPub::Adapter,
ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter) content_type: 'application/activity+json'
end
end end
end end
end end

View File

@@ -4,19 +4,14 @@ class FollowerAccountsController < ApplicationController
include AccountControllerConcern include AccountControllerConcern
def index def index
@follows = Follow.where(target_account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account)
respond_to do |format| respond_to do |format|
format.html do format.html do
use_pack 'public' use_pack 'public'
next if @account.user_hides_network?
follows
@relationships = AccountRelationshipsPresenter.new(follows.map(&:account_id), current_user.account_id) if user_signed_in?
end end
format.json do format.json do
raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?
render json: collection_presenter, render json: collection_presenter,
serializer: ActivityPub::CollectionSerializer, serializer: ActivityPub::CollectionSerializer,
adapter: ActivityPub::Adapter, adapter: ActivityPub::Adapter,
@@ -27,31 +22,28 @@ class FollowerAccountsController < ApplicationController
private private
def follows
@follows ||= Follow.where(target_account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account)
end
def page_url(page) def page_url(page)
account_followers_url(@account, page: page) unless page.nil? account_followers_url(@account, page: page) unless page.nil?
end end
def collection_presenter def collection_presenter
page = ActivityPub::CollectionPresenter.new(
id: account_followers_url(@account, page: params.fetch(:page, 1)),
type: :ordered,
size: @account.followers_count,
items: @follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) },
part_of: account_followers_url(@account),
next: page_url(@follows.next_page),
prev: page_url(@follows.prev_page)
)
if params[:page].present? if params[:page].present?
ActivityPub::CollectionPresenter.new( page
id: account_followers_url(@account, page: params.fetch(:page, 1)),
type: :ordered,
size: @account.followers_count,
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) },
part_of: account_followers_url(@account),
next: page_url(follows.next_page),
prev: page_url(follows.prev_page)
)
else else
ActivityPub::CollectionPresenter.new( ActivityPub::CollectionPresenter.new(
id: account_followers_url(@account), id: account_followers_url(@account),
type: :ordered, type: :ordered,
size: @account.followers_count, size: @account.followers_count,
first: page_url(1) first: page
) )
end end
end end

View File

@@ -4,19 +4,14 @@ class FollowingAccountsController < ApplicationController
include AccountControllerConcern include AccountControllerConcern
def index def index
@follows = Follow.where(account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account)
respond_to do |format| respond_to do |format|
format.html do format.html do
use_pack 'public' use_pack 'public'
next if @account.user_hides_network?
follows
@relationships = AccountRelationshipsPresenter.new(follows.map(&:target_account_id), current_user.account_id) if user_signed_in?
end end
format.json do format.json do
raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?
render json: collection_presenter, render json: collection_presenter,
serializer: ActivityPub::CollectionSerializer, serializer: ActivityPub::CollectionSerializer,
adapter: ActivityPub::Adapter, adapter: ActivityPub::Adapter,
@@ -27,31 +22,28 @@ class FollowingAccountsController < ApplicationController
private private
def follows
@follows ||= Follow.where(account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account)
end
def page_url(page) def page_url(page)
account_following_index_url(@account, page: page) unless page.nil? account_following_index_url(@account, page: page) unless page.nil?
end end
def collection_presenter def collection_presenter
page = ActivityPub::CollectionPresenter.new(
id: account_following_index_url(@account, page: params.fetch(:page, 1)),
type: :ordered,
size: @account.following_count,
items: @follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) },
part_of: account_following_index_url(@account),
next: page_url(@follows.next_page),
prev: page_url(@follows.prev_page)
)
if params[:page].present? if params[:page].present?
ActivityPub::CollectionPresenter.new( page
id: account_following_index_url(@account, page: params.fetch(:page, 1)),
type: :ordered,
size: @account.following_count,
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) },
part_of: account_following_index_url(@account),
next: page_url(follows.next_page),
prev: page_url(follows.prev_page)
)
else else
ActivityPub::CollectionPresenter.new( ActivityPub::CollectionPresenter.new(
id: account_following_index_url(@account), id: account_following_index_url(@account),
type: :ordered, type: :ordered,
size: @account.following_count, size: @account.following_count,
first: page_url(1) first: page
) )
end end
end end

View File

@@ -2,9 +2,7 @@
class HomeController < ApplicationController class HomeController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action :set_pack before_action :set_pack
before_action :set_referrer_policy_header
before_action :set_initial_state_json before_action :set_initial_state_json
def index def index
@@ -37,8 +35,7 @@ class HomeController < ApplicationController
end end
end end
matches = request.path.match(%r{\A/web/timelines/tag/(?<tag>.+)\z}) redirect_to(default_redirect_path)
redirect_to(matches ? tag_path(CGI.unescape(matches[:tag])) : default_redirect_path)
end end
def set_pack def set_pack
@@ -69,8 +66,4 @@ class HomeController < ApplicationController
about_path about_path
end end
end end
def set_referrer_policy_header
response.headers['Referrer-Policy'] = 'origin'
end
end end

View File

@@ -1,10 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class IntentsController < ApplicationController class IntentsController < ApplicationController
before_action :check_uri
rescue_from Addressable::URI::InvalidURIError, with: :handle_invalid_uri
def show def show
uri = Addressable::URI.parse(params[:uri])
if uri.scheme == 'web+mastodon' if uri.scheme == 'web+mastodon'
case uri.host case uri.host
when 'follow' when 'follow'
@@ -16,18 +15,4 @@ class IntentsController < ApplicationController
not_found not_found
end end
private
def check_uri
not_found if uri.blank?
end
def handle_invalid_uri
not_found
end
def uri
@uri ||= Addressable::URI.parse(params[:uri])
end
end end

View File

@@ -11,7 +11,7 @@ class InvitesController < ApplicationController
def index def index
authorize :invite, :create? authorize :invite, :create?
@invites = invites @invites = Invite.where(user: current_user)
@invite = Invite.new(expires_in: 1.day.to_i) @invite = Invite.new(expires_in: 1.day.to_i)
end end
@@ -24,13 +24,13 @@ class InvitesController < ApplicationController
if @invite.save if @invite.save
redirect_to invites_path redirect_to invites_path
else else
@invites = invites @invites = Invite.where(user: current_user)
render :index render :index
end end
end end
def destroy def destroy
@invite = invites.find(params[:id]) @invite = Invite.where(user: current_user).find(params[:id])
authorize @invite, :destroy? authorize @invite, :destroy?
@invite.expire! @invite.expire!
redirect_to invites_path redirect_to invites_path
@@ -42,10 +42,6 @@ class InvitesController < ApplicationController
use_pack 'settings' use_pack 'settings'
end end
def invites
Invite.where(user: current_user)
end
def resource_params def resource_params
params.require(:invite).permit(:max_uses, :expires_in) params.require(:invite).permit(:max_uses, :expires_in)
end end

View File

@@ -3,26 +3,20 @@
class MediaController < ApplicationController class MediaController < ApplicationController
include Authorization include Authorization
before_action :set_media_attachment before_action :verify_permitted_status
before_action :verify_permitted_status!
def show def show
redirect_to @media_attachment.file.url(:original) redirect_to media_attachment.file.url(:original)
end
def player
@body_classes = 'player'
raise ActiveRecord::RecordNotFound unless @media_attachment.video? || @media_attachment.gifv?
end end
private private
def set_media_attachment def media_attachment
@media_attachment = MediaAttachment.attached.find_by!(shortcode: params[:id] || params[:medium_id]) MediaAttachment.attached.find_by!(shortcode: params[:id])
end end
def verify_permitted_status! def verify_permitted_status
authorize @media_attachment.status, :show? authorize media_attachment.status, :show?
rescue Mastodon::NotPermittedError rescue Mastodon::NotPermittedError
# Reraise in order to get a 404 instead of a 403 error code # Reraise in order to get a 404 instead of a 403 error code
raise ActiveRecord::RecordNotFound raise ActiveRecord::RecordNotFound

View File

@@ -8,8 +8,6 @@ class MediaProxyController < ApplicationController
if lock.acquired? if lock.acquired?
@media_attachment = MediaAttachment.remote.find(params[:id]) @media_attachment = MediaAttachment.remote.find(params[:id])
redownload! if @media_attachment.needs_redownload? && !reject_media? redownload! if @media_attachment.needs_redownload? && !reject_media?
else
raise Mastodon::RaceConditionError
end end
end end

View File

@@ -9,11 +9,6 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
include Localized include Localized
def destroy
Web::PushSubscription.unsubscribe_for(params[:id], current_resource_owner)
super
end
private private
def store_current_location def store_current_location

View File

@@ -1,14 +0,0 @@
# frozen_string_literal: true
class Oauth::TokensController < Doorkeeper::TokensController
def revoke
unsubscribe_for_token if authorized? && token.accessible?
super
end
private
def unsubscribe_for_token
Web::PushSubscription.where(access_token_id: token.id).delete_all
end
end

View File

@@ -43,8 +43,4 @@ class RemoteFollowController < ApplicationController
def suspended_account? def suspended_account?
@account.suspended? @account.suspended?
end end
def set_body_classes
@body_classes = 'modal-layout'
end
end end

View File

@@ -1,39 +0,0 @@
# frozen_string_literal: true
class RemoteUnfollowsController < ApplicationController
layout 'modal'
before_action :authenticate_user!
before_action :set_body_classes
def create
@account = unfollow_attempt.try(:target_account)
if @account.nil?
render :error
else
render :success
end
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
render :error
end
private
def unfollow_attempt
username, domain = acct_without_prefix.split('@')
UnfollowService.new.call(current_account, Account.find_remote!(username, domain))
end
def acct_without_prefix
acct_params.gsub(/\Aacct:/, '')
end
def acct_params
params.fetch(:acct, '')
end
def set_body_classes
@body_classes = 'modal-layout'
end
end

View File

@@ -6,7 +6,7 @@ class Settings::ApplicationsController < Settings::BaseController
before_action :prepare_scopes, only: [:create, :update] before_action :prepare_scopes, only: [:create, :update]
def index def index
@applications = current_user.applications.order(id: :desc).page(params[:page]) @applications = current_user.applications.page(params[:page])
end end
def new def new

Some files were not shown because too many files have changed in this diff Show More