@@ -1,66 +0,0 @@ | |||||
{ | |||||
"presets": [ | |||||
"react", | |||||
[ | |||||
"env", | |||||
{ | |||||
"exclude": ["transform-async-to-generator", "transform-regenerator"], | |||||
"loose": true, | |||||
"modules": false, | |||||
"targets": { | |||||
"browsers": ["last 2 versions", "IE >= 11", "iOS >= 9"] | |||||
} | |||||
} | |||||
] | |||||
], | |||||
"plugins": [ | |||||
"syntax-dynamic-import", | |||||
["transform-object-rest-spread", { "useBuiltIns": true }], | |||||
"transform-decorators-legacy", | |||||
"transform-class-properties", | |||||
[ | |||||
"react-intl", | |||||
{ | |||||
"messagesDir": "./build/messages" | |||||
} | |||||
], | |||||
"preval" | |||||
], | |||||
"env": { | |||||
"development": { | |||||
"plugins": [ | |||||
"transform-react-jsx-source", | |||||
"transform-react-jsx-self" | |||||
] | |||||
}, | |||||
"production": { | |||||
"plugins": [ | |||||
"lodash", | |||||
[ | |||||
"transform-react-remove-prop-types", | |||||
{ | |||||
"mode": "remove", | |||||
"removeImport": true, | |||||
"additionalLibraries": [ | |||||
"react-immutable-proptypes" | |||||
] | |||||
} | |||||
], | |||||
"transform-react-inline-elements", | |||||
[ | |||||
"transform-runtime", | |||||
{ | |||||
"helpers": true, | |||||
"polyfill": false, | |||||
"regenerator": false | |||||
} | |||||
] | |||||
] | |||||
}, | |||||
"test": { | |||||
"plugins": [ | |||||
"transform-es2015-modules-commonjs" | |||||
] | |||||
} | |||||
} | |||||
} |
@@ -1,3 +1,4 @@ | |||||
https://github.com/heroku/heroku-buildpack-apt | https://github.com/heroku/heroku-buildpack-apt | ||||
https://github.com/Scalingo/ffmpeg-buildpack | |||||
https://github.com/Scalingo/nodejs-buildpack | https://github.com/Scalingo/nodejs-buildpack | ||||
https://github.com/Scalingo/ruby-buildpack | https://github.com/Scalingo/ruby-buildpack |
@@ -3,7 +3,7 @@ version: 2 | |||||
aliases: | aliases: | ||||
- &defaults | - &defaults | ||||
docker: | docker: | ||||
- image: circleci/ruby:2.5.1-stretch-node | |||||
- image: circleci/ruby:2.6.0-stretch-node | |||||
environment: &ruby_environment | environment: &ruby_environment | ||||
BUNDLE_APP_CONFIG: ./.bundle/ | BUNDLE_APP_CONFIG: ./.bundle/ | ||||
DB_HOST: localhost | DB_HOST: localhost | ||||
@@ -13,6 +13,9 @@ aliases: | |||||
ALLOW_NOPAM: true | ALLOW_NOPAM: true | ||||
CONTINUOUS_INTEGRATION: true | CONTINUOUS_INTEGRATION: true | ||||
DISABLE_SIMPLECOV: true | DISABLE_SIMPLECOV: true | ||||
PAM_ENABLED: true | |||||
PAM_DEFAULT_SERVICE: pam_test | |||||
PAM_CONTROLLED_SERVICE: pam_test_controlled | |||||
working_directory: ~/projects/mastodon/ | working_directory: ~/projects/mastodon/ | ||||
- &attach_workspace | - &attach_workspace | ||||
@@ -64,12 +67,17 @@ aliases: | |||||
- run: ruby -e 'puts RUBY_VERSION' | tee /tmp/.ruby-version | - run: ruby -e 'puts RUBY_VERSION' | tee /tmp/.ruby-version | ||||
- *restore_ruby_dependencies | - *restore_ruby_dependencies | ||||
- run: bundle install --clean --jobs 16 --path ./vendor/bundle/ --retry 3 --with pam_authentication --without development production | |||||
- run: bundle install --clean --jobs 16 --path ./vendor/bundle/ --retry 3 --with pam_authentication --without development production && bundle clean | |||||
- save_cache: | - save_cache: | ||||
key: v2-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-{{ checksum "Gemfile.lock" }} | key: v2-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-{{ checksum "Gemfile.lock" }} | ||||
paths: | paths: | ||||
- ./.bundle/ | - ./.bundle/ | ||||
- ./vendor/bundle/ | - ./vendor/bundle/ | ||||
- persist_to_workspace: | |||||
root: ~/projects/ | |||||
paths: | |||||
- ./mastodon/.bundle/ | |||||
- ./mastodon/vendor/bundle/ | |||||
- &test_steps | - &test_steps | ||||
steps: | steps: | ||||
@@ -78,15 +86,6 @@ aliases: | |||||
- *install_system_dependencies | - *install_system_dependencies | ||||
- run: sudo apt-get install -y ffmpeg | - 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: | - run: | ||||
name: Prepare Tests | name: Prepare Tests | ||||
command: ./bin/rails parallel:create parallel:load_schema parallel:prepare | command: ./bin/rails parallel:create parallel:load_schema parallel:prepare | ||||
@@ -99,21 +98,21 @@ jobs: | |||||
<<: *defaults | <<: *defaults | ||||
<<: *install_steps | <<: *install_steps | ||||
install-ruby2.5: | |||||
install-ruby2.6: | |||||
<<: *defaults | <<: *defaults | ||||
<<: *install_ruby_dependencies | <<: *install_ruby_dependencies | ||||
install-ruby2.4: | |||||
install-ruby2.5: | |||||
<<: *defaults | <<: *defaults | ||||
docker: | docker: | ||||
- image: circleci/ruby:2.4.4-stretch-node | |||||
- image: circleci/ruby:2.5.3-stretch-node | |||||
environment: *ruby_environment | environment: *ruby_environment | ||||
<<: *install_ruby_dependencies | <<: *install_ruby_dependencies | ||||
install-ruby2.3: | |||||
install-ruby2.4: | |||||
<<: *defaults | <<: *defaults | ||||
docker: | docker: | ||||
- image: circleci/ruby:2.3.7-stretch-node | |||||
- image: circleci/ruby:2.4.5-stretch-node | |||||
environment: *ruby_environment | environment: *ruby_environment | ||||
<<: *install_ruby_dependencies | <<: *install_ruby_dependencies | ||||
@@ -122,52 +121,50 @@ jobs: | |||||
steps: | steps: | ||||
- *attach_workspace | - *attach_workspace | ||||
- *install_system_dependencies | - *install_system_dependencies | ||||
- run: ruby -e 'puts RUBY_VERSION' | tee /tmp/.ruby-version | |||||
- *restore_ruby_dependencies | |||||
- run: ./bin/rails assets:precompile | - run: ./bin/rails assets:precompile | ||||
- save_cache: | |||||
key: precompiled-assets-{{ .Branch }}-{{ .Revision }} | |||||
- persist_to_workspace: | |||||
root: ~/projects/ | |||||
paths: | paths: | ||||
- ./public/assets | |||||
- ./public/packs-test/ | |||||
- ./mastodon/public/assets | |||||
- ./mastodon/public/packs-test/ | |||||
test-ruby2.5: | |||||
test-ruby2.6: | |||||
<<: *defaults | <<: *defaults | ||||
docker: | docker: | ||||
- image: circleci/ruby:2.5.1-stretch-node | |||||
- image: circleci/ruby:2.6.0-stretch-node | |||||
environment: *ruby_environment | environment: *ruby_environment | ||||
- image: circleci/postgres:10.3-alpine | |||||
- image: circleci/postgres:10.6-alpine | |||||
environment: | environment: | ||||
POSTGRES_USER: root | POSTGRES_USER: root | ||||
- image: circleci/redis:4.0.9-alpine | |||||
- image: circleci/redis:5.0.3-alpine3.8 | |||||
<<: *test_steps | <<: *test_steps | ||||
test-ruby2.4: | |||||
test-ruby2.5: | |||||
<<: *defaults | <<: *defaults | ||||
docker: | docker: | ||||
- image: circleci/ruby:2.4.4-stretch-node | |||||
- image: circleci/ruby:2.5.3-stretch-node | |||||
environment: *ruby_environment | environment: *ruby_environment | ||||
- image: circleci/postgres:10.3-alpine | |||||
- image: circleci/postgres:10.6-alpine | |||||
environment: | environment: | ||||
POSTGRES_USER: root | POSTGRES_USER: root | ||||
- image: circleci/redis:4.0.9-alpine | |||||
- image: circleci/redis:4.0.12-alpine | |||||
<<: *test_steps | <<: *test_steps | ||||
test-ruby2.3: | |||||
test-ruby2.4: | |||||
<<: *defaults | <<: *defaults | ||||
docker: | docker: | ||||
- image: circleci/ruby:2.3.7-stretch-node | |||||
- image: circleci/ruby:2.4.5-stretch-node | |||||
environment: *ruby_environment | environment: *ruby_environment | ||||
- image: circleci/postgres:10.3-alpine | |||||
- image: circleci/postgres:10.6-alpine | |||||
environment: | environment: | ||||
POSTGRES_USER: root | POSTGRES_USER: root | ||||
- image: circleci/redis:4.0.9-alpine | |||||
- image: circleci/redis:4.0.12-alpine | |||||
<<: *test_steps | <<: *test_steps | ||||
test-webui: | test-webui: | ||||
<<: *defaults | <<: *defaults | ||||
docker: | docker: | ||||
- image: circleci/node:8.11.1-stretch | |||||
- image: circleci/node:8.15.0-stretch | |||||
steps: | steps: | ||||
- *attach_workspace | - *attach_workspace | ||||
- run: ./bin/retry yarn test:jest | - run: ./bin/retry yarn test:jest | ||||
@@ -176,28 +173,34 @@ jobs: | |||||
<<: *defaults | <<: *defaults | ||||
steps: | steps: | ||||
- *attach_workspace | - *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 check-normalized | ||||
- run: bundle exec i18n-tasks unused | - run: bundle exec i18n-tasks unused | ||||
- run: bundle exec i18n-tasks missing -t plural | |||||
- run: bundle exec i18n-tasks check-consistent-interpolations | |||||
workflows: | workflows: | ||||
version: 2 | version: 2 | ||||
build-and-test: | build-and-test: | ||||
jobs: | jobs: | ||||
- install | - install | ||||
- install-ruby2.5: | |||||
- install-ruby2.6: | |||||
requires: | requires: | ||||
- install | - install | ||||
- install-ruby2.4: | |||||
- install-ruby2.5: | |||||
requires: | requires: | ||||
- install | - install | ||||
- install-ruby2.3: | |||||
- install-ruby2.6 | |||||
- install-ruby2.4: | |||||
requires: | requires: | ||||
- install | - install | ||||
- install-ruby2.6 | |||||
- build: | - build: | ||||
requires: | requires: | ||||
- install-ruby2.5 | |||||
- install-ruby2.6 | |||||
- test-ruby2.6: | |||||
requires: | |||||
- install-ruby2.6 | |||||
- build | |||||
- test-ruby2.5: | - test-ruby2.5: | ||||
requires: | requires: | ||||
- install-ruby2.5 | - install-ruby2.5 | ||||
@@ -206,13 +209,9 @@ workflows: | |||||
requires: | requires: | ||||
- install-ruby2.4 | - install-ruby2.4 | ||||
- build | - build | ||||
- test-ruby2.3: | |||||
requires: | |||||
- install-ruby2.3 | |||||
- build | |||||
- test-webui: | - test-webui: | ||||
requires: | requires: | ||||
- install | - install | ||||
- check-i18n: | - check-i18n: | ||||
requires: | requires: | ||||
- install-ruby2.5 | |||||
- install-ruby2.6 |
@@ -27,7 +27,7 @@ plugins: | |||||
enabled: true | enabled: true | ||||
eslint: | eslint: | ||||
enabled: true | enabled: true | ||||
channel: eslint-4 | |||||
channel: eslint-5 | |||||
rubocop: | rubocop: | ||||
enabled: true | enabled: true | ||||
channel: rubocop-0-54 | channel: rubocop-0-54 | ||||
@@ -136,8 +136,8 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io | |||||
# Defaults to 60 seconds. Set to 0 to disable | # Defaults to 60 seconds. Set to 0 to disable | ||||
# SWIFT_CACHE_TTL= | # SWIFT_CACHE_TTL= | ||||
# Optional alias for S3 if you want to use Cloudfront or Cloudflare in front | |||||
# S3_CLOUDFRONT_HOST= | |||||
# Optional alias for S3 (e.g. to serve files on a custom domain, possibly using Cloudfront or Cloudflare) | |||||
# S3_ALIAS_HOST= | |||||
# Streaming API integration | # Streaming API integration | ||||
# STREAMING_API_BASE_URL= | # STREAMING_API_BASE_URL= | ||||
@@ -134,8 +134,8 @@ SMTP_FROM_ADDRESS=notifications@example.com | |||||
# Defaults to 60 seconds. Set to 0 to disable | # Defaults to 60 seconds. Set to 0 to disable | ||||
# SWIFT_CACHE_TTL= | # SWIFT_CACHE_TTL= | ||||
# Optional alias for S3 if you want to use Cloudfront or Cloudflare in front | |||||
# S3_CLOUDFRONT_HOST= | |||||
# Optional alias for S3 (e.g. to serve files on a custom domain, possibly using Cloudfront or Cloudflare) | |||||
# S3_ALIAS_HOST= | |||||
# Streaming API integration | # Streaming API integration | ||||
# STREAMING_API_BASE_URL= | # STREAMING_API_BASE_URL= | ||||
@@ -162,6 +162,7 @@ STREAMING_CLUSTER_NUM=1 | |||||
# LDAP_BIND_DN= | # LDAP_BIND_DN= | ||||
# LDAP_PASSWORD= | # LDAP_PASSWORD= | ||||
# LDAP_UID=cn | # LDAP_UID=cn | ||||
# LDAP_SEARCH_FILTER="%{uid}=%{email}" | |||||
# PAM authentication (optional) | # PAM authentication (optional) | ||||
# PAM authentication uses for the email generation the "email" pam variable | # PAM authentication uses for the email generation the "email" pam variable | ||||
@@ -3,7 +3,3 @@ NODE_ENV=test | |||||
# Federation | # Federation | ||||
LOCAL_DOMAIN=cb6e6126.ngrok.io | LOCAL_DOMAIN=cb6e6126.ngrok.io | ||||
LOCAL_HTTPS=true | LOCAL_HTTPS=true | ||||
# test pam authentication | |||||
PAM_ENABLED=true | |||||
PAM_DEFAULT_SERVICE=pam_test | |||||
PAM_CONTROLLED_SERVICE=pam_test_controlled |
@@ -1,2 +1,2 @@ | |||||
VAGRANT=true | VAGRANT=true | ||||
LOCAL_DOMAIN=mastodon.dev | |||||
LOCAL_DOMAIN=mastodon.local |
@@ -1,30 +1,13 @@ | |||||
# See https://help.github.com/articles/ignoring-files for more about ignoring files. | |||||
# | |||||
# If you find yourself ignoring temporary files generated by your text editor | |||||
# or operating system, you probably want to add a global ignore instead: | |||||
# git config --global core.excludesfile '~/.gitignore_global' | |||||
# Ignore bundler config. | |||||
/.bundle | |||||
# Ignore the default SQLite database. | |||||
/db/*.sqlite3 | |||||
/db/*.sqlite3-journal | |||||
# Ignore all logfiles and tempfiles. | |||||
/log/* | |||||
!/log/.keep | |||||
/tmp | |||||
coverage | |||||
public/system | |||||
public/assets | |||||
.env | |||||
.env.production | |||||
node_modules/ | |||||
neo4j/ | |||||
# Ignore Vagrant files | |||||
.vagrant/ | |||||
# Ignore Capistrano customizations | |||||
config/deploy/* | |||||
/build/** | |||||
/coverage/** | |||||
/db/** | |||||
/lib/** | |||||
/log/** | |||||
/node_modules/** | |||||
/nonobox/** | |||||
/public/** | |||||
!/public/embed.js | |||||
/spec/** | |||||
/tmp/** | |||||
/vendor/** | |||||
!.eslintrc.js |
@@ -0,0 +1,199 @@ | |||||
module.exports = { | |||||
root: true, | |||||
env: { | |||||
browser: true, | |||||
node: true, | |||||
es6: true, | |||||
jest: true, | |||||
}, | |||||
globals: { | |||||
ATTACHMENT_HOST: false, | |||||
}, | |||||
parser: 'babel-eslint', | |||||
plugins: [ | |||||
'react', | |||||
'jsx-a11y', | |||||
'import', | |||||
'promise', | |||||
], | |||||
parserOptions: { | |||||
sourceType: 'module', | |||||
ecmaFeatures: { | |||||
experimentalObjectRestSpread: true, | |||||
jsx: true, | |||||
}, | |||||
ecmaVersion: 2018, | |||||
}, | |||||
settings: { | |||||
react: { | |||||
version: 'detect', | |||||
}, | |||||
'import/extensions': [ | |||||
'.js', | |||||
], | |||||
'import/ignore': [ | |||||
'node_modules', | |||||
'\\.(css|scss|json)$', | |||||
], | |||||
}, | |||||
rules: { | |||||
'brace-style': 'warn', | |||||
'comma-dangle': ['error', 'always-multiline'], | |||||
'comma-spacing': [ | |||||
'warn', | |||||
{ | |||||
before: false, | |||||
after: true, | |||||
}, | |||||
], | |||||
'comma-style': ['warn', 'last'], | |||||
'consistent-return': 'error', | |||||
'dot-notation': 'error', | |||||
eqeqeq: 'error', | |||||
indent: ['warn', 2], | |||||
'jsx-quotes': ['error', 'prefer-single'], | |||||
'no-catch-shadow': 'error', | |||||
'no-cond-assign': 'error', | |||||
'no-console': [ | |||||
'warn', | |||||
{ | |||||
allow: [ | |||||
'error', | |||||
'warn', | |||||
], | |||||
}, | |||||
], | |||||
'no-fallthrough': 'error', | |||||
'no-irregular-whitespace': 'error', | |||||
'no-mixed-spaces-and-tabs': 'warn', | |||||
'no-nested-ternary': 'warn', | |||||
'no-trailing-spaces': 'warn', | |||||
'no-undef': 'error', | |||||
'no-unreachable': 'error', | |||||
'no-unused-expressions': 'error', | |||||
'no-unused-vars': [ | |||||
'error', | |||||
{ | |||||
vars: 'all', | |||||
args: 'after-used', | |||||
ignoreRestSiblings: true, | |||||
}, | |||||
], | |||||
'object-curly-spacing': ['error', 'always'], | |||||
'padded-blocks': [ | |||||
'error', | |||||
{ | |||||
classes: 'always', | |||||
}, | |||||
], | |||||
quotes: ['error', 'single'], | |||||
semi: 'error', | |||||
strict: 'off', | |||||
'valid-typeof': 'error', | |||||
'react/jsx-boolean-value': 'error', | |||||
'react/jsx-closing-bracket-location': ['error', 'line-aligned'], | |||||
'react/jsx-curly-spacing': 'error', | |||||
'react/jsx-equals-spacing': 'error', | |||||
'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'], | |||||
'react/jsx-indent': ['error', 2], | |||||
'react/jsx-no-bind': 'error', | |||||
'react/jsx-no-duplicate-props': 'error', | |||||
'react/jsx-no-undef': 'error', | |||||
'react/jsx-tag-spacing': 'error', | |||||
'react/jsx-uses-react': 'error', | |||||
'react/jsx-uses-vars': 'error', | |||||
'react/jsx-wrap-multilines': 'error', | |||||
'react/no-multi-comp': 'off', | |||||
'react/no-string-refs': 'error', | |||||
'react/prop-types': 'error', | |||||
'react/self-closing-comp': 'error', | |||||
'jsx-a11y/accessible-emoji': 'warn', | |||||
'jsx-a11y/alt-text': '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-props': 'warn', | |||||
'jsx-a11y/aria-proptypes': 'warn', | |||||
'jsx-a11y/aria-role': 'warn', | |||||
'jsx-a11y/aria-unsupported-elements': 'warn', | |||||
'jsx-a11y/heading-has-content': 'warn', | |||||
'jsx-a11y/html-has-lang': 'warn', | |||||
'jsx-a11y/iframe-has-title': 'warn', | |||||
'jsx-a11y/img-redundant-alt': 'warn', | |||||
'jsx-a11y/interactive-supports-focus': 'warn', | |||||
'jsx-a11y/label-has-for': 'off', | |||||
'jsx-a11y/mouse-events-have-key-events': 'warn', | |||||
'jsx-a11y/no-access-key': 'warn', | |||||
'jsx-a11y/no-distracting-elements': 'warn', | |||||
'jsx-a11y/no-noninteractive-element-interactions': [ | |||||
'warn', | |||||
{ | |||||
handlers: [ | |||||
'onClick', | |||||
], | |||||
}, | |||||
], | |||||
'jsx-a11y/no-onchange': 'warn', | |||||
'jsx-a11y/no-redundant-roles': 'warn', | |||||
'jsx-a11y/no-static-element-interactions': [ | |||||
'warn', | |||||
{ | |||||
handlers: [ | |||||
'onClick', | |||||
], | |||||
}, | |||||
], | |||||
'jsx-a11y/role-has-required-aria-props': 'warn', | |||||
'jsx-a11y/role-supports-aria-props': 'off', | |||||
'jsx-a11y/scope': 'warn', | |||||
'jsx-a11y/tabindex-no-positive': 'warn', | |||||
'import/extensions': [ | |||||
'error', | |||||
'always', | |||||
{ | |||||
js: 'never', | |||||
}, | |||||
], | |||||
'import/newline-after-import': 'error', | |||||
'import/no-extraneous-dependencies': [ | |||||
'error', | |||||
{ | |||||
devDependencies: [ | |||||
'config/webpack/**', | |||||
'app/javascript/mastodon/test_setup.js', | |||||
'app/javascript/**/__tests__/**', | |||||
], | |||||
}, | |||||
], | |||||
'import/no-unresolved': 'error', | |||||
'import/no-webpack-loader-syntax': 'error', | |||||
'promise/catch-or-return': 'error', | |||||
}, | |||||
}; |
@@ -1,170 +0,0 @@ | |||||
--- | |||||
root: true | |||||
env: | |||||
browser: true | |||||
node: true | |||||
es6: true | |||||
jest: true | |||||
globals: | |||||
ATTACHMENT_HOST: false | |||||
parser: babel-eslint | |||||
plugins: | |||||
- react | |||||
- jsx-a11y | |||||
- import | |||||
- promise | |||||
parserOptions: | |||||
sourceType: module | |||||
ecmaFeatures: | |||||
experimentalObjectRestSpread: true | |||||
jsx: true | |||||
ecmaVersion: 2018 | |||||
settings: | |||||
import/extensions: | |||||
- .js | |||||
import/ignore: | |||||
- node_modules | |||||
- \\.(css|scss|json)$ | |||||
rules: | |||||
brace-style: warn | |||||
comma-dangle: | |||||
- error | |||||
- always-multiline | |||||
comma-spacing: | |||||
- warn | |||||
- before: false | |||||
after: true | |||||
comma-style: | |||||
- warn | |||||
- last | |||||
consistent-return: error | |||||
dot-notation: error | |||||
eqeqeq: error | |||||
indent: | |||||
- warn | |||||
- 2 | |||||
jsx-quotes: | |||||
- error | |||||
- prefer-single | |||||
no-catch-shadow: error | |||||
no-cond-assign: error | |||||
no-console: | |||||
- warn | |||||
- allow: | |||||
- error | |||||
- warn | |||||
no-fallthrough: error | |||||
no-irregular-whitespace: error | |||||
no-mixed-spaces-and-tabs: warn | |||||
no-nested-ternary: warn | |||||
no-trailing-spaces: warn | |||||
no-undef: error | |||||
no-unreachable: error | |||||
no-unused-expressions: error | |||||
no-unused-vars: | |||||
- error | |||||
- vars: all | |||||
args: after-used | |||||
ignoreRestSiblings: true | |||||
object-curly-spacing: | |||||
- error | |||||
- always | |||||
padded-blocks: | |||||
- error | |||||
- classes: always | |||||
quotes: | |||||
- error | |||||
- single | |||||
semi: error | |||||
strict: off | |||||
valid-typeof: error | |||||
react/jsx-boolean-value: error | |||||
react/jsx-closing-bracket-location: | |||||
- error | |||||
- line-aligned | |||||
react/jsx-curly-spacing: error | |||||
react/jsx-equals-spacing: error | |||||
react/jsx-first-prop-new-line: | |||||
- error | |||||
- multiline-multiprop | |||||
react/jsx-indent: | |||||
- error | |||||
- 2 | |||||
react/jsx-no-bind: error | |||||
react/jsx-no-duplicate-props: error | |||||
react/jsx-no-undef: error | |||||
react/jsx-tag-spacing: error | |||||
react/jsx-uses-react: error | |||||
react/jsx-uses-vars: error | |||||
react/jsx-wrap-multilines: error | |||||
react/no-multi-comp: off | |||||
react/no-string-refs: error | |||||
react/prop-types: error | |||||
react/self-closing-comp: error | |||||
jsx-a11y/accessible-emoji: warn | |||||
jsx-a11y/alt-text: 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-props: warn | |||||
jsx-a11y/aria-proptypes: warn | |||||
jsx-a11y/aria-role: warn | |||||
jsx-a11y/aria-unsupported-elements: warn | |||||
jsx-a11y/heading-has-content: warn | |||||
jsx-a11y/html-has-lang: warn | |||||
jsx-a11y/iframe-has-title: warn | |||||
jsx-a11y/img-redundant-alt: warn | |||||
jsx-a11y/interactive-supports-focus: warn | |||||
jsx-a11y/label-has-for: off | |||||
jsx-a11y/mouse-events-have-key-events: warn | |||||
jsx-a11y/no-access-key: warn | |||||
jsx-a11y/no-distracting-elements: warn | |||||
jsx-a11y/no-noninteractive-element-interactions: | |||||
- warn | |||||
- handlers: | |||||
- onClick | |||||
jsx-a11y/no-onchange: warn | |||||
jsx-a11y/no-redundant-roles: warn | |||||
jsx-a11y/no-static-element-interactions: | |||||
- warn | |||||
- handlers: | |||||
- onClick | |||||
jsx-a11y/role-has-required-aria-props: warn | |||||
jsx-a11y/role-supports-aria-props: off | |||||
jsx-a11y/scope: warn | |||||
jsx-a11y/tabindex-no-positive: warn | |||||
import/extensions: | |||||
- error | |||||
- always | |||||
- js: never | |||||
import/newline-after-import: error | |||||
import/no-extraneous-dependencies: | |||||
- error | |||||
- devDependencies: | |||||
- "config/webpack/**" | |||||
- "app/javascript/mastodon/test_setup.js" | |||||
- "app/javascript/**/__tests__/**" | |||||
import/no-unresolved: error | |||||
import/no-webpack-loader-syntax: error | |||||
promise/catch-or-return: error |
@@ -1,12 +1,27 @@ | |||||
--- | --- | ||||
name: Bug Report | name: Bug Report | ||||
about: Create a report to help us improve | |||||
about: If something isn't working as expected | |||||
--- | --- | ||||
[Issue text goes here]. | |||||
<!-- Make sure that you are submitting a new bug that was not previously reported or already fixed --> | |||||
* * * * | |||||
<!-- Please use a concise and distinct title for the issue --> | |||||
- [ ] I searched or browsed the repo’s other issues to ensure this is not a duplicate. | |||||
- [ ] This bug happens on a [tagged release](https://github.com/tootsuite/mastodon/releases) and not on `master` (If you're a user, don't worry about this). | |||||
### Expected behaviour | |||||
<!-- What should have happened? --> | |||||
### Actual behaviour | |||||
<!-- What happened? --> | |||||
### Steps to reproduce the problem | |||||
<!-- What were you trying to do? --> | |||||
### Specifications | |||||
<!-- What version or commit hash of Mastodon did you find this bug in? --> | |||||
<!-- If a front-end issue, what browser and operating systems were you using? --> |
@@ -1,11 +1,17 @@ | |||||
--- | --- | ||||
name: Feature Request | name: Feature Request | ||||
about: Suggest an idea for this project | |||||
about: I have a suggestion | |||||
--- | --- | ||||
[Issue text goes here]. | |||||
<!-- Please use a concise and distinct title for the issue --> | |||||
* * * * | |||||
<!-- Consider: Could it be implemented as a 3rd party app using the REST API instead? --> | |||||
- [ ] I searched or browsed the repo’s other issues to ensure this is not a duplicate. | |||||
### Pitch | |||||
<!-- Describe your idea for a feature. Make sure it has not already been suggested/implemented/turned down before --> | |||||
### Motivation | |||||
<!-- Why do you think this feature is needed? Who would benefit from it? --> |
@@ -0,0 +1,10 @@ | |||||
--- | |||||
name: Support | |||||
about: Ask for help with your deployment | |||||
--- | |||||
We primarily use GitHub as a bug and feature tracker. For usage questions, troubleshooting of deployments and other individual technical assistance, please use one of the resources below: | |||||
- https://discourse.joinmastodon.org | |||||
- #mastodon on irc.freenode.net |
@@ -1 +1 @@ | |||||
6 | |||||
8 |
@@ -1,9 +0,0 @@ | |||||
plugins: | |||||
postcss-smart-import: {} | |||||
precss: {} | |||||
autoprefixer: | |||||
browsers: | |||||
- last 2 versions | |||||
- IE >= 11 | |||||
- iOS >= 9 | |||||
postcss-object-fit-images: {} |
@@ -11,6 +11,7 @@ AllCops: | |||||
- 'Vagrantfile' | - 'Vagrantfile' | ||||
- 'vendor/**/*' | - 'vendor/**/*' | ||||
- 'lib/json_ld/*' | - 'lib/json_ld/*' | ||||
- 'lib/templates/**/*' | |||||
Bundler/OrderedGems: | Bundler/OrderedGems: | ||||
Enabled: false | Enabled: false | ||||
@@ -61,6 +62,9 @@ Metrics/ParameterLists: | |||||
Metrics/PerceivedComplexity: | Metrics/PerceivedComplexity: | ||||
Max: 20 | Max: 20 | ||||
Naming/MemoizedInstanceVariableName: | |||||
Enabled: false | |||||
Rails: | Rails: | ||||
Enabled: true | Enabled: true | ||||
@@ -70,6 +74,14 @@ Rails/HasAndBelongsToMany: | |||||
Rails/SkipsModelValidations: | Rails/SkipsModelValidations: | ||||
Enabled: false | Enabled: false | ||||
Rails/HttpStatus: | |||||
Enabled: false | |||||
Rails/Exit: | |||||
Exclude: | |||||
- 'lib/mastodon/*' | |||||
- 'lib/cli' | |||||
Style/ClassAndModuleChildren: | Style/ClassAndModuleChildren: | ||||
Enabled: false | Enabled: false | ||||
@@ -1 +1 @@ | |||||
2.5.1 | |||||
2.6.0 |
@@ -1,158 +1,199 @@ | |||||
Authors | |||||
======= | |||||
Mastodon is available on [GitHub](https://github.com/tootsuite/mastodon) | Mastodon is available on [GitHub](https://github.com/tootsuite/mastodon) | ||||
and provided thanks to the work of the following contributors: | and provided thanks to the work of the following contributors: | ||||
* [Gargron](https://github.com/Gargron) | * [Gargron](https://github.com/Gargron) | ||||
* [ykzts](https://github.com/ykzts) | * [ykzts](https://github.com/ykzts) | ||||
* [mjankowski](https://github.com/mjankowski) | |||||
* [akihikodaki](https://github.com/akihikodaki) | * [akihikodaki](https://github.com/akihikodaki) | ||||
* [ThibG](https://github.com/ThibG) | |||||
* [mjankowski](https://github.com/mjankowski) | |||||
* [unarist](https://github.com/unarist) | * [unarist](https://github.com/unarist) | ||||
* [yiskah](https://github.com/yiskah) | |||||
* [m4sk1n](https://github.com/m4sk1n) | * [m4sk1n](https://github.com/m4sk1n) | ||||
* [dependabot[bot]](https://github.com/apps/dependabot) | |||||
* [yiskah](https://github.com/yiskah) | |||||
* [nolanlawson](https://github.com/nolanlawson) | * [nolanlawson](https://github.com/nolanlawson) | ||||
* [sorin-davidoi](https://github.com/sorin-davidoi) | * [sorin-davidoi](https://github.com/sorin-davidoi) | ||||
* [ysksn](https://github.com/ysksn) | |||||
* [abcang](https://github.com/abcang) | * [abcang](https://github.com/abcang) | ||||
* [ThibG](https://github.com/ThibG) | |||||
* [lynlynlynx](https://github.com/lynlynlynx) | * [lynlynlynx](https://github.com/lynlynlynx) | ||||
* [alpaca-tc](https://github.com/alpaca-tc) | * [alpaca-tc](https://github.com/alpaca-tc) | ||||
* [mayaeh](https://github.com/mayaeh) | |||||
* [renatolond](https://github.com/renatolond) | |||||
* [nclm](https://github.com/nclm) | * [nclm](https://github.com/nclm) | ||||
* [ineffyble](https://github.com/ineffyble) | * [ineffyble](https://github.com/ineffyble) | ||||
* [jeroenpraat](https://github.com/jeroenpraat) | * [jeroenpraat](https://github.com/jeroenpraat) | ||||
* [blackle](https://github.com/blackle) | * [blackle](https://github.com/blackle) | ||||
* [Quent-in](https://github.com/Quent-in) | * [Quent-in](https://github.com/Quent-in) | ||||
* [JantsoP](https://github.com/JantsoP) | * [JantsoP](https://github.com/JantsoP) | ||||
* [mabkenar](https://github.com/mabkenar) | |||||
* [nullkal](https://github.com/nullkal) | * [nullkal](https://github.com/nullkal) | ||||
* [yookoala](https://github.com/yookoala) | * [yookoala](https://github.com/yookoala) | ||||
* [ysksn](https://github.com/ysksn) | |||||
* [Kjwon15](https://github.com/Kjwon15) | |||||
* [shuheiktgw](https://github.com/shuheiktgw) | |||||
* [ashfurrow](https://github.com/ashfurrow) | * [ashfurrow](https://github.com/ashfurrow) | ||||
* [eramdam](https://github.com/eramdam) | |||||
* [mayaeh](https://github.com/mayaeh) | |||||
* [Quenty31](https://github.com/Quenty31) | |||||
* [zunda](https://github.com/zunda) | * [zunda](https://github.com/zunda) | ||||
* [ticky](https://github.com/ticky) | |||||
* [eramdam](https://github.com/eramdam) | |||||
* [takayamaki](https://github.com/takayamaki) | |||||
* [masarakki](https://github.com/masarakki) | * [masarakki](https://github.com/masarakki) | ||||
* [ticky](https://github.com/ticky) | |||||
* [danhunsaker](https://github.com/danhunsaker) | |||||
* [ThisIsMissEm](https://github.com/ThisIsMissEm) | |||||
* [hcmiya](https://github.com/hcmiya) | |||||
* [stephenburgess8](https://github.com/stephenburgess8) | |||||
* [Wonderfall](https://github.com/Wonderfall) | * [Wonderfall](https://github.com/Wonderfall) | ||||
* [matteoaquila](https://github.com/matteoaquila) | * [matteoaquila](https://github.com/matteoaquila) | ||||
* [rkarabut](https://github.com/rkarabut) | * [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) | * [yukimochi](https://github.com/yukimochi) | ||||
* [Artoria2e5](https://github.com/Artoria2e5) | |||||
* [marrus-sh](https://github.com/marrus-sh) | * [marrus-sh](https://github.com/marrus-sh) | ||||
* [krainboltgreene](https://github.com/krainboltgreene) | * [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) | * [patf](https://github.com/patf) | ||||
* [Quenty31](https://github.com/Quenty31) | |||||
* [MitarashiDango](https://github.com/MitarashiDango) | |||||
* [Aldarone](https://github.com/Aldarone) | * [Aldarone](https://github.com/Aldarone) | ||||
* [BoFFire](https://github.com/BoFFire) | |||||
* [clworld](https://github.com/clworld) | |||||
* [dracos](https://github.com/dracos) | |||||
* [SerCom_KC](mailto:sercom-kc@users.noreply.github.com) | |||||
* [Sylvhem](https://github.com/Sylvhem) | |||||
* [nightpool](https://github.com/nightpool) | |||||
* [MasterGroosha](https://github.com/MasterGroosha) | |||||
* [JeanGauthier](https://github.com/JeanGauthier) | * [JeanGauthier](https://github.com/JeanGauthier) | ||||
* [kschaper](https://github.com/kschaper) | * [kschaper](https://github.com/kschaper) | ||||
* [takayamaki](https://github.com/takayamaki) | |||||
* [MaciekBaron](https://github.com/MaciekBaron) | |||||
* [MitarashiDango](mailto:mitarashidango@users.noreply.github.com) | |||||
* [beatrix-bitrot](https://github.com/beatrix-bitrot) | |||||
* [adbelle](https://github.com/adbelle) | * [adbelle](https://github.com/adbelle) | ||||
* [evanminto](https://github.com/evanminto) | * [evanminto](https://github.com/evanminto) | ||||
* [mabkenar](https://github.com/mabkenar) | |||||
* [MightyPork](https://github.com/MightyPork) | * [MightyPork](https://github.com/MightyPork) | ||||
* [beatrix-bitrot](https://github.com/beatrix-bitrot) | |||||
* [yhirano55](https://github.com/yhirano55) | * [yhirano55](https://github.com/yhirano55) | ||||
* [camponez](https://github.com/camponez) | * [camponez](https://github.com/camponez) | ||||
* [SerCom-KC](https://github.com/SerCom-KC) | |||||
* [aschmitz](https://github.com/aschmitz) | * [aschmitz](https://github.com/aschmitz) | ||||
* [devkral](https://github.com/devkral) | |||||
* [fpiesche](https://github.com/fpiesche) | * [fpiesche](https://github.com/fpiesche) | ||||
* [gandaro](https://github.com/gandaro) | * [gandaro](https://github.com/gandaro) | ||||
* [johnsudaar](https://github.com/johnsudaar) | * [johnsudaar](https://github.com/johnsudaar) | ||||
* [trebmuh](https://github.com/trebmuh) | * [trebmuh](https://github.com/trebmuh) | ||||
* [Sylvhem](https://github.com/Sylvhem) | |||||
* [Rakib Hasan](mailto:rmhasan@gmail.com) | |||||
* [lindwurm](https://github.com/lindwurm) | * [lindwurm](https://github.com/lindwurm) | ||||
* [victorhck](mailto:victorhck@geeko.site) | |||||
* [voidsatisfaction](https://github.com/voidsatisfaction) | * [voidsatisfaction](https://github.com/voidsatisfaction) | ||||
* [neetshin](https://github.com/neetshin) | |||||
* [valentin2105](https://github.com/valentin2105) | |||||
* [hikari-no-yume](https://github.com/hikari-no-yume) | * [hikari-no-yume](https://github.com/hikari-no-yume) | ||||
* [Angristan](https://github.com/Angristan) | |||||
* [angristan](https://github.com/angristan) | |||||
* [seefood](https://github.com/seefood) | * [seefood](https://github.com/seefood) | ||||
* [jackjennings](https://github.com/jackjennings) | * [jackjennings](https://github.com/jackjennings) | ||||
* [hcmiya](https://github.com/hcmiya) | |||||
* [nightpool](https://github.com/nightpool) | |||||
* [salvadorpla](https://github.com/salvadorpla) | |||||
* [spla](mailto:spla@mastodont.cat) | |||||
* [expenses](https://github.com/expenses) | * [expenses](https://github.com/expenses) | ||||
* [walf443](https://github.com/walf443) | * [walf443](https://github.com/walf443) | ||||
* [JoelQ](https://github.com/JoelQ) | * [JoelQ](https://github.com/JoelQ) | ||||
* [mistydemeo](https://github.com/mistydemeo) | * [mistydemeo](https://github.com/mistydemeo) | ||||
* [dunn](https://github.com/dunn) | * [dunn](https://github.com/dunn) | ||||
* [xqus](https://github.com/xqus) | * [xqus](https://github.com/xqus) | ||||
* [hugogameiro](https://github.com/hugogameiro) | |||||
* [pfm-eyesightjp](https://github.com/pfm-eyesightjp) | * [pfm-eyesightjp](https://github.com/pfm-eyesightjp) | ||||
* [fakenine](https://github.com/fakenine) | * [fakenine](https://github.com/fakenine) | ||||
* [tsuwatch](https://github.com/tsuwatch) | * [tsuwatch](https://github.com/tsuwatch) | ||||
* [victorhck](https://github.com/victorhck) | * [victorhck](https://github.com/victorhck) | ||||
* [ashleyhull-versent](https://github.com/ashleyhull-versent) | |||||
* [kedamaDQ](https://github.com/kedamaDQ) | |||||
* [puckipedia](https://github.com/puckipedia) | * [puckipedia](https://github.com/puckipedia) | ||||
* [fvh-P](https://github.com/fvh-P) | |||||
* [contraexemplo](https://github.com/contraexemplo) | * [contraexemplo](https://github.com/contraexemplo) | ||||
* [kazu9su](https://github.com/kazu9su) | * [kazu9su](https://github.com/kazu9su) | ||||
* [Komic](https://github.com/Komic) | * [Komic](https://github.com/Komic) | ||||
* [lmorchard](https://github.com/lmorchard) | |||||
* [diomed](https://github.com/diomed) | * [diomed](https://github.com/diomed) | ||||
* [ariasuni](https://github.com/ariasuni) | |||||
* [Neetshin](mailto:neetshin@neetsh.in) | |||||
* [rainyday](https://github.com/rainyday) | * [rainyday](https://github.com/rainyday) | ||||
* [ProgVal](https://github.com/ProgVal) | |||||
* [valentin2105](https://github.com/valentin2105) | |||||
* [yuntan](https://github.com/yuntan) | |||||
* [goofy-bz](mailto:goofy@babelzilla.org) | |||||
* [kadiix](https://github.com/kadiix) | * [kadiix](https://github.com/kadiix) | ||||
* [kodacs](https://github.com/kodacs) | * [kodacs](https://github.com/kodacs) | ||||
* [ProgVal](https://github.com/ProgVal) | |||||
* [rtucker](https://github.com/rtucker) | |||||
* [KScl](https://github.com/KScl) | |||||
* [sterdev](https://github.com/sterdev) | * [sterdev](https://github.com/sterdev) | ||||
* [TheKinrar](https://github.com/TheKinrar) | * [TheKinrar](https://github.com/TheKinrar) | ||||
* [AA4ch1](https://github.com/AA4ch1) | * [AA4ch1](https://github.com/AA4ch1) | ||||
* [alexgleason](https://github.com/alexgleason) | * [alexgleason](https://github.com/alexgleason) | ||||
* [cpytel](https://github.com/cpytel) | * [cpytel](https://github.com/cpytel) | ||||
* [northerner](https://github.com/northerner) | * [northerner](https://github.com/northerner) | ||||
* [hnrysmth](https://github.com/hnrysmth) | |||||
* [hugogameiro](https://github.com/hugogameiro) | |||||
* [fhemberger](https://github.com/fhemberger) | |||||
* [greysteil](https://github.com/greysteil) | |||||
* [hensmith](https://github.com/hensmith) | |||||
* [hinaloe](https://github.com/hinaloe) | |||||
* [d6rkaiz](https://github.com/d6rkaiz) | |||||
* [Reverite](https://github.com/Reverite) | |||||
* [JMendyk](https://github.com/JMendyk) | |||||
* [JohnD28](https://github.com/JohnD28) | * [JohnD28](https://github.com/JohnD28) | ||||
* [znz](https://github.com/znz) | * [znz](https://github.com/znz) | ||||
* [Naouak](https://github.com/Naouak) | * [Naouak](https://github.com/Naouak) | ||||
* [rtucker](https://github.com/rtucker) | |||||
* [pawelngei](https://github.com/pawelngei) | |||||
* [reneklacan](https://github.com/reneklacan) | * [reneklacan](https://github.com/reneklacan) | ||||
* [KScl](https://github.com/KScl) | |||||
* [SerCom-KC](https://github.com/SerCom-KC) | |||||
* [ekiru](https://github.com/ekiru) | |||||
* [tcitworld](https://github.com/tcitworld) | * [tcitworld](https://github.com/tcitworld) | ||||
* [geta6](https://github.com/geta6) | * [geta6](https://github.com/geta6) | ||||
* [goofy-bz](https://github.com/goofy-bz) | |||||
* [happycoloredbanana](https://github.com/happycoloredbanana) | * [happycoloredbanana](https://github.com/happycoloredbanana) | ||||
* [leopku](https://github.com/leopku) | * [leopku](https://github.com/leopku) | ||||
* [SansPseudoFix](https://github.com/SansPseudoFix) | * [SansPseudoFix](https://github.com/SansPseudoFix) | ||||
* [tomfhowe](https://github.com/tomfhowe) | * [tomfhowe](https://github.com/tomfhowe) | ||||
* [noraworld](https://github.com/noraworld) | * [noraworld](https://github.com/noraworld) | ||||
* [fvh-P](https://github.com/fvh-P) | |||||
* [theboss](https://github.com/theboss) | |||||
* [178inaba](https://github.com/178inaba) | * [178inaba](https://github.com/178inaba) | ||||
* [devkral](https://github.com/devkral) | |||||
* [Aditoo17](https://github.com/Aditoo17) | |||||
* [alyssais](https://github.com/alyssais) | * [alyssais](https://github.com/alyssais) | ||||
* [kodnaplakal](https://github.com/kodnaplakal) | * [kodnaplakal](https://github.com/kodnaplakal) | ||||
* [stalker314314](https://github.com/stalker314314) | * [stalker314314](https://github.com/stalker314314) | ||||
* [huertanix](https://github.com/huertanix) | * [huertanix](https://github.com/huertanix) | ||||
* [genesixx](https://github.com/genesixx) | * [genesixx](https://github.com/genesixx) | ||||
* [fhemberger](https://github.com/fhemberger) | |||||
* [halkeye](https://github.com/halkeye) | * [halkeye](https://github.com/halkeye) | ||||
* [treby](https://github.com/treby) | * [treby](https://github.com/treby) | ||||
* [d6rkaiz](https://github.com/d6rkaiz) | |||||
* [jpdevries](https://github.com/jpdevries) | * [jpdevries](https://github.com/jpdevries) | ||||
* [rndm-stranger](https://github.com/rndm-stranger) | |||||
* [gdpelican](https://github.com/gdpelican) | |||||
* [kmichl](https://github.com/kmichl) | |||||
* [Kurtis Rainbolt-Greene](mailto:me@kurtisrainboltgreene.name) | |||||
* [saper](https://github.com/saper) | * [saper](https://github.com/saper) | ||||
* [nevillepark](https://github.com/nevillepark) | * [nevillepark](https://github.com/nevillepark) | ||||
* [ornithocoder](https://github.com/ornithocoder) | * [ornithocoder](https://github.com/ornithocoder) | ||||
* [pierreozoux](https://github.com/pierreozoux) | * [pierreozoux](https://github.com/pierreozoux) | ||||
* [ramlmn](https://github.com/ramlmn) | |||||
* [qguv](https://github.com/qguv) | |||||
* [Ram Lmn](mailto:ramlmn@users.noreply.github.com) | |||||
* [harukasan](https://github.com/harukasan) | * [harukasan](https://github.com/harukasan) | ||||
* [stamak](https://github.com/stamak) | * [stamak](https://github.com/stamak) | ||||
* [noellabo](https://github.com/noellabo) | |||||
* [Technowix](mailto:technowix@users.noreply.github.com) | |||||
* [Eychics](https://github.com/Eychics) | * [Eychics](https://github.com/Eychics) | ||||
* [thor-the-norseman](https://github.com/thor-the-norseman) | |||||
* [Thor Harald Johansen](mailto:thj@thj.no) | |||||
* [0x70b1a5](https://github.com/0x70b1a5) | * [0x70b1a5](https://github.com/0x70b1a5) | ||||
* [gled-rs](https://github.com/gled-rs) | * [gled-rs](https://github.com/gled-rs) | ||||
* [Valentin_NC](mailto:valentin.ouvrard@nautile.sarl) | |||||
* [R0ckweb](https://github.com/R0ckweb) | * [R0ckweb](https://github.com/R0ckweb) | ||||
* [caasi](https://github.com/caasi) | |||||
* [chr-1x](https://github.com/chr-1x) | |||||
* [esetomo](https://github.com/esetomo) | * [esetomo](https://github.com/esetomo) | ||||
* [foxiehkins](https://github.com/foxiehkins) | * [foxiehkins](https://github.com/foxiehkins) | ||||
* [sdukhovni](https://github.com/sdukhovni) | |||||
* [hoodie](mailto:hoodiekitten@outlook.com) | |||||
* [luzi82](https://github.com/luzi82) | |||||
* [duxovni](https://github.com/duxovni) | |||||
* [trwnh](https://github.com/trwnh) | |||||
* [unsmell](https://github.com/unsmell) | * [unsmell](https://github.com/unsmell) | ||||
* [valerauko](https://github.com/valerauko) | |||||
* [chriswmartin](https://github.com/chriswmartin) | * [chriswmartin](https://github.com/chriswmartin) | ||||
* [vahnj](https://github.com/vahnj) | * [vahnj](https://github.com/vahnj) | ||||
* [ikuradon](https://github.com/ikuradon) | * [ikuradon](https://github.com/ikuradon) | ||||
* [AndreLewin](https://github.com/AndreLewin) | * [AndreLewin](https://github.com/AndreLewin) | ||||
* [rinsuki](https://github.com/rinsuki) | |||||
* [0xflotus](https://github.com/0xflotus) | |||||
* [redtachyons](https://github.com/redtachyons) | * [redtachyons](https://github.com/redtachyons) | ||||
* [thurloat](https://github.com/thurloat) | * [thurloat](https://github.com/thurloat) | ||||
* [aaribaud](https://github.com/aaribaud) | * [aaribaud](https://github.com/aaribaud) | ||||
* [Andrew](mailto:andrewlchronister@gmail.com) | |||||
* [estuans](https://github.com/estuans) | * [estuans](https://github.com/estuans) | ||||
* [BenLubar](https://github.com/BenLubar) | |||||
* [dissolve](https://github.com/dissolve) | * [dissolve](https://github.com/dissolve) | ||||
* [PurpleBooth](https://github.com/PurpleBooth) | * [PurpleBooth](https://github.com/PurpleBooth) | ||||
* [bradurani](https://github.com/bradurani) | * [bradurani](https://github.com/bradurani) | ||||
@@ -164,37 +205,50 @@ and provided thanks to the work of the following contributors: | |||||
* [cdutson](https://github.com/cdutson) | * [cdutson](https://github.com/cdutson) | ||||
* [farlistener](https://github.com/farlistener) | * [farlistener](https://github.com/farlistener) | ||||
* [DavidLibeau](https://github.com/DavidLibeau) | * [DavidLibeau](https://github.com/DavidLibeau) | ||||
* [SirCmpwn](https://github.com/SirCmpwn) | |||||
* [MasterGroosha](https://github.com/MasterGroosha) | |||||
* [ddevault](https://github.com/ddevault) | |||||
* [Fjoerfoks](https://github.com/Fjoerfoks) | * [Fjoerfoks](https://github.com/Fjoerfoks) | ||||
* [fmauNeko](https://github.com/fmauNeko) | * [fmauNeko](https://github.com/fmauNeko) | ||||
* [gloaec](https://github.com/gloaec) | * [gloaec](https://github.com/gloaec) | ||||
* [greysteil](https://github.com/greysteil) | |||||
* [Gomasy](https://github.com/Gomasy) | |||||
* [unstabler](https://github.com/unstabler) | * [unstabler](https://github.com/unstabler) | ||||
* [potato4d](https://github.com/potato4d) | * [potato4d](https://github.com/potato4d) | ||||
* [h-izumi](https://github.com/h-izumi) | * [h-izumi](https://github.com/h-izumi) | ||||
* [ErikXXon](https://github.com/ErikXXon) | * [ErikXXon](https://github.com/ErikXXon) | ||||
* [ian-kelling](https://github.com/ian-kelling) | * [ian-kelling](https://github.com/ian-kelling) | ||||
* [immae](https://github.com/immae) | |||||
* [foozmeat](https://github.com/foozmeat) | * [foozmeat](https://github.com/foozmeat) | ||||
* [jasonrhodes](https://github.com/jasonrhodes) | * [jasonrhodes](https://github.com/jasonrhodes) | ||||
* [asm](https://github.com/asm) | |||||
* [Jason Snell](mailto:jason@newrelic.com) | |||||
* [jviide](https://github.com/jviide) | * [jviide](https://github.com/jviide) | ||||
* [YuleZ](https://github.com/YuleZ) | |||||
* [crakaC](https://github.com/crakaC) | * [crakaC](https://github.com/crakaC) | ||||
* [tkbky](https://github.com/tkbky) | * [tkbky](https://github.com/tkbky) | ||||
* [Kaylee](mailto:kaylee@codethat.sucks) | |||||
* [Kazhnuz](https://github.com/Kazhnuz) | * [Kazhnuz](https://github.com/Kazhnuz) | ||||
* [connyduck](https://github.com/connyduck) | |||||
* [Lindsey Bieda](mailto:lindseyb@users.noreply.github.com) | |||||
* [Lorenz Diener](mailto:halcyon@icosahedron.website) | |||||
* [alimony](https://github.com/alimony) | * [alimony](https://github.com/alimony) | ||||
* [mig5](https://github.com/mig5) | * [mig5](https://github.com/mig5) | ||||
* [ndarville](https://github.com/ndarville) | * [ndarville](https://github.com/ndarville) | ||||
* [Abzol](https://github.com/Abzol) | * [Abzol](https://github.com/Abzol) | ||||
* [pwoolcoc](https://github.com/pwoolcoc) | |||||
* [xPaw](https://github.com/xPaw) | * [xPaw](https://github.com/xPaw) | ||||
* [petzah](https://github.com/petzah) | |||||
* [ignisf](https://github.com/ignisf) | |||||
* [raymestalez](https://github.com/raymestalez) | * [raymestalez](https://github.com/raymestalez) | ||||
* [remram44](https://github.com/remram44) | |||||
* [sascha-sl](https://github.com/sascha-sl) | |||||
* [u1-liquid](https://github.com/u1-liquid) | |||||
* [sim6](https://github.com/sim6) | * [sim6](https://github.com/sim6) | ||||
* [ekiru](https://github.com/ekiru) | |||||
* [Technowix](https://github.com/Technowix) | |||||
* [stemid](https://github.com/stemid) | |||||
* [sumdog](https://github.com/sumdog) | |||||
* [ThomasLeister](https://github.com/ThomasLeister) | * [ThomasLeister](https://github.com/ThomasLeister) | ||||
* [mcat-ee](https://github.com/mcat-ee) | * [mcat-ee](https://github.com/mcat-ee) | ||||
* [tototoshi](https://github.com/tototoshi) | * [tototoshi](https://github.com/tototoshi) | ||||
* [TrashMacNugget](https://github.com/TrashMacNugget) | |||||
* [VirtuBox](https://github.com/VirtuBox) | * [VirtuBox](https://github.com/VirtuBox) | ||||
* [Vladyslav](mailto:vaden@tuta.io) | |||||
* [kaniini](https://github.com/kaniini) | * [kaniini](https://github.com/kaniini) | ||||
* [vayan](https://github.com/vayan) | * [vayan](https://github.com/vayan) | ||||
* [yannicka](https://github.com/yannicka) | * [yannicka](https://github.com/yannicka) | ||||
@@ -202,45 +256,61 @@ and provided thanks to the work of the following contributors: | |||||
* [zacanger](https://github.com/zacanger) | * [zacanger](https://github.com/zacanger) | ||||
* [amazedkoumei](https://github.com/amazedkoumei) | * [amazedkoumei](https://github.com/amazedkoumei) | ||||
* [anon5r](https://github.com/anon5r) | * [anon5r](https://github.com/anon5r) | ||||
* [aus-social](https://github.com/aus-social) | |||||
* [imbsky](https://github.com/imbsky) | |||||
* [bsky](mailto:me@imbsky.net) | |||||
* [codl](https://github.com/codl) | * [codl](https://github.com/codl) | ||||
* [cpsdqs](https://github.com/cpsdqs) | |||||
* [barzamin](https://github.com/barzamin) | * [barzamin](https://github.com/barzamin) | ||||
* [fhalna](https://github.com/fhalna) | * [fhalna](https://github.com/fhalna) | ||||
* [haoyayoi](https://github.com/haoyayoi) | * [haoyayoi](https://github.com/haoyayoi) | ||||
* [ik11235](https://github.com/ik11235) | * [ik11235](https://github.com/ik11235) | ||||
* [kawax](https://github.com/kawax) | * [kawax](https://github.com/kawax) | ||||
* [007lva](https://github.com/007lva) | * [007lva](https://github.com/007lva) | ||||
* [mbajur](https://github.com/mbajur) | |||||
* [matsurai25](https://github.com/matsurai25) | * [matsurai25](https://github.com/matsurai25) | ||||
* [mecab](https://github.com/mecab) | * [mecab](https://github.com/mecab) | ||||
* [nicobz25](https://github.com/nicobz25) | * [nicobz25](https://github.com/nicobz25) | ||||
* [oliverkeeble](https://github.com/oliverkeeble) | * [oliverkeeble](https://github.com/oliverkeeble) | ||||
* [pinfort](https://github.com/pinfort) | * [pinfort](https://github.com/pinfort) | ||||
* [rbaumert](https://github.com/rbaumert) | * [rbaumert](https://github.com/rbaumert) | ||||
* [rhoio](https://github.com/rhoio) | |||||
* [usagi-f](https://github.com/usagi-f) | * [usagi-f](https://github.com/usagi-f) | ||||
* [vidarlee](https://github.com/vidarlee) | * [vidarlee](https://github.com/vidarlee) | ||||
* [vjackson725](https://github.com/vjackson725) | * [vjackson725](https://github.com/vjackson725) | ||||
* [wxcafe](https://github.com/wxcafe) | * [wxcafe](https://github.com/wxcafe) | ||||
* [rinsuki](https://github.com/rinsuki) | |||||
* [新都心(Neet Shin)](mailto:nucx@dio-vox.com) | |||||
* [cygnan](https://github.com/cygnan) | * [cygnan](https://github.com/cygnan) | ||||
* [Awea](https://github.com/Awea) | * [Awea](https://github.com/Awea) | ||||
* [halcy](https://github.com/halcy) | * [halcy](https://github.com/halcy) | ||||
* [bounshi](https://github.com/bounshi) | |||||
* [naaaaaaaaaaaf](https://github.com/naaaaaaaaaaaf) | |||||
* [8398a7](https://github.com/8398a7) | * [8398a7](https://github.com/8398a7) | ||||
* [857b](https://github.com/857b) | * [857b](https://github.com/857b) | ||||
* [insom](https://github.com/insom) | |||||
* [tachyons](https://github.com/tachyons) | |||||
* [Esteth](https://github.com/Esteth) | |||||
* [unascribed](https://github.com/unascribed) | * [unascribed](https://github.com/unascribed) | ||||
* [Aguay-val](https://github.com/Aguay-val) | * [Aguay-val](https://github.com/Aguay-val) | ||||
* [Akihiko Odaki](mailto:nekomanma@pixiv.co.jp) | |||||
* [knu](https://github.com/knu) | * [knu](https://github.com/knu) | ||||
* [h3poteto](https://github.com/h3poteto) | |||||
* [unleashed](https://github.com/unleashed) | |||||
* [alxrcs](https://github.com/alxrcs) | * [alxrcs](https://github.com/alxrcs) | ||||
* [console-cowboy](https://github.com/console-cowboy) | * [console-cowboy](https://github.com/console-cowboy) | ||||
* [pointlessone](https://github.com/pointlessone) | * [pointlessone](https://github.com/pointlessone) | ||||
* [Alkarex](https://github.com/Alkarex) | |||||
* [a2](https://github.com/a2) | * [a2](https://github.com/a2) | ||||
* [0xa](https://github.com/0xa) | * [0xa](https://github.com/0xa) | ||||
* [palindromordnilap](https://github.com/palindromordnilap) | |||||
* [virtualpain](https://github.com/virtualpain) | * [virtualpain](https://github.com/virtualpain) | ||||
* [sapphirus](https://github.com/sapphirus) | * [sapphirus](https://github.com/sapphirus) | ||||
* [amandavisconti](https://github.com/amandavisconti) | * [amandavisconti](https://github.com/amandavisconti) | ||||
* [ameliavoncat](https://github.com/ameliavoncat) | * [ameliavoncat](https://github.com/ameliavoncat) | ||||
* [ilpianista](https://github.com/ilpianista) | * [ilpianista](https://github.com/ilpianista) | ||||
* [andydrop](https://github.com/andydrop) | |||||
* [Andreas Drop](mailto:andy@remline.de) | |||||
* [andi1984](https://github.com/andi1984) | |||||
* [schas002](https://github.com/schas002) | * [schas002](https://github.com/schas002) | ||||
* [abackstrom](https://github.com/abackstrom) | |||||
* [jumbosushi](https://github.com/jumbosushi) | * [jumbosushi](https://github.com/jumbosushi) | ||||
* [ayumin](https://github.com/ayumin) | * [ayumin](https://github.com/ayumin) | ||||
* [BaptisteGelez](https://github.com/BaptisteGelez) | * [BaptisteGelez](https://github.com/BaptisteGelez) | ||||
@@ -251,6 +321,7 @@ and provided thanks to the work of the following contributors: | |||||
* [brycied00d](https://github.com/brycied00d) | * [brycied00d](https://github.com/brycied00d) | ||||
* [carlosjs23](https://github.com/carlosjs23) | * [carlosjs23](https://github.com/carlosjs23) | ||||
* [cgxxx](https://github.com/cgxxx) | * [cgxxx](https://github.com/cgxxx) | ||||
* [kibitan](https://github.com/kibitan) | |||||
* [chrisheninger](https://github.com/chrisheninger) | * [chrisheninger](https://github.com/chrisheninger) | ||||
* [chris-martin](https://github.com/chris-martin) | * [chris-martin](https://github.com/chris-martin) | ||||
* [DoubleMalt](https://github.com/DoubleMalt) | * [DoubleMalt](https://github.com/DoubleMalt) | ||||
@@ -259,22 +330,34 @@ and provided thanks to the work of the following contributors: | |||||
* [chriswk](https://github.com/chriswk) | * [chriswk](https://github.com/chriswk) | ||||
* [csu](https://github.com/csu) | * [csu](https://github.com/csu) | ||||
* [kklleemm](https://github.com/kklleemm) | * [kklleemm](https://github.com/kklleemm) | ||||
* [monsterpit-daggertooth](https://github.com/monsterpit-daggertooth) | |||||
* [colindean](https://github.com/colindean) | |||||
* [dachinat](https://github.com/dachinat) | |||||
* [multiple-creatures](https://github.com/multiple-creatures) | |||||
* [watilde](https://github.com/watilde) | * [watilde](https://github.com/watilde) | ||||
* [daprice](https://github.com/daprice) | * [daprice](https://github.com/daprice) | ||||
* [dar5hak](https://github.com/dar5hak) | * [dar5hak](https://github.com/dar5hak) | ||||
* [kant](https://github.com/kant) | * [kant](https://github.com/kant) | ||||
* [maxolasersquad](https://github.com/maxolasersquad) | |||||
* [singingwolfboy](https://github.com/singingwolfboy) | * [singingwolfboy](https://github.com/singingwolfboy) | ||||
* [davidcelis](https://github.com/davidcelis) | * [davidcelis](https://github.com/davidcelis) | ||||
* [davefp](https://github.com/davefp) | |||||
* [yipdw](https://github.com/yipdw) | * [yipdw](https://github.com/yipdw) | ||||
* [debanshuk](https://github.com/debanshuk) | * [debanshuk](https://github.com/debanshuk) | ||||
* [Derek Lewis](mailto:derekcecillewis@gmail.com) | |||||
* [dblandin](https://github.com/dblandin) | * [dblandin](https://github.com/dblandin) | ||||
* [aranaur](https://github.com/aranaur) | |||||
* [Drew Gates](mailto:aranaur@users.noreply.github.com) | |||||
* [dtschust](https://github.com/dtschust) | |||||
* [Dryusdan](https://github.com/Dryusdan) | |||||
* [eai04191](https://github.com/eai04191) | |||||
* [d3vgru](https://github.com/d3vgru) | * [d3vgru](https://github.com/d3vgru) | ||||
* [Elizafox](https://github.com/Elizafox) | * [Elizafox](https://github.com/Elizafox) | ||||
* [ericblade](https://github.com/ericblade) | * [ericblade](https://github.com/ericblade) | ||||
* [mikoim](https://github.com/mikoim) | * [mikoim](https://github.com/mikoim) | ||||
* [espenronnevik](https://github.com/espenronnevik) | |||||
* [Finariel](https://github.com/Finariel) | |||||
* [siuying](https://github.com/siuying) | * [siuying](https://github.com/siuying) | ||||
* [fwenzel](https://github.com/fwenzel) | |||||
* [GenbuHase](https://github.com/GenbuHase) | |||||
* [hattori6789](https://github.com/hattori6789) | * [hattori6789](https://github.com/hattori6789) | ||||
* [algernon](https://github.com/algernon) | * [algernon](https://github.com/algernon) | ||||
* [Fastbyte01](https://github.com/Fastbyte01) | * [Fastbyte01](https://github.com/Fastbyte01) | ||||
@@ -283,22 +366,25 @@ and provided thanks to the work of the following contributors: | |||||
* [Fiaxhs](https://github.com/Fiaxhs) | * [Fiaxhs](https://github.com/Fiaxhs) | ||||
* [reedcourty](https://github.com/reedcourty) | * [reedcourty](https://github.com/reedcourty) | ||||
* [anneau](https://github.com/anneau) | * [anneau](https://github.com/anneau) | ||||
* [lanodan](https://github.com/lanodan) | |||||
* [Harmon758](https://github.com/Harmon758) | |||||
* [HellPie](https://github.com/HellPie) | * [HellPie](https://github.com/HellPie) | ||||
* [Habu-Kagumba](https://github.com/Habu-Kagumba) | * [Habu-Kagumba](https://github.com/Habu-Kagumba) | ||||
* [hinaloe](https://github.com/hinaloe) | |||||
* [suzukaze](https://github.com/suzukaze) | * [suzukaze](https://github.com/suzukaze) | ||||
* [Hiromi-Kai](https://github.com/Hiromi-Kai) | * [Hiromi-Kai](https://github.com/Hiromi-Kai) | ||||
* [hishamhm](https://github.com/hishamhm) | |||||
* [musashino205](https://github.com/musashino205) | * [musashino205](https://github.com/musashino205) | ||||
* [iwaim](https://github.com/iwaim) | * [iwaim](https://github.com/iwaim) | ||||
* [valrus](https://github.com/valrus) | * [valrus](https://github.com/valrus) | ||||
* [IMcD23](https://github.com/IMcD23) | * [IMcD23](https://github.com/IMcD23) | ||||
* [yi0713](https://github.com/yi0713) | * [yi0713](https://github.com/yi0713) | ||||
* [immae](https://github.com/immae) | |||||
* [iblech](https://github.com/iblech) | * [iblech](https://github.com/iblech) | ||||
* [usbsnowcrash](https://github.com/usbsnowcrash) | |||||
* [jack-michaud](https://github.com/jack-michaud) | * [jack-michaud](https://github.com/jack-michaud) | ||||
* [Floppy](https://github.com/Floppy) | * [Floppy](https://github.com/Floppy) | ||||
* [loomchild](https://github.com/loomchild) | * [loomchild](https://github.com/loomchild) | ||||
* [docjkl](https://github.com/docjkl) | |||||
* [jenkr55](https://github.com/jenkr55) | |||||
* [press5](https://github.com/press5) | |||||
* [TrollDecker](https://github.com/TrollDecker) | * [TrollDecker](https://github.com/TrollDecker) | ||||
* [jmontane](https://github.com/jmontane) | * [jmontane](https://github.com/jmontane) | ||||
* [jonathanklee](https://github.com/jonathanklee) | * [jonathanklee](https://github.com/jonathanklee) | ||||
@@ -307,28 +393,33 @@ and provided thanks to the work of the following contributors: | |||||
* [joshuap](https://github.com/joshuap) | * [joshuap](https://github.com/joshuap) | ||||
* [Tiwy57](https://github.com/Tiwy57) | * [Tiwy57](https://github.com/Tiwy57) | ||||
* [xuv](https://github.com/xuv) | * [xuv](https://github.com/xuv) | ||||
* [Jnsll](https://github.com/Jnsll) | |||||
* [June Sallou](mailto:jnsll@users.noreply.github.com) | |||||
* [j0k3r](https://github.com/j0k3r) | * [j0k3r](https://github.com/j0k3r) | ||||
* [KEINOS](https://github.com/KEINOS) | * [KEINOS](https://github.com/KEINOS) | ||||
* [futoase](https://github.com/futoase) | * [futoase](https://github.com/futoase) | ||||
* [abjectio](https://github.com/abjectio) | |||||
* [Pneumaticat](https://github.com/Pneumaticat) | |||||
* [Kit Redgrave](mailto:qwertyitis@gmail.com) | |||||
* [Knut Erik](mailto:abjectio@users.noreply.github.com) | |||||
* [mkody](https://github.com/mkody) | * [mkody](https://github.com/mkody) | ||||
* [connyduck](https://github.com/connyduck) | |||||
* [k0ta0uchi](https://github.com/k0ta0uchi) | * [k0ta0uchi](https://github.com/k0ta0uchi) | ||||
* [KrzysiekJ](https://github.com/KrzysiekJ) | * [KrzysiekJ](https://github.com/KrzysiekJ) | ||||
* [leowzukw](https://github.com/leowzukw) | * [leowzukw](https://github.com/leowzukw) | ||||
* [lmorchard](https://github.com/lmorchard) | |||||
* [Tak](https://github.com/Tak) | |||||
* [cacheflow](https://github.com/cacheflow) | * [cacheflow](https://github.com/cacheflow) | ||||
* [ldidry](https://github.com/ldidry) | * [ldidry](https://github.com/ldidry) | ||||
* [jemus42](https://github.com/jemus42) | * [jemus42](https://github.com/jemus42) | ||||
* [lfuelling](https://github.com/lfuelling) | * [lfuelling](https://github.com/lfuelling) | ||||
* [Grabacr07](https://github.com/Grabacr07) | * [Grabacr07](https://github.com/Grabacr07) | ||||
* [mistermantas](https://github.com/mistermantas) | * [mistermantas](https://github.com/mistermantas) | ||||
* [mareklach](https://github.com/mareklach) | |||||
* [wirehack7](https://github.com/wirehack7) | * [wirehack7](https://github.com/wirehack7) | ||||
* [martymcguire](https://github.com/martymcguire) | |||||
* [marvinkopf](https://github.com/marvinkopf) | * [marvinkopf](https://github.com/marvinkopf) | ||||
* [otsune](https://github.com/otsune) | * [otsune](https://github.com/otsune) | ||||
* [m-blc](https://github.com/m-blc) | |||||
* [Mathias B](mailto:10813340+mathias-b@users.noreply.github.com) | |||||
* [matt-auckland](https://github.com/matt-auckland) | * [matt-auckland](https://github.com/matt-auckland) | ||||
* [webroo](https://github.com/webroo) | |||||
* [matthiasbeyer](https://github.com/matthiasbeyer) | |||||
* [mattjmattj](https://github.com/mattjmattj) | * [mattjmattj](https://github.com/mattjmattj) | ||||
* [mtparet](https://github.com/mtparet) | * [mtparet](https://github.com/mtparet) | ||||
* [maximeborges](https://github.com/maximeborges) | * [maximeborges](https://github.com/maximeborges) | ||||
@@ -336,16 +427,21 @@ and provided thanks to the work of the following contributors: | |||||
* [michaeljdeeb](https://github.com/michaeljdeeb) | * [michaeljdeeb](https://github.com/michaeljdeeb) | ||||
* [Themimitoof](https://github.com/Themimitoof) | * [Themimitoof](https://github.com/Themimitoof) | ||||
* [cyweo](https://github.com/cyweo) | * [cyweo](https://github.com/cyweo) | ||||
* [M1dgard](https://github.com/M1dgard) | |||||
* [Midgard](mailto:m1dgard@users.noreply.github.com) | |||||
* [mike-burns](https://github.com/mike-burns) | * [mike-burns](https://github.com/mike-burns) | ||||
* [verymilan](https://github.com/verymilan) | * [verymilan](https://github.com/verymilan) | ||||
* [milmazz](https://github.com/milmazz) | * [milmazz](https://github.com/milmazz) | ||||
* [premist](https://github.com/premist) | |||||
* [Mnkai](https://github.com/Mnkai) | * [Mnkai](https://github.com/Mnkai) | ||||
* [mitchhentges](https://github.com/mitchhentges) | * [mitchhentges](https://github.com/mitchhentges) | ||||
* [moritzheiber](https://github.com/moritzheiber) | * [moritzheiber](https://github.com/moritzheiber) | ||||
* [mouse-reeve](https://github.com/mouse-reeve) | * [mouse-reeve](https://github.com/mouse-reeve) | ||||
* [Mozinet-fr](https://github.com/Mozinet-fr) | |||||
* [lae](https://github.com/lae) | * [lae](https://github.com/lae) | ||||
* [Nanamachi](https://github.com/Nanamachi) | * [Nanamachi](https://github.com/Nanamachi) | ||||
* [orinthe](https://github.com/orinthe) | |||||
* [NecroTechno](https://github.com/NecroTechno) | |||||
* [Dar13](https://github.com/Dar13) | |||||
* [ngerakines](https://github.com/ngerakines) | * [ngerakines](https://github.com/ngerakines) | ||||
* [vonneudeck](https://github.com/vonneudeck) | * [vonneudeck](https://github.com/vonneudeck) | ||||
* [Ninetailed](https://github.com/Ninetailed) | * [Ninetailed](https://github.com/Ninetailed) | ||||
@@ -355,96 +451,381 @@ and provided thanks to the work of the following contributors: | |||||
* [norayr](https://github.com/norayr) | * [norayr](https://github.com/norayr) | ||||
* [joyeusenoelle](https://github.com/joyeusenoelle) | * [joyeusenoelle](https://github.com/joyeusenoelle) | ||||
* [OlivierNicole](https://github.com/OlivierNicole) | * [OlivierNicole](https://github.com/OlivierNicole) | ||||
* [noppa](https://github.com/noppa) | |||||
* [Otakan951](https://github.com/Otakan951) | * [Otakan951](https://github.com/Otakan951) | ||||
* [fahy](https://github.com/fahy) | * [fahy](https://github.com/fahy) | ||||
* [PatrickRWells](https://github.com/PatrickRWells) | |||||
* [Pangoraw](https://github.com/Pangoraw) | * [Pangoraw](https://github.com/Pangoraw) | ||||
* [pwoolcoc](https://github.com/pwoolcoc) | |||||
* [peterkeen](https://github.com/peterkeen) | * [peterkeen](https://github.com/peterkeen) | ||||
* [petzah](https://github.com/petzah) | |||||
* [ignisf](https://github.com/ignisf) | |||||
* [pgate](https://github.com/pgate) | |||||
* [retokromer](https://github.com/retokromer) | |||||
* [rfwatson](https://github.com/rfwatson) | * [rfwatson](https://github.com/rfwatson) | ||||
* [rfreebern](https://github.com/rfreebern) | * [rfreebern](https://github.com/rfreebern) | ||||
* [Ryan Wade](mailto:ryan.wade@protonmail.com) | |||||
* [sylph01](https://github.com/sylph01) | * [sylph01](https://github.com/sylph01) | ||||
* [S-H-GAMELINKS](https://github.com/S-H-GAMELINKS) | |||||
* [staticsafe](https://github.com/staticsafe) | * [staticsafe](https://github.com/staticsafe) | ||||
* [snwh](https://github.com/snwh) | * [snwh](https://github.com/snwh) | ||||
* [sts10](https://github.com/sts10) | |||||
* [skoji](https://github.com/skoji) | * [skoji](https://github.com/skoji) | ||||
* [ScienJus](https://github.com/ScienJus) | * [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) | |||||
* [Scott Larkin](mailto:scott@codeclimate.com) | |||||
* [Sebastian Hübner](mailto:imolein@users.noreply.github.com) | |||||
* [Sebastian Morr](mailto:sebastian@morr.cc) | |||||
* [Sergei Č](mailto:noiwex1911@gmail.com) | |||||
* [Setuu](mailto:yuki764setuu@gmail.com) | |||||
* [Shaun Gillies](mailto:me@shaungillies.net) | |||||
* [Shin Adachi](mailto:shn@glucose.jp) | |||||
* [Shin Kojima](mailto:shin@kojima.org) | |||||
* [Sho Kusano](mailto:rosylilly@aduca.org) | |||||
* [Shouko Yu](mailto:imshouko@gmail.com) | |||||
* [Sina Mashek](mailto:sina@mashek.xyz) | |||||
* [Sir-Boops](mailto:admin@boops.me) | |||||
* [Soshi Kato](mailto:mail@sossii.com) | |||||
* [Spanky](mailto:2788886+spankyworks@users.noreply.github.com) | |||||
* [StefOfficiel](mailto:pichard.stephane@free.fr) | |||||
* [Steven Tappert](mailto:admin@dark-it.net) | |||||
* [Svetlozar Todorov](mailto:svetlik@users.noreply.github.com) | |||||
* [Sébastien Santoro](mailto:dereckson@espace-win.org) | |||||
* [Tad Thorley](mailto:phaedryx@users.noreply.github.com) | |||||
* [Takayoshi Nishida](mailto:takayoshi.nishida@gmail.com) | |||||
* [Takayuki KUSANO](mailto:github@tkusano.jp) | |||||
* [TakesxiSximada](mailto:takesxi.sximada@gmail.com) | |||||
* [TheInventrix](mailto:theinventrix@users.noreply.github.com) | |||||
* [Thomas Alberola](mailto:thomas@needacoffee.fr) | |||||
* [Toby Deshane](mailto:fortyseven@users.noreply.github.com) | |||||
* [Toby Pinder](mailto:gigitrix@gmail.com) | |||||
* [Tomonori Murakami](mailto:crosslife777@gmail.com) | |||||
* [TomoyaShibata](mailto:wind.of.hometown@gmail.com) | |||||
* [Treyssat-Vincent Nino](mailto:treyssatvincent@users.noreply.github.com) | |||||
* [Udo Kramer](mailto:optik@fluffel.io) | |||||
* [Una](mailto:una@unascribed.com) | |||||
* [Ushitora Anqou](mailto:ushitora_anqou@yahoo.co.jp) | |||||
* [Valentin Lorentz](mailto:progval+git@progval.net) | |||||
* [Vladimir Mincev](mailto:vladimir@canicinteractive.com) | |||||
* [Waldir Pimenta](mailto:waldyrious@gmail.com) | |||||
* [Wesley Ellis](mailto:tahnok@gmail.com) | |||||
* [Wiktor](mailto:wiktor@metacode.biz) | |||||
* [Wonderfall](mailto:wonderfall@schrodinger.io) | |||||
* [YDrogen](mailto:ydrogen45@gmail.com) | |||||
* [YMHuang](mailto:ymhuang@fmbase.tw) | |||||
* [YOSHIOKA Eiichiro](mailto:yoshioka.eiichiro@gmail.com) | |||||
* [YOU](mailto:stackexchange.you@gmail.com) | |||||
* [YaQ](mailto:i_k_o_m_a_7@yahoo.co.jp) | |||||
* [Yanaken](mailto:yanakend@gmail.com) | |||||
* [Yann Klis](mailto:yann.klis@gmail.com) | |||||
* [Yeechan Lu](mailto:wz.bluesnow@gmail.com) | |||||
* [Yusuke Abe](mailto:moonset20@gmail.com) | |||||
* [Zachary Spector](mailto:logicaldash@gmail.com) | |||||
* [ZiiX](mailto:ziix@users.noreply.github.com) | |||||
* [asria-jp](mailto:is@alicematic.com) | |||||
* [ava](mailto:vladooku@users.noreply.github.com) | |||||
* [benklop](mailto:benklop@gmail.com) | |||||
* [bsky](mailto:git@imbsky.net) | |||||
* [caesarologia](mailto:lopesgemelli.1@gmail.com) | |||||
* [cbayerlein](mailto:c.bayerlein@gmail.com) | |||||
* [chrolis](mailto:chrolis@users.noreply.github.com) | |||||
* [cormo](mailto:cormorant2+github@gmail.com) | |||||
* [d0p1](mailto:dopi-sama@hush.com) | |||||
* [evilny0](mailto:evilny0@moomoocamp.net) | |||||
* [febrezo](mailto:felixbrezo@gmail.com) | |||||
* [fsubal](mailto:fsubal@users.noreply.github.com) | |||||
* [fusshi-](mailto:dikky1218@users.noreply.github.com) | |||||
* [gentaro](mailto:gentaroooo@gmail.com) | |||||
* [hakoai](mailto:hk--76@qa2.so-net.ne.jp) | |||||
* [haosbvnker](mailto:github@chaosbunker.com) | |||||
* [isati](mailto:phil@juchnowi.cz) | |||||
* [jacob](mailto:jacobherringtondeveloper@gmail.com) | |||||
* [jenn kaplan](mailto:me@jkap.io) | |||||
* [jirayudech](mailto:jirayudech@gmail.com) | |||||
* [jomo](mailto:github@jomo.tv) | |||||
* [jooops](mailto:joops@autistici.org) | |||||
* [jukper](mailto:jukkaperanto@gmail.com) | |||||
* [jumoru](mailto:jumoru@mailbox.org) | |||||
* [karlyeurl](mailto:karl.yeurl@gmail.com) | |||||
* [kedama](mailto:32974885+kedamadq@users.noreply.github.com) | |||||
* [kodai](mailto:shirafuta.kodai@gmail.com) | |||||
* [kuro5hin](mailto:rusty@kuro5hin.org) | |||||
* [luzpaz](mailto:luzpaz@users.noreply.github.com) | |||||
* [maxypy](mailto:maxime@mpigou.fr) | |||||
* [mhe](mailto:mail@marcus-herrmann.com) | |||||
* [mimikun](mailto:dzdzble_effort_311@outlook.jp) | |||||
* [mshrtkch](mailto:mshrtkch@users.noreply.github.com) | |||||
* [muan](mailto:muan@github.com) | |||||
* [namelessGonbai](mailto:43787036+namelessgonbai@users.noreply.github.com) | |||||
* [neetshin](mailto:neetshin@neetsh.in) | |||||
* [nightpool](mailto:nightpool@users.noreply.github.com) | |||||
* [rch850](mailto:rich850@gmail.com) | |||||
* [roikale](mailto:roikale@users.noreply.github.com) | |||||
* [rysiekpl](mailto:rysiek@hackerspace.pl) | |||||
* [saturday06](mailto:dyob@lunaport.net) | |||||
* [scriptjunkie](mailto:scriptjunkie@scriptjunkie.us) | |||||
* [seekr](mailto:mario.drs@gmail.com) | |||||
* [sundevour](mailto:31990469+sundevour@users.noreply.github.com) | |||||
* [syui](mailto:syui@users.noreply.github.com) | |||||
* [tackeyy](mailto:mailto.takita.yusuke@gmail.com) | |||||
* [tateisu](mailto:tateisu@gmail.com) | |||||
* [tmyt](mailto:shigure@refy.net) | |||||
* [trevDev()](mailto:trev@trevdev.ca) | |||||
* [utam0k](mailto:k0ma@utam0k.jp) | |||||
* [vpzomtrrfrt](mailto:vpzomtrrfrt@gmail.com) | |||||
* [walfie](mailto:walfington@gmail.com) | |||||
* [y-temp4](mailto:y.temp4@gmail.com) | |||||
* [ymmtmdk](mailto:ymmtmdk@gmail.com) | |||||
* [yoshipc](mailto:yoooo@yoshipc.net) | |||||
* [Özcan Zafer AYAN](mailto:ozcanzaferayan@gmail.com) | |||||
* [ばん](mailto:detteiu0321@gmail.com) | |||||
* [みたらしだんご](mailto:mitarashidango@users.noreply.github.com) | |||||
* [りんすき](mailto:6533808+rinsuki@users.noreply.github.com) | |||||
* [ヨイツの賢狼ホロ | 3rd style](mailto:horo@yoitsu.moe) | |||||
* [猫吸血鬼ディフリス / 猫ロキP](mailto:deflis@gmail.com) | |||||
* [艮 鮟鱇](mailto:ushitora_anqou@yahoo.co.jp) | |||||
* [西小倉宏信](mailto:nishiko@mindia.jp) | |||||
* [雨宮美羽](mailto:k737566@gmail.com) | |||||
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. | 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. | ||||
## Translators | |||||
Following people have contributed to translation of Mastodon: | |||||
- **Arabic** | |||||
- ButterflyOfFire | |||||
- **Asturian** | |||||
- ButterflyOfFire | |||||
- Enol P. | |||||
- **Basque** | |||||
- Aitzol | |||||
- ButterflyOfFire | |||||
- Gorka Azkarate | |||||
- Osoitz | |||||
- Peru Iparragirre | |||||
- **Bulgarian** | |||||
- ButterflyOfFire | |||||
- **Catalan** | |||||
- ButterflyOfFire | |||||
- Joan Montané | |||||
- Jose Luis | |||||
- spla | |||||
- **Chinese (Hong Kong)** | |||||
- ButterflyOfFire | |||||
- Luzi Leung | |||||
- **Chinese (Simplified)** | |||||
- Allen Zhong | |||||
- ButterflyOfFire | |||||
- SerCom_KC | |||||
- **Chinese (Traditional)** | |||||
- ButterflyOfFire | |||||
- James58899 | |||||
- Jeff Huang | |||||
- S1ttidoe477 | |||||
- SHA265 | |||||
- **Corsican** | |||||
- Alix D. R. | |||||
- ButterflyOfFire | |||||
- **Croatian** | |||||
- ButterflyOfFire | |||||
- **Czech** | |||||
- ButterflyOfFire | |||||
- Lorem Ipsum | |||||
- Marek Ľach | |||||
- **Danish** | |||||
- ButterflyOfFire | |||||
- Rasmus Sæderup | |||||
- **Dutch** | |||||
- ButterflyOfFire | |||||
- Jelv | |||||
- jeroenpraat | |||||
- rscmbbng | |||||
- **English** | |||||
- ButterflyOfFire | |||||
- Renato "Lond" Cerqueira | |||||
- **Esperanto** | |||||
- ButterflyOfFire | |||||
- Jeong Arm | |||||
- Martin Bodin | |||||
- Mélanie Chauvel | |||||
- Vanege | |||||
- tuxayo/Victor Grousset | |||||
- **Finnish** | |||||
- ButterflyOfFire | |||||
- Jonne Arjoranta | |||||
- S Heija | |||||
- Taru Luojola | |||||
- **French** | |||||
- Alda Marteau-Hardi | |||||
- Alix D. R. | |||||
- Baptiste Jonglez | |||||
- ButterflyOfFire | |||||
- Franck Paul | |||||
- Jean-Baptiste Holcroft | |||||
- Jonathan Chan | |||||
- Letiteuf55 | |||||
- Martin Bodin | |||||
- Mélanie Chauvel | |||||
- Olivier Humbert | |||||
- Paul Marques Mota | |||||
- Sylvhem | |||||
- Technowix | |||||
- Thibaut Girka | |||||
- Théodore | |||||
- azenet | |||||
- codl | |||||
- **Galician** | |||||
- ButterflyOfFire | |||||
- Xose M. | |||||
- manequim | |||||
- **Georgian** | |||||
- ButterflyOfFire | |||||
- **German** | |||||
- Benedikt Geißler | |||||
- ButterflyOfFire | |||||
- Daniel | |||||
- Eugen Rochko | |||||
- Koyu Berteon | |||||
- Patrick Figel | |||||
- Weblate Admin | |||||
- averageunicorn | |||||
- ePirat | |||||
- koyu | |||||
- larsreineke | |||||
- lilo | |||||
- **Greek** | |||||
- Antonis | |||||
- ButterflyOfFire | |||||
- Dimitris Maroulidis | |||||
- Konstantinos Grevenitis | |||||
- **Hebrew** | |||||
- ButterflyOfFire | |||||
- Ira | |||||
- Yaron Shahrabani | |||||
- **Hungarian** | |||||
- Adam Paszternak | |||||
- ButterflyOfFire | |||||
- Tibike Miklós | |||||
- **Ido** | |||||
- ButterflyOfFire | |||||
- **Indonesian** | |||||
- Alfiana Sibuea | |||||
- ButterflyOfFire | |||||
- Dito Kurnia Pratama | |||||
- Eirworks | |||||
- afachri | |||||
- se7entime | |||||
- **Italian** | |||||
- Alessandro Levati | |||||
- ButterflyOfFire | |||||
- Giuseppe Pignataro | |||||
- Stefano | |||||
- **Japanese** | |||||
- ButterflyOfFire | |||||
- Kumasun Morino | |||||
- Yamagishi Kazutoshi | |||||
- mayaeh | |||||
- osapon | |||||
- unarist | |||||
- 小鳥遊まりあ | |||||
- 森の子リスのミーコの大冒険 | |||||
- **Korean** | |||||
- ButterflyOfFire | |||||
- Jeong Arm | |||||
- Minori Hiraoka | |||||
- Yamagishi Kazutoshi | |||||
- **Malay** | |||||
- ButterflyOfFire | |||||
- Muhammad Nur Hidayat (MNH48) | |||||
- **Norwegian (old code)** | |||||
- ButterflyOfFire | |||||
- Espen Rønnevik | |||||
- Tale | |||||
- **Occitan** | |||||
- ButterflyOfFire | |||||
- Maxenç | |||||
- Quenti2 | |||||
- Quentí | |||||
- **Persian** | |||||
- ButterflyOfFire | |||||
- Masoud Abkenar | |||||
- **Polish** | |||||
- ButterflyOfFire | |||||
- Jakub Mendyk | |||||
- Marcin Mikołajczak | |||||
- Marek Ľach | |||||
- Stasiek Michalski | |||||
- krkk | |||||
- **Portuguese** | |||||
- ButterflyOfFire | |||||
- Hugo Gameiro | |||||
- manequim | |||||
- **Portuguese (Brazil)** | |||||
- André Andrade | |||||
- Anna e só | |||||
- ButterflyOfFire | |||||
- Renato "Lond" Cerqueira | |||||
- **Romanian** | |||||
- ButterflyOfFire | |||||
- adrianbblk | |||||
- **Russian** | |||||
- Andrew Zyabin | |||||
- ButterflyOfFire | |||||
- Evgeny Petrov | |||||
- Yaron Shahrabani | |||||
- **Serbian** | |||||
- Branko Kokanovic | |||||
- Burekz Finezt | |||||
- ButterflyOfFire | |||||
- **Serbian (latin)** | |||||
- ButterflyOfFire | |||||
- **Slovak** | |||||
- ButterflyOfFire | |||||
- Ivan Pleva | |||||
- Lorem Ipsum | |||||
- Marek Ľach | |||||
- Peter | |||||
- **Slovenian** | |||||
- ButterflyOfFire | |||||
- Kristijan Tkalec | |||||
- **Spanish** | |||||
- Angeles Broullón | |||||
- Antón López | |||||
- ButterflyOfFire | |||||
- Carlos Mondragon | |||||
- David Charte | |||||
- Emmanuel | |||||
- Lothar Wolf | |||||
- Pablo de la Concepción Sanz | |||||
- **Swedish** | |||||
- ButterflyOfFire | |||||
- Elias Mårtenson | |||||
- Isak Holmström | |||||
- Shellkr | |||||
- Stefan Midjich | |||||
- Tim Stahel | |||||
- **Telugu** | |||||
- ButterflyOfFire | |||||
- Joseph Nuthalapati | |||||
- Ranjith Tellakula | |||||
- avndp | |||||
- **Thai** | |||||
- ButterflyOfFire | |||||
- **Turkish** | |||||
- ButterflyOfFire | |||||
- **Ukrainian** | |||||
- ButterflyOfFire | |||||
- Ivan Verchenko | |||||
- alexcleac | |||||
- **Welsh** | |||||
- ButterflyOfFire | |||||
- Jaz-Michael King | |||||
- Kevin Beynon | |||||
- Owain Rhys Lewis | |||||
- Renato "Lond" Cerqueira | |||||
- Rhoslyn Prys | |||||
- carl morris | |||||
- **Armenian** | |||||
- ButterflyOfFire | |||||
- **Latvian** | |||||
- ButterflyOfFire | |||||
- **Tamil** | |||||
- ButterflyOfFire | |||||
- Prasanna Venkadesh |
@@ -5,6 +5,25 @@ libidn11 | |||||
libidn11-dev | libidn11-dev | ||||
libpq-dev | libpq-dev | ||||
libprotobuf-dev | libprotobuf-dev | ||||
libssl-dev | |||||
libxdamage1 | libxdamage1 | ||||
libxfixes3 | libxfixes3 | ||||
protobuf-compiler | protobuf-compiler | ||||
zlib1g-dev | |||||
libcairo2 | |||||
libcroco3 | |||||
libdatrie1 | |||||
libgdk-pixbuf2.0-0 | |||||
libgraphite2-3 | |||||
libharfbuzz0b | |||||
libpango-1.0-0 | |||||
libpangocairo-1.0-0 | |||||
libpangoft2-1.0-0 | |||||
libpixman-1-0 | |||||
librsvg2-2 | |||||
libthai-data | |||||
libthai0 | |||||
libvpx5 | |||||
libxcb-render0 | |||||
libxcb-shm0 | |||||
libxrender1 |
@@ -0,0 +1,330 @@ | |||||
Changelog | |||||
========= | |||||
All notable changes to this project will be documented in this file. | |||||
## [2.7.0] - 2019-01-20 | |||||
### Added | |||||
- Add link for adding a user to a list from their profile ([namelessGonbai](https://github.com/tootsuite/mastodon/pull/9062)) | |||||
- Add joining several hashtags in a single column ([gdpelican](https://github.com/tootsuite/mastodon/pull/8904)) | |||||
- Add volume sliders for videos ([sumdog](https://github.com/tootsuite/mastodon/pull/9366)) | |||||
- Add a tooltip explaining what a locked account is ([pawelngei](https://github.com/tootsuite/mastodon/pull/9403)) | |||||
- Add preloaded cache for common JSON-LD contexts ([ThibG](https://github.com/tootsuite/mastodon/pull/9412)) | |||||
- Add profile directory ([Gargron](https://github.com/tootsuite/mastodon/pull/9427)) | |||||
- Add setting to not group reblogs in home feed ([ThibG](https://github.com/tootsuite/mastodon/pull/9248)) | |||||
- Add admin ability to remove a user's header image ([ThibG](https://github.com/tootsuite/mastodon/pull/9495)) | |||||
- Add account hashtags to ActivityPub actor JSON ([Gargron](https://github.com/tootsuite/mastodon/pull/9450)) | |||||
- Add error message for avatar image that's too large ([sumdog](https://github.com/tootsuite/mastodon/pull/9518)) | |||||
- Add notification quick-filter bar ([pawelngei](https://github.com/tootsuite/mastodon/pull/9399)) | |||||
- Add new first-time tutorial ([Gargron](https://github.com/tootsuite/mastodon/pull/9531)) | |||||
- Add moderation warnings ([Gargron](https://github.com/tootsuite/mastodon/pull/9519)) | |||||
- Add emoji codepoint mappings for v11.0 ([Gargron](https://github.com/tootsuite/mastodon/pull/9618)) | |||||
- Add REST API for creating an account ([Gargron](https://github.com/tootsuite/mastodon/pull/9572)) | |||||
- Add support for Malayalam in language filter ([tachyons](https://github.com/tootsuite/mastodon/pull/9624)) | |||||
- Add exclude_reblogs option to account statuses API ([Gargron](https://github.com/tootsuite/mastodon/pull/9640)) | |||||
- Add local followers page to admin account UI ([chr-1x](https://github.com/tootsuite/mastodon/pull/9610)) | |||||
- Add healthcheck commands to docker-compose.yml ([BenLubar](https://github.com/tootsuite/mastodon/pull/9143)) | |||||
- Add handler for Move activity to migrate followers ([Gargron](https://github.com/tootsuite/mastodon/pull/9629)) | |||||
- Add CSV export for lists and domain blocks ([Gargron](https://github.com/tootsuite/mastodon/pull/9677)) | |||||
- Add `tootctl accounts follow ACCT` ([Gargron](https://github.com/tootsuite/mastodon/pull/9414)) | |||||
- Add scheduled statuses ([Gargron](https://github.com/tootsuite/mastodon/pull/9706)) | |||||
- Add immutable caching for S3 objects ([nolanlawson](https://github.com/tootsuite/mastodon/pull/9722)) | |||||
- Add cache to custom emojis API ([Gargron](https://github.com/tootsuite/mastodon/pull/9732)) | |||||
- Add preview cards to non-detailed statuses on public pages ([Gargron](https://github.com/tootsuite/mastodon/pull/9714)) | |||||
- Add `mod` and `moderator` to list of default reserved usernames ([Gargron](https://github.com/tootsuite/mastodon/pull/9713)) | |||||
- Add quick links to the admin interface in the web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/8545)) | |||||
- Add `tootctl domains crawl` ([Gargron](https://github.com/tootsuite/mastodon/pull/9809)) | |||||
- Add attachment list fallback to public pages ([ThibG](https://github.com/tootsuite/mastodon/pull/9780)) | |||||
- Add `tootctl --version` ([Gargron](https://github.com/tootsuite/mastodon/pull/9835)) | |||||
- Add information about how to opt-in to the directory on the directory ([Gargron](https://github.com/tootsuite/mastodon/pull/9834)) | |||||
- Add timeouts for S3 ([Gargron](https://github.com/tootsuite/mastodon/pull/9842)) | |||||
- Add support for non-public reblogs from ActivityPub ([Gargron](https://github.com/tootsuite/mastodon/pull/9841)) | |||||
- Add sending of `Reject` activity when sending a `Block` activity ([ThibG](https://github.com/tootsuite/mastodon/pull/9811)) | |||||
### Changed | |||||
- Temporarily pause timeline if mouse moved recently ([lmorchard](https://github.com/tootsuite/mastodon/pull/9200)) | |||||
- Change the password form order ([mayaeh](https://github.com/tootsuite/mastodon/pull/9267)) | |||||
- Redesign admin UI for accounts ([Gargron](https://github.com/tootsuite/mastodon/pull/9340), [Gargron](https://github.com/tootsuite/mastodon/pull/9643)) | |||||
- Redesign admin UI for instances/domain blocks ([Gargron](https://github.com/tootsuite/mastodon/pull/9645)) | |||||
- Swap avatar and header input fields in profile page ([ThibG](https://github.com/tootsuite/mastodon/pull/9271)) | |||||
- When posting in mobile mode, go back to previous history location ([ThibG](https://github.com/tootsuite/mastodon/pull/9502)) | |||||
- Split out is_changing_upload from is_submitting ([ThibG](https://github.com/tootsuite/mastodon/pull/9536)) | |||||
- Back to the getting-started when pins the timeline. ([kedamaDQ](https://github.com/tootsuite/mastodon/pull/9561)) | |||||
- Allow unauthenticated REST API access to GET /api/v1/accounts/:id/statuses ([Gargron](https://github.com/tootsuite/mastodon/pull/9573)) | |||||
- Limit maximum visibility of local silenced users to unlisted ([ThibG](https://github.com/tootsuite/mastodon/pull/9583)) | |||||
- Change API error message for unconfirmed accounts ([noellabo](https://github.com/tootsuite/mastodon/pull/9625)) | |||||
- Change the icon to "reply-all" when it's a reply to other accounts ([mayaeh](https://github.com/tootsuite/mastodon/pull/9378)) | |||||
- Do not ignore federated reports targetting already-reported accounts ([ThibG](https://github.com/tootsuite/mastodon/pull/9534)) | |||||
- Upgrade default Ruby version to 2.6.0 ([Gargron](https://github.com/tootsuite/mastodon/pull/9688)) | |||||
- Change e-mail digest frequency ([Gargron](https://github.com/tootsuite/mastodon/pull/9689)) | |||||
- Change Docker images for Tor support in docker-compose.yml ([Sir-Boops](https://github.com/tootsuite/mastodon/pull/9438)) | |||||
- Display fallback link card thumbnail when none is given ([Gargron](https://github.com/tootsuite/mastodon/pull/9715)) | |||||
- Change account bio length validation to ignore mention domains and URLs ([Gargron](https://github.com/tootsuite/mastodon/pull/9717)) | |||||
- Use configured contact user for "anonymous" federation activities ([yukimochi](https://github.com/tootsuite/mastodon/pull/9661)) | |||||
- Change remote interaction dialog to use specific actions instead of generic "interact" ([Gargron](https://github.com/tootsuite/mastodon/pull/9743)) | |||||
- Always re-fetch public key when signature verification fails to support blind key rotation ([ThibG](https://github.com/tootsuite/mastodon/pull/9667)) | |||||
- Make replies to boosts impossible, connect reply to original status instead ([valerauko](https://github.com/tootsuite/mastodon/pull/9129)) | |||||
- Change e-mail MX validation to check both A and MX records against blacklist ([Gargron](https://github.com/tootsuite/mastodon/pull/9489)) | |||||
- Hide floating action button on search and getting started pages ([tmm576](https://github.com/tootsuite/mastodon/pull/9826)) | |||||
- Redesign public hashtag page to use a masonry layout ([Gargron](https://github.com/tootsuite/mastodon/pull/9822)) | |||||
- Use `summary` as summary instead of content warning for converted ActivityPub objects ([Gargron](https://github.com/tootsuite/mastodon/pull/9823)) | |||||
- Display a double reply arrow on public pages for toots that are replies ([ThibG](https://github.com/tootsuite/mastodon/pull/9808)) | |||||
- Change admin UI right panel size to be wider ([Kjwon15](https://github.com/tootsuite/mastodon/pull/9768)) | |||||
### Removed | |||||
- Remove links to bridge.joinmastodon.org (non-functional) ([Gargron](https://github.com/tootsuite/mastodon/pull/9608)) | |||||
- Remove LD-Signatures from activities that do not need them ([ThibG](https://github.com/tootsuite/mastodon/pull/9659)) | |||||
### Fixed | |||||
- Remove unused computation of reblog references from updateTimeline ([ThibG](https://github.com/tootsuite/mastodon/pull/9244)) | |||||
- Fix loaded embeds resetting if a status arrives from API again ([ThibG](https://github.com/tootsuite/mastodon/pull/9270)) | |||||
- Fix race condition causing shallow status with only a "favourited" attribute ([ThibG](https://github.com/tootsuite/mastodon/pull/9272)) | |||||
- Remove intermediary arrays when creating hash maps from results ([Gargron](https://github.com/tootsuite/mastodon/pull/9291)) | |||||
- Extract counters from accounts table to account_stats table to improve performance ([Gargron](https://github.com/tootsuite/mastodon/pull/9295)) | |||||
- Change identities id column to a bigint ([Gargron](https://github.com/tootsuite/mastodon/pull/9371)) | |||||
- Fix conversations API pagination ([ThibG](https://github.com/tootsuite/mastodon/pull/9407)) | |||||
- Improve account suspension speed and completeness ([Gargron](https://github.com/tootsuite/mastodon/pull/9290)) | |||||
- Fix thread depth computation in statuses_controller ([ThibG](https://github.com/tootsuite/mastodon/pull/9426)) | |||||
- Fix database deadlocks by moving account stats update outside transaction ([ThibG](https://github.com/tootsuite/mastodon/pull/9437)) | |||||
- Escape HTML in profile name preview in profile settings ([pawelngei](https://github.com/tootsuite/mastodon/pull/9446)) | |||||
- Use same CORS policy for /@:username and /users/:username ([ThibG](https://github.com/tootsuite/mastodon/pull/9485)) | |||||
- Make custom emoji domains case insensitive ([Esteth](https://github.com/tootsuite/mastodon/pull/9474)) | |||||
- Various fixes to scrollable lists and media gallery ([ThibG](https://github.com/tootsuite/mastodon/pull/9501)) | |||||
- Fix bootsnap cache directory being declared relatively ([Gargron](https://github.com/tootsuite/mastodon/pull/9511)) | |||||
- Fix timeline pagination in the web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/9516)) | |||||
- Fix padding on dropdown elements in preferences ([ThibG](https://github.com/tootsuite/mastodon/pull/9517)) | |||||
- Make avatar and headers respect GIF autoplay settings ([ThibG](https://github.com/tootsuite/mastodon/pull/9515)) | |||||
- Do no retry Web Push workers if the server returns a 4xx response ([Gargron](https://github.com/tootsuite/mastodon/pull/9434)) | |||||
- Minor scrollable list fixes ([ThibG](https://github.com/tootsuite/mastodon/pull/9551)) | |||||
- Ignore low-confidence CharlockHolmes guesses when parsing link cards ([ThibG](https://github.com/tootsuite/mastodon/pull/9510)) | |||||
- Fix `tootctl accounts rotate` not updating public keys ([Gargron](https://github.com/tootsuite/mastodon/pull/9556)) | |||||
- Fix CSP / X-Frame-Options for media players ([jomo](https://github.com/tootsuite/mastodon/pull/9558)) | |||||
- Fix unnecessary loadMore calls when the end of a timeline has been reached ([ThibG](https://github.com/tootsuite/mastodon/pull/9581)) | |||||
- Skip mailer job retries when a record no longer exists ([Gargron](https://github.com/tootsuite/mastodon/pull/9590)) | |||||
- Fix composer not getting focus after reply confirmation dialog ([ThibG](https://github.com/tootsuite/mastodon/pull/9602)) | |||||
- Fix signature verification stoplight triggering on non-timeout errors ([Gargron](https://github.com/tootsuite/mastodon/pull/9617)) | |||||
- Fix ThreadResolveWorker getting queued with invalid URLs ([Gargron](https://github.com/tootsuite/mastodon/pull/9628)) | |||||
- Fix crash when clearing uninitialized timeline ([ThibG](https://github.com/tootsuite/mastodon/pull/9662)) | |||||
- Avoid duplicate work by merging ReplyDistributionWorker into DistributionWorker ([ThibG](https://github.com/tootsuite/mastodon/pull/9660)) | |||||
- Skip full text search if it fails, instead of erroring out completely ([Kjwon15](https://github.com/tootsuite/mastodon/pull/9654)) | |||||
- Fix profile metadata links not verifying correctly sometimes ([shrft](https://github.com/tootsuite/mastodon/pull/9673)) | |||||
- Ensure blocked user unfollows blocker if Block/Undo-Block activities are processed out of order ([ThibG](https://github.com/tootsuite/mastodon/pull/9687)) | |||||
- Fix unreadable text color in report modal for some statuses ([Gargron](https://github.com/tootsuite/mastodon/pull/9716)) | |||||
- Stop GIFV timeline preview explicitly when it's opened in modal ([kedamaDQ](https://github.com/tootsuite/mastodon/pull/9749)) | |||||
- Fix scrollbar width compensation ([ThibG](https://github.com/tootsuite/mastodon/pull/9824)) | |||||
- Fix race conditions when processing deleted toots ([ThibG](https://github.com/tootsuite/mastodon/pull/9815)) | |||||
- Fix SSO issues on WebKit browsers by disabling Same-Site cookie again ([moritzheiber](https://github.com/tootsuite/mastodon/pull/9819)) | |||||
- Fix empty OEmbed error ([renatolond](https://github.com/tootsuite/mastodon/pull/9807)) | |||||
- Fix drag & drop modal not disappearing sometimes ([hinaloe](https://github.com/tootsuite/mastodon/pull/9797)) | |||||
- Fix statuses with content warnings being displayed in web push notifications sometimes ([ThibG](https://github.com/tootsuite/mastodon/pull/9778)) | |||||
- Fix scroll-to-detailed status not working on public pages ([ThibG](https://github.com/tootsuite/mastodon/pull/9773)) | |||||
- Fix media modal loading indicator ([ThibG](https://github.com/tootsuite/mastodon/pull/9771)) | |||||
- Fix hashtag search results not having a permalink fallback in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/9810)) | |||||
- Fix slightly cropped font on settings page dropdowns when using system font ([ariasuni](https://github.com/tootsuite/mastodon/pull/9839)) | |||||
- Fix not being able to drag & drop text into forms ([tmm576](https://github.com/tootsuite/mastodon/pull/9840)) | |||||
### Security | |||||
- Sanitize and sandbox toot embeds in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/9552)) | |||||
- Add tombstones for remote statuses to prevent replay attacks ([ThibG](https://github.com/tootsuite/mastodon/pull/9830)) | |||||
## [2.6.5] - 2018-12-01 | |||||
### Changed | |||||
- Change lists to display replies to others on the list and list owner ([ThibG](https://github.com/tootsuite/mastodon/pull/9324)) | |||||
### Fixed | |||||
- Fix failures caused by commonly-used JSON-LD contexts being unavailable ([ThibG](https://github.com/tootsuite/mastodon/pull/9412)) | |||||
## [2.6.4] - 2018-11-30 | |||||
### Fixed | |||||
- Fix yarn dependencies not installing due to yanked event-stream package ([Gargron](https://github.com/tootsuite/mastodon/pull/9401)) | |||||
## [2.6.3] - 2018-11-30 | |||||
### Added | |||||
- Add hyphen to characters allowed in remote usernames ([ThibG](https://github.com/tootsuite/mastodon/pull/9345)) | |||||
### Changed | |||||
- Change server user count to exclude suspended accounts ([Gargron](https://github.com/tootsuite/mastodon/pull/9380)) | |||||
### Fixed | |||||
- Fix ffmpeg processing sometimes stalling due to overfilled stdout buffer ([hugogameiro](https://github.com/tootsuite/mastodon/pull/9368)) | |||||
- Fix missing DNS records raising the wrong kind of exception ([Gargron](https://github.com/tootsuite/mastodon/pull/9379)) | |||||
- Fix already queued deliveries still trying to reach inboxes marked as unavailable ([Gargron](https://github.com/tootsuite/mastodon/pull/9358)) | |||||
### Security | |||||
- Fix TLS handshake timeout not being enforced ([Gargron](https://github.com/tootsuite/mastodon/pull/9381)) | |||||
## [2.6.2] - 2018-11-23 | |||||
### Added | |||||
- Add Page to whitelisted ActivityPub types ([mbajur](https://github.com/tootsuite/mastodon/pull/9188)) | |||||
- Add 20px to column width in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/9227)) | |||||
- Add amount of freed disk space in `tootctl media remove` ([Gargron](https://github.com/tootsuite/mastodon/pull/9229), [Gargron](https://github.com/tootsuite/mastodon/pull/9239), [mayaeh](https://github.com/tootsuite/mastodon/pull/9288)) | |||||
- Add "Show thread" link to self-replies ([Gargron](https://github.com/tootsuite/mastodon/pull/9228)) | |||||
### Changed | |||||
- Change order of Atom and RSS links so Atom is first ([Alkarex](https://github.com/tootsuite/mastodon/pull/9302)) | |||||
- Change Nginx configuration for Nanobox apps ([danhunsaker](https://github.com/tootsuite/mastodon/pull/9310)) | |||||
- Change the follow action to appear instant in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/9220)) | |||||
- Change how the ActiveRecord connection is instantiated in on_worker_boot ([Gargron](https://github.com/tootsuite/mastodon/pull/9238)) | |||||
- Change `tootctl accounts cull` to always touch accounts so they can be skipped ([renatolond](https://github.com/tootsuite/mastodon/pull/9293)) | |||||
- Change mime type comparison to ignore JSON-LD profile ([valerauko](https://github.com/tootsuite/mastodon/pull/9179)) | |||||
### Fixed | |||||
- Fix web UI crash when conversation has no last status ([sammy8806](https://github.com/tootsuite/mastodon/pull/9207)) | |||||
- Fix follow limit validator reporting lower number past threshold ([Gargron](https://github.com/tootsuite/mastodon/pull/9230)) | |||||
- Fix form validation flash message color and input borders ([Gargron](https://github.com/tootsuite/mastodon/pull/9235)) | |||||
- Fix invalid twitter:player cards being displayed ([ThibG](https://github.com/tootsuite/mastodon/pull/9254)) | |||||
- Fix emoji update date being processed incorrectly ([ThibG](https://github.com/tootsuite/mastodon/pull/9255)) | |||||
- Fix playing embed resetting if status is reloaded in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/9270), [Gargron](https://github.com/tootsuite/mastodon/pull/9275)) | |||||
- Fix web UI crash when favouriting a deleted status ([ThibG](https://github.com/tootsuite/mastodon/pull/9272)) | |||||
- Fix intermediary arrays being created for hash maps ([Gargron](https://github.com/tootsuite/mastodon/pull/9291)) | |||||
- Fix filter ID not being a string in REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/9303)) | |||||
### Security | |||||
- Fix multiple remote account deletions being able to deadlock the database ([Gargron](https://github.com/tootsuite/mastodon/pull/9292)) | |||||
- Fix HTTP connection timeout of 10s not being enforced ([Gargron](https://github.com/tootsuite/mastodon/pull/9329)) | |||||
## [2.6.1] - 2018-10-30 | |||||
### Fixed | |||||
- Fix resolving resources by URL not working due to a regression in [valerauko](https://github.com/tootsuite/mastodon/pull/9132) ([Gargron](https://github.com/tootsuite/mastodon/pull/9171)) | |||||
- Fix reducer error in web UI when a conversation has no last status ([Gargron](https://github.com/tootsuite/mastodon/pull/9173)) | |||||
## [2.6.0] - 2018-10-30 | |||||
### Added | |||||
- Add link ownership verification ([Gargron](https://github.com/tootsuite/mastodon/pull/8703)) | |||||
- Add conversations API ([Gargron](https://github.com/tootsuite/mastodon/pull/8832)) | |||||
- Add limit for the number of people that can be followed from one account ([Gargron](https://github.com/tootsuite/mastodon/pull/8807)) | |||||
- Add admin setting to customize mascot ([ashleyhull-versent](https://github.com/tootsuite/mastodon/pull/8766)) | |||||
- Add support for more granular ActivityPub audiences from other software, i.e. circles ([Gargron](https://github.com/tootsuite/mastodon/pull/8950), [Gargron](https://github.com/tootsuite/mastodon/pull/9093), [Gargron](https://github.com/tootsuite/mastodon/pull/9150)) | |||||
- Add option to block all reports from a domain ([Gargron](https://github.com/tootsuite/mastodon/pull/8830)) | |||||
- Add user preference to always expand toots marked with content warnings ([webroo](https://github.com/tootsuite/mastodon/pull/8762)) | |||||
- Add user preference to always hide all media ([fvh-P](https://github.com/tootsuite/mastodon/pull/8569)) | |||||
- Add `force_login` param to OAuth authorize page ([Gargron](https://github.com/tootsuite/mastodon/pull/8655)) | |||||
- Add `tootctl accounts backup` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811)) | |||||
- Add `tootctl accounts create` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811)) | |||||
- Add `tootctl accounts cull` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811)) | |||||
- Add `tootctl accounts delete` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811)) | |||||
- Add `tootctl accounts modify` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811)) | |||||
- Add `tootctl accounts refresh` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811)) | |||||
- Add `tootctl feeds build` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811)) | |||||
- Add `tootctl feeds clear` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811)) | |||||
- Add `tootctl settings registrations open` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811)) | |||||
- Add `tootctl settings registrations close` ([Gargron](https://github.com/tootsuite/mastodon/pull/8642), [Gargron](https://github.com/tootsuite/mastodon/pull/8811)) | |||||
- Add `min_id` param to REST API to support backwards pagination ([Gargron](https://github.com/tootsuite/mastodon/pull/8736)) | |||||
- Add a confirmation dialog when hitting reply and the compose box isn't empty ([ThibG](https://github.com/tootsuite/mastodon/pull/8893)) | |||||
- Add PostgreSQL disk space growth tracking in PGHero ([Gargron](https://github.com/tootsuite/mastodon/pull/8906)) | |||||
- Add button for disabling local account to report quick actions bar ([Gargron](https://github.com/tootsuite/mastodon/pull/9024)) | |||||
- Add Czech language ([Aditoo17](https://github.com/tootsuite/mastodon/pull/8594)) | |||||
- Add `same-site` (`lax`) attribute to cookies ([sorin-davidoi](https://github.com/tootsuite/mastodon/pull/8626)) | |||||
- Add support for styled scrollbars in Firefox Nightly ([sorin-davidoi](https://github.com/tootsuite/mastodon/pull/8653)) | |||||
- Add highlight to the active tab in web UI profiles ([rhoio](https://github.com/tootsuite/mastodon/pull/8673)) | |||||
- Add auto-focus for comment textarea in report modal ([ThibG](https://github.com/tootsuite/mastodon/pull/8689)) | |||||
- Add auto-focus for emoji picker's search field ([ThibG](https://github.com/tootsuite/mastodon/pull/8688)) | |||||
- Add nginx and systemd templates to `dist/` directory ([Gargron](https://github.com/tootsuite/mastodon/pull/8770)) | |||||
- Add support for `/.well-known/change-password` ([Gargron](https://github.com/tootsuite/mastodon/pull/8828)) | |||||
- Add option to override FFMPEG binary path ([sascha-sl](https://github.com/tootsuite/mastodon/pull/8855)) | |||||
- Add `dns-prefetch` tag when using different host for assets or uploads ([Gargron](https://github.com/tootsuite/mastodon/pull/8942)) | |||||
- Add `description` meta tag ([Gargron](https://github.com/tootsuite/mastodon/pull/8941)) | |||||
- Add `Content-Security-Policy` header ([ThibG](https://github.com/tootsuite/mastodon/pull/8957)) | |||||
- Add cache for the instance info API ([ykzts](https://github.com/tootsuite/mastodon/pull/8765)) | |||||
- Add suggested follows to search screen in mobile layout ([Gargron](https://github.com/tootsuite/mastodon/pull/9010)) | |||||
- Add CORS header to `/.well-known/*` routes ([BenLubar](https://github.com/tootsuite/mastodon/pull/9083)) | |||||
- Add `card` attribute to statuses returned from REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/9120)) | |||||
- Add in-stream link preview ([Gargron](https://github.com/tootsuite/mastodon/pull/9120)) | |||||
- Add support for ActivityPub `Page` objects ([mbajur](https://github.com/tootsuite/mastodon/pull/9121)) | |||||
### Changed | |||||
- Change forms design ([Gargron](https://github.com/tootsuite/mastodon/pull/8703)) | |||||
- Change reports overview to group by target account ([Gargron](https://github.com/tootsuite/mastodon/pull/8674)) | |||||
- Change web UI to show "read more" link on overly long in-stream statuses ([lanodan](https://github.com/tootsuite/mastodon/pull/8205)) | |||||
- Change design of direct messages column ([Gargron](https://github.com/tootsuite/mastodon/pull/8832), [Gargron](https://github.com/tootsuite/mastodon/pull/9022)) | |||||
- Change home timelines to exclude DMs ([Gargron](https://github.com/tootsuite/mastodon/pull/8940)) | |||||
- Change list timelines to exclude all replies ([cbayerlein](https://github.com/tootsuite/mastodon/pull/8683)) | |||||
- Change admin accounts UI default sort to most recent ([Gargron](https://github.com/tootsuite/mastodon/pull/8813)) | |||||
- Change documentation URL in the UI ([Gargron](https://github.com/tootsuite/mastodon/pull/8898)) | |||||
- Change style of success and failure messages ([Gargron](https://github.com/tootsuite/mastodon/pull/8973)) | |||||
- Change DM filtering to always allow DMs from staff ([qguv](https://github.com/tootsuite/mastodon/pull/8993)) | |||||
- Change recommended Ruby version to 2.5.3 ([zunda](https://github.com/tootsuite/mastodon/pull/9003)) | |||||
- Change docker-compose default to persist volumes in current directory ([Gargron](https://github.com/tootsuite/mastodon/pull/9055)) | |||||
- Change character counters on edit profile page to input length limit ([Gargron](https://github.com/tootsuite/mastodon/pull/9100)) | |||||
- Change notification filtering to always let through messages from staff ([Gargron](https://github.com/tootsuite/mastodon/pull/9152)) | |||||
- Change "hide boosts from user" function also hiding notifications about boosts ([ThibG](https://github.com/tootsuite/mastodon/pull/9147)) | |||||
- Change CSS `detailed-status__wrapper` class actually wrap the detailed status ([trwnh](https://github.com/tootsuite/mastodon/pull/8547)) | |||||
### Deprecated | |||||
- `GET /api/v1/timelines/direct` → `GET /api/v1/conversations` ([Gargron](https://github.com/tootsuite/mastodon/pull/8832)) | |||||
- `POST /api/v1/notifications/dismiss` → `POST /api/v1/notifications/:id/dismiss` ([Gargron](https://github.com/tootsuite/mastodon/pull/8905)) | |||||
- `GET /api/v1/statuses/:id/card` → `card` attributed included in status ([Gargron](https://github.com/tootsuite/mastodon/pull/9120)) | |||||
### Removed | |||||
- Remove "on this device" label in column push settings ([rhoio](https://github.com/tootsuite/mastodon/pull/8704)) | |||||
- Remove rake tasks in favour of tootctl commands ([Gargron](https://github.com/tootsuite/mastodon/pull/8675)) | |||||
### Fixed | |||||
- Fix remote statuses using instance's default locale if no language given ([Kjwon15](https://github.com/tootsuite/mastodon/pull/8861)) | |||||
- Fix streaming API not exiting when port or socket is unavailable ([Gargron](https://github.com/tootsuite/mastodon/pull/9023)) | |||||
- Fix network calls being performed in database transaction in ActivityPub handler ([Gargron](https://github.com/tootsuite/mastodon/pull/8951)) | |||||
- Fix dropdown arrow position ([ThibG](https://github.com/tootsuite/mastodon/pull/8637)) | |||||
- Fix first element of dropdowns being focused even if not using keyboard ([ThibG](https://github.com/tootsuite/mastodon/pull/8679)) | |||||
- Fix tootctl requiring `bundle exec` invocation ([abcang](https://github.com/tootsuite/mastodon/pull/8619)) | |||||
- Fix public pages not using animation preference for avatars ([renatolond](https://github.com/tootsuite/mastodon/pull/8614)) | |||||
- Fix OEmbed/OpenGraph cards not understanding relative URLs ([ThibG](https://github.com/tootsuite/mastodon/pull/8669)) | |||||
- Fix some dark emojis not having a white outline ([ThibG](https://github.com/tootsuite/mastodon/pull/8597)) | |||||
- Fix media description not being displayed in various media modals ([ThibG](https://github.com/tootsuite/mastodon/pull/8678)) | |||||
- Fix generated URLs of desktop notifications missing base URL ([GenbuHase](https://github.com/tootsuite/mastodon/pull/8758)) | |||||
- Fix RTL styles ([mabkenar](https://github.com/tootsuite/mastodon/pull/8764), [mabkenar](https://github.com/tootsuite/mastodon/pull/8767), [mabkenar](https://github.com/tootsuite/mastodon/pull/8823), [mabkenar](https://github.com/tootsuite/mastodon/pull/8897), [mabkenar](https://github.com/tootsuite/mastodon/pull/9005), [mabkenar](https://github.com/tootsuite/mastodon/pull/9007), [mabkenar](https://github.com/tootsuite/mastodon/pull/9018), [mabkenar](https://github.com/tootsuite/mastodon/pull/9021), [mabkenar](https://github.com/tootsuite/mastodon/pull/9145), [mabkenar](https://github.com/tootsuite/mastodon/pull/9146)) | |||||
- Fix crash in streaming API when tag param missing ([Gargron](https://github.com/tootsuite/mastodon/pull/8955)) | |||||
- Fix hotkeys not working when no element is focused ([ThibG](https://github.com/tootsuite/mastodon/pull/8998)) | |||||
- Fix some hotkeys not working on detailed status view ([ThibG](https://github.com/tootsuite/mastodon/pull/9006)) | |||||
- Fix og:url on status pages ([ThibG](https://github.com/tootsuite/mastodon/pull/9047)) | |||||
- Fix upload option buttons only being visible on hover ([Gargron](https://github.com/tootsuite/mastodon/pull/9074)) | |||||
- Fix tootctl not returning exit code 1 on wrong arguments ([sascha-sl](https://github.com/tootsuite/mastodon/pull/9094)) | |||||
- Fix preview cards for appearing for profiles mentioned in toot ([ThibG](https://github.com/tootsuite/mastodon/pull/6934), [ThibG](https://github.com/tootsuite/mastodon/pull/9158)) | |||||
- Fix local accounts sometimes being duplicated as faux-remote ([Gargron](https://github.com/tootsuite/mastodon/pull/9109)) | |||||
- Fix emoji search when the shortcode has multiple separators ([ThibG](https://github.com/tootsuite/mastodon/pull/9124)) | |||||
- Fix dropdowns sometimes being partially obscured by other elements ([kedamaDQ](https://github.com/tootsuite/mastodon/pull/9126)) | |||||
- Fix cache not updating when reply/boost/favourite counters or media sensitivity update ([Gargron](https://github.com/tootsuite/mastodon/pull/9119)) | |||||
- Fix empty display name precedence over username in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/9163)) | |||||
- Fix td instead of th in sessions table header ([Gargron](https://github.com/tootsuite/mastodon/pull/9162)) | |||||
- Fix handling of content types with profile ([valerauko](https://github.com/tootsuite/mastodon/pull/9132)) | |||||
## [2.5.2] - 2018-10-12 | |||||
### Security | |||||
- Fix XSS vulnerability ([Gargron](https://github.com/tootsuite/mastodon/pull/8959)) | |||||
## [2.5.1] - 2018-10-07 | |||||
### Fixed | |||||
- Fix database migrations for PostgreSQL below 9.5 ([Gargron](https://github.com/tootsuite/mastodon/pull/8903)) | |||||
- Fix class autoloading issue in ActivityPub Create handler ([Gargron](https://github.com/tootsuite/mastodon/pull/8820)) | |||||
- Fix cache statistics not being sent via statsd when statsd enabled ([ykzts](https://github.com/tootsuite/mastodon/pull/8831)) | |||||
- Bump puma from 3.11.4 to 3.12.0 ([dependabot[bot]](https://github.com/tootsuite/mastodon/pull/8883)) | |||||
### Security | |||||
- Fix some local images not having their EXIF metadata stripped on upload ([ThibG](https://github.com/tootsuite/mastodon/pull/8714)) | |||||
- Fix being able to enable a disabled relay via ActivityPub Accept handler ([ThibG](https://github.com/tootsuite/mastodon/pull/8864)) | |||||
- Bump nokogiri from 1.8.4 to 1.8.5 ([dependabot[bot]](https://github.com/tootsuite/mastodon/pull/8881)) | |||||
- Fix being able to report statuses not belonging to the reported account ([ThibG](https://github.com/tootsuite/mastodon/pull/8916)) |
@@ -1,56 +1,37 @@ | |||||
CONTRIBUTING | |||||
Contributing | |||||
============ | ============ | ||||
There are three ways in which you can contribute to this repository: | |||||
Thank you for considering contributing to Mastodon 🐘 | |||||
1. By improving the documentation | |||||
2. By working on the back-end application | |||||
3. By working on the front-end application | |||||
You can contribute in the following ways: | |||||
Choosing what to work on in a large open source project is not easy. The list of [GitHub issues](https://github.com/tootsuite/mastodon/issues) may provide some ideas, but not every feature request has been greenlit. Likewise, not every change or feature that resolves a personal itch will be merged into the main repository. Some communication ahead of time may be wise. If your addition creates a new feature or setting, or otherwise changes how things work in some substantial way, please remember to submit a correlating pull request to document your changes in the [documentation](http://github.com/tootsuite/documentation). | |||||
- Finding and reporting bugs | |||||
- Translating the Mastodon interface into various languages | |||||
- Contributing code to Mastodon by fixing bugs or implementing features | |||||
- Improving the documentation | |||||
Below are the guidelines for working on pull requests: | |||||
## Bug reports | |||||
## General | |||||
Bug reports and feature suggestions can be submitted to [GitHub Issues](https://github.com/tootsuite/mastodon/issues). Please make sure that you are not submitting duplicates, and that a similar report or request has not already been resolved or rejected in the past using the search function. Please also use descriptive, concise titles. | |||||
- 2 spaces indentation | |||||
## Translations | |||||
## Documentation | |||||
- No spelling mistakes | |||||
- No orthographic mistakes | |||||
- No Markdown syntax errors | |||||
## Requirements | |||||
- Ruby | |||||
- Node.js | |||||
- PostgreSQL | |||||
- Redis | |||||
- Nginx (optional) | |||||
## Back-end application | |||||
You can submit translations via [Weblate](https://weblate.joinmastodon.org/). They are periodically merged into the codebase. | |||||
It is expected that you have a working development environment set up. The development environment includes [rubocop](https://github.com/bbatsov/rubocop), which checks your Ruby code for compliance with our style guide and best practices. Sublime Text, likely like other editors, has a [Rubocop plugin](https://github.com/pderichs/sublime_rubocop) that runs checks on files as you edit them. The codebase also has a test suite. | |||||
* The codebase is not perfect, at the time of writing, but it is expected that you do not introduce new code style violations | |||||
* The rspec test suite must pass | |||||
* To the extent that it is possible, verify your changes. In the best case, by adding new tests to the test suite. At the very least, by running the server or console and checking it manually | |||||
* If you are introducing new strings to the user interface, they must be using localization methods | |||||
[![Mastodon translation statistics by language](https://weblate.joinmastodon.org/widgets/mastodon/-/multi-auto.svg)](https://weblate.joinmastodon.org/) | |||||
If your code has syntax errors that won't let it run, it's a good sign that the pull request isn't ready for submission yet. | |||||
## Pull requests | |||||
## Front-end application | |||||
Please use clean, concise titles for your pull requests. We use commit squashing, so the final commit in the master branch will carry the title of the pull request. | |||||
It is expected that you have a working development environment set up (see back-end application section). This project includes an ESLint configuration file, with which you can lint your changes. | |||||
The smaller the set of changes in the pull request is, the quicker it can be reviewed and merged. Splitting tasks into multiple smaller pull requests is often preferable. | |||||
* Avoid grave ESLint violations | |||||
* Verify that your changes work | |||||
* If you are introducing new strings, they must be using localization methods | |||||
**Pull requests that do not pass automated checks may not be reviewed**. In particular, you need to keep in mind: | |||||
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. | |||||
- Unit and integration tests (rspec, jest) | |||||
- Code style rules (rubocop, eslint) | |||||
- Normalization of locale files (i18n-tasks) | |||||
## Translate | |||||
## Documentation | |||||
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/) | |||||
The [Mastodon documentation](https://docs.joinmastodon.org) is a statically generated site. You can [submit merge requests to mastodon/docs](https://source.joinmastodon.org/mastodon/docs). |
@@ -1,4 +1,5 @@ | |||||
FROM ruby:2.4.4-alpine3.6 | |||||
FROM node:8.15-alpine as node | |||||
FROM ruby:2.6-alpine3.8 | |||||
LABEL maintainer="https://github.com/tootsuite/mastodon" \ | LABEL maintainer="https://github.com/tootsuite/mastodon" \ | ||||
description="Your self-hosted, globally interconnected microblogging community" | description="Your self-hosted, globally interconnected microblogging community" | ||||
@@ -11,8 +12,6 @@ ENV PATH=/mastodon/bin:$PATH \ | |||||
RAILS_ENV=production \ | RAILS_ENV=production \ | ||||
NODE_ENV=production | NODE_ENV=production | ||||
ARG YARN_VERSION=1.3.2 | |||||
ARG YARN_DOWNLOAD_SHA256=6cfe82e530ef0837212f13e45c1565ba53f5199eec2527b85ecbcd88bf26821d | |||||
ARG LIBICONV_VERSION=1.15 | ARG LIBICONV_VERSION=1.15 | ||||
ARG LIBICONV_DOWNLOAD_SHA256=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178 | ARG LIBICONV_DOWNLOAD_SHA256=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178 | ||||
@@ -20,6 +19,11 @@ EXPOSE 3000 4000 | |||||
WORKDIR /mastodon | WORKDIR /mastodon | ||||
COPY --from=node /usr/local/bin/node /usr/local/bin/node | |||||
COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules | |||||
COPY --from=node /usr/local/bin/npm /usr/local/bin/npm | |||||
COPY --from=node /opt/yarn-* /opt/yarn | |||||
RUN apk -U upgrade \ | RUN apk -U upgrade \ | ||||
&& apk add -t build-dependencies \ | && apk add -t build-dependencies \ | ||||
build-base \ | build-base \ | ||||
@@ -27,6 +31,8 @@ RUN apk -U upgrade \ | |||||
libidn-dev \ | libidn-dev \ | ||||
libressl \ | libressl \ | ||||
libtool \ | libtool \ | ||||
libxml2-dev \ | |||||
libxslt-dev \ | |||||
postgresql-dev \ | postgresql-dev \ | ||||
protobuf-dev \ | protobuf-dev \ | ||||
python \ | python \ | ||||
@@ -39,20 +45,15 @@ RUN apk -U upgrade \ | |||||
imagemagick \ | imagemagick \ | ||||
libidn \ | libidn \ | ||||
libpq \ | libpq \ | ||||
nodejs \ | |||||
nodejs-npm \ | |||||
libxml2 \ | |||||
libxslt \ | |||||
protobuf \ | protobuf \ | ||||
tini \ | tini \ | ||||
tzdata \ | tzdata \ | ||||
&& update-ca-certificates \ | && update-ca-certificates \ | ||||
&& 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" \ | |||||
&& echo "$YARN_DOWNLOAD_SHA256 *yarn.tar.gz" | sha256sum -c - \ | |||||
&& tar -xzf yarn.tar.gz -C /tmp/src \ | |||||
&& rm yarn.tar.gz \ | |||||
&& mv /tmp/src/yarn-v$YARN_VERSION /opt/yarn \ | |||||
&& ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \ | && ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \ | ||||
&& ln -s /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg \ | && ln -s /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg \ | ||||
&& mkdir -p /tmp/src /opt \ | |||||
&& wget -O libiconv.tar.gz "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-$LIBICONV_VERSION.tar.gz" \ | && wget -O libiconv.tar.gz "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-$LIBICONV_VERSION.tar.gz" \ | ||||
&& echo "$LIBICONV_DOWNLOAD_SHA256 *libiconv.tar.gz" | sha256sum -c - \ | && echo "$LIBICONV_DOWNLOAD_SHA256 *libiconv.tar.gz" | sha256sum -c - \ | ||||
&& tar -xzf libiconv.tar.gz -C /tmp/src \ | && tar -xzf libiconv.tar.gz -C /tmp/src \ | ||||
@@ -67,9 +68,9 @@ RUN apk -U upgrade \ | |||||
COPY Gemfile Gemfile.lock package.json yarn.lock .yarnclean /mastodon/ | COPY Gemfile Gemfile.lock package.json yarn.lock .yarnclean /mastodon/ | ||||
RUN bundle config build.nokogiri --with-iconv-lib=/usr/local/lib --with-iconv-include=/usr/local/include \ | |||||
RUN bundle config build.nokogiri --use-system-libraries --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 install --pure-lockfile --ignore-engines \ | |||||
&& yarn cache clean | && yarn cache clean | ||||
RUN addgroup -g ${GID} mastodon && adduser -h /mastodon -s /bin/sh -D -G mastodon -u ${UID} mastodon \ | RUN addgroup -g ${GID} mastodon && adduser -h /mastodon -s /bin/sh -D -G mastodon -u ${UID} mastodon \ | ||||
@@ -80,8 +81,10 @@ COPY . /mastodon | |||||
RUN chown -R mastodon:mastodon /mastodon | RUN chown -R mastodon:mastodon /mastodon | ||||
VOLUME /mastodon/public/system /mastodon/public/assets /mastodon/public/packs | |||||
VOLUME /mastodon/public/system | |||||
USER mastodon | USER mastodon | ||||
RUN OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile | |||||
ENTRYPOINT ["/sbin/tini", "--"] | ENTRYPOINT ["/sbin/tini", "--"] |
@@ -1,138 +1,139 @@ | |||||
# 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.4.0', '< 2.7.0' | |||||
gem 'pkg-config', '~> 1.3' | gem 'pkg-config', '~> 1.3' | ||||
gem 'puma', '~> 3.11' | |||||
gem 'rails', '~> 5.2.0' | |||||
gem 'puma', '~> 3.12' | |||||
gem 'rails', '~> 5.2.2' | |||||
gem 'thor', '~> 0.20' | |||||
gem 'hamlit-rails', '~> 0.2' | gem 'hamlit-rails', '~> 0.2' | ||||
gem 'pg', '~> 1.0' | |||||
gem 'pghero', '~> 2.1' | |||||
gem 'dotenv-rails', '~> 2.2', '< 2.3' | |||||
gem 'aws-sdk-s3', '~> 1.9', require: false | |||||
gem 'fog-core', '~> 1.45' | |||||
gem 'fog-local', '~> 0.5', require: false | |||||
gem 'fog-openstack', '~> 0.1', require: false | |||||
gem 'pg', '~> 1.1' | |||||
gem 'makara', '~> 0.4' | |||||
gem 'pghero', '~> 2.2' | |||||
gem 'dotenv-rails', '~> 2.6' | |||||
gem 'aws-sdk-s3', '~> 1.30', require: false | |||||
gem 'fog-core', '<= 2.1.0' | |||||
gem 'fog-openstack', '~> 0.3', require: false | |||||
gem 'paperclip', '~> 6.0' | gem 'paperclip', '~> 6.0' | ||||
gem 'paperclip-av-transcoder', '~> 0.6' | gem 'paperclip-av-transcoder', '~> 0.6' | ||||
gem 'streamio-ffmpeg', '~> 3.0' | gem 'streamio-ffmpeg', '~> 3.0' | ||||
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', '~> 1.3', require: false | |||||
gem 'browser' | gem 'browser' | ||||
gem 'charlock_holmes', '~> 0.7.6' | gem 'charlock_holmes', '~> 0.7.6' | ||||
gem 'iso-639' | gem 'iso-639' | ||||
gem 'chewy', '~> 5.0' | gem 'chewy', '~> 5.0' | ||||
gem 'cld3', '~> 3.2.0' | |||||
gem 'devise', '~> 4.4' | |||||
gem 'cld3', '~> 3.2.3' | |||||
gem 'devise', '~> 4.5' | |||||
gem 'devise-two-factor', '~> 3.0' | gem 'devise-two-factor', '~> 3.0' | ||||
group :pam_authentication, optional: true do | group :pam_authentication, optional: true do | ||||
gem 'devise_pam_authenticatable2', '~> 9.1' | |||||
gem 'devise_pam_authenticatable2', '~> 9.2' | |||||
end | end | ||||
gem 'net-ldap', '~> 0.10' | gem 'net-ldap', '~> 0.10' | ||||
gem 'omniauth-cas', '~> 1.1' | gem 'omniauth-cas', '~> 1.1' | ||||
gem 'omniauth-saml', '~> 1.10' | gem 'omniauth-saml', '~> 1.10' | ||||
gem 'omniauth', '~> 1.2' | |||||
gem 'omniauth', '~> 1.9' | |||||
gem 'doorkeeper', '~> 4.4' | |||||
gem 'doorkeeper', '~> 5.0' | |||||
gem 'fast_blank', '~> 1.0' | gem 'fast_blank', '~> 1.0' | ||||
gem 'fastimage' | gem 'fastimage' | ||||
gem 'goldfinger', '~> 2.1' | gem 'goldfinger', '~> 2.1' | ||||
gem 'hiredis', '~> 0.6' | gem 'hiredis', '~> 0.6' | ||||
gem 'redis-namespace', '~> 1.5' | gem 'redis-namespace', '~> 1.5' | ||||
gem 'htmlentities', '~> 4.3' | gem 'htmlentities', '~> 4.3' | ||||
gem 'http', '~> 3.2' | |||||
gem 'http', '~> 3.3' | |||||
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 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2' | ||||
gem 'httplog', '~> 1.0' | |||||
gem 'httplog', '~> 1.2' | |||||
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 'nokogiri', '~> 1.8' | |||||
gem 'mime-types', '~> 3.2', require: 'mime/types/columnar' | |||||
gem 'nokogiri', '~> 1.10' | |||||
gem 'nsa', '~> 0.2' | gem 'nsa', '~> 0.2' | ||||
gem 'oj', '~> 3.5' | |||||
gem 'oj', '~> 3.7' | |||||
gem 'ostatus2', '~> 2.0' | gem 'ostatus2', '~> 2.0' | ||||
gem 'ox', '~> 2.9' | |||||
gem 'ox', '~> 2.10' | |||||
gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c' | gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c' | ||||
gem 'pundit', '~> 1.1' | |||||
gem 'pundit', '~> 2.0' | |||||
gem 'premailer-rails' | gem 'premailer-rails' | ||||
gem 'rack-attack', '~> 5.2' | |||||
gem 'rack-attack', '~> 5.4' | |||||
gem 'rack-cors', '~> 1.0', require: 'rack/cors' | gem 'rack-cors', '~> 1.0', require: 'rack/cors' | ||||
gem 'rails-i18n', '~> 5.1' | gem 'rails-i18n', '~> 5.1' | ||||
gem 'rails-settings-cached', '~> 0.6' | gem 'rails-settings-cached', '~> 0.6' | ||||
gem 'redis', '~> 4.0', require: ['redis', 'redis/connection/hiredis'] | |||||
gem 'redis', '~> 4.1', 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 'sanitize', '~> 4.6' | |||||
gem 'sidekiq', '~> 5.1' | |||||
gem 'sidekiq-scheduler', '~> 2.2' | |||||
gem 'sidekiq-unique-jobs', '~> 5.0' | |||||
gem 'sidekiq-bulk', '~>0.1.1' | |||||
gem 'sanitize', '~> 5.0' | |||||
gem 'sidekiq', '~> 5.2' | |||||
gem 'sidekiq-scheduler', '~> 3.0' | |||||
gem 'sidekiq-unique-jobs', '~> 6.0' | |||||
gem 'sidekiq-bulk', '~>0.2.0' | |||||
gem 'simple-navigation', '~> 4.0' | gem 'simple-navigation', '~> 4.0' | ||||
gem 'simple_form', '~> 4.0' | |||||
gem 'simple_form', '~> 4.1' | |||||
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie' | gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie' | ||||
gem 'stoplight', '~> 2.1.3' | gem 'stoplight', '~> 2.1.3' | ||||
gem 'strong_migrations', '~> 0.2' | |||||
gem 'strong_migrations', '~> 0.3' | |||||
gem 'tty-command', '~> 0.8', require: false | gem 'tty-command', '~> 0.8', require: false | ||||
gem 'tty-prompt', '~> 0.16', require: false | |||||
gem 'tty-prompt', '~> 0.18', require: false | |||||
gem 'twitter-text', '~> 1.14' | gem 'twitter-text', '~> 1.14' | ||||
gem 'tzinfo-data', '~> 1.2018' | gem 'tzinfo-data', '~> 1.2018' | ||||
gem 'webpacker', '~> 3.4' | |||||
gem 'webpacker', '~> 3.5' | |||||
gem 'webpush' | gem 'webpush' | ||||
gem 'json-ld', '~> 2.2' | |||||
gem 'json-ld', '~> 3.0' | |||||
gem 'json-ld-preloaded', '~> 3.0' | |||||
gem 'rdf-normalize', '~> 0.3' | gem 'rdf-normalize', '~> 0.3' | ||||
group :development, :test do | group :development, :test do | ||||
gem 'fabrication', '~> 2.20' | gem 'fabrication', '~> 2.20' | ||||
gem 'fuubar', '~> 2.2' | |||||
gem 'fuubar', '~> 2.3' | |||||
gem 'i18n-tasks', '~> 0.9', require: false | gem 'i18n-tasks', '~> 0.9', require: false | ||||
gem 'pry-byebug', '~> 3.6' | gem 'pry-byebug', '~> 3.6' | ||||
gem 'pry-rails', '~> 0.3' | gem 'pry-rails', '~> 0.3' | ||||
gem 'rspec-rails', '~> 3.7' | |||||
gem 'rspec-rails', '~> 3.8' | |||||
end | end | ||||
group :production, :test do | group :production, :test do | ||||
gem 'private_address_check', '~> 0.4.1' | |||||
gem 'private_address_check', '~> 0.5' | |||||
end | end | ||||
group :test do | group :test do | ||||
gem 'capybara', '~> 2.18' | |||||
gem 'capybara', '~> 3.12' | |||||
gem 'climate_control', '~> 0.2' | gem 'climate_control', '~> 0.2' | ||||
gem 'faker', '~> 1.8' | |||||
gem 'faker', '~> 1.9' | |||||
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.16', require: false | ||||
gem 'webmock', '~> 3.3' | |||||
gem 'parallel_tests', '~> 2.21' | |||||
gem 'webmock', '~> 3.5' | |||||
gem 'parallel_tests', '~> 2.27' | |||||
end | end | ||||
group :development do | group :development do | ||||
gem 'active_record_query_trace', '~> 1.5' | gem 'active_record_query_trace', '~> 1.5' | ||||
gem 'annotate', '~> 2.7' | gem 'annotate', '~> 2.7' | ||||
gem 'better_errors', '~> 2.4' | |||||
gem 'better_errors', '~> 2.5' | |||||
gem 'binding_of_caller', '~> 0.7' | gem 'binding_of_caller', '~> 0.7' | ||||
gem 'bullet', '~> 5.7' | |||||
gem 'letter_opener', '~> 1.4' | |||||
gem 'bullet', '~> 5.9' | |||||
gem 'letter_opener', '~> 1.7' | |||||
gem 'letter_opener_web', '~> 1.3' | gem 'letter_opener_web', '~> 1.3' | ||||
gem 'memory_profiler' | gem 'memory_profiler' | ||||
gem 'rubocop', '~> 0.55', require: false | |||||
gem 'brakeman', '~> 4.2', require: false | |||||
gem 'rubocop', '~> 0.63', require: false | |||||
gem 'brakeman', '~> 4.4', 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.57', require: false | ||||
gem 'capistrano', '~> 3.10' | |||||
gem 'capistrano-rails', '~> 1.3' | |||||
gem 'capistrano', '~> 3.11' | |||||
gem 'capistrano-rails', '~> 1.4' | |||||
gem 'capistrano-rbenv', '~> 2.1' | gem 'capistrano-rbenv', '~> 2.1' | ||||
gem 'capistrano-yarn', '~> 2.0' | gem 'capistrano-yarn', '~> 2.0' | ||||
@@ -144,3 +145,5 @@ group :production do | |||||
gem 'lograge', '~> 0.10' | gem 'lograge', '~> 0.10' | ||||
gem 'redis-rails', '~> 5.0' | gem 'redis-rails', '~> 5.0' | ||||
end | end | ||||
gem 'concurrent-ruby', require: false |
@@ -15,49 +15,49 @@ GIT | |||||
GEM | GEM | ||||
remote: https://rubygems.org/ | remote: https://rubygems.org/ | ||||
specs: | specs: | ||||
actioncable (5.2.0) | |||||
actionpack (= 5.2.0) | |||||
actioncable (5.2.2) | |||||
actionpack (= 5.2.2) | |||||
nio4r (~> 2.0) | nio4r (~> 2.0) | ||||
websocket-driver (>= 0.6.1) | websocket-driver (>= 0.6.1) | ||||
actionmailer (5.2.0) | |||||
actionpack (= 5.2.0) | |||||
actionview (= 5.2.0) | |||||
activejob (= 5.2.0) | |||||
actionmailer (5.2.2) | |||||
actionpack (= 5.2.2) | |||||
actionview (= 5.2.2) | |||||
activejob (= 5.2.2) | |||||
mail (~> 2.5, >= 2.5.4) | mail (~> 2.5, >= 2.5.4) | ||||
rails-dom-testing (~> 2.0) | rails-dom-testing (~> 2.0) | ||||
actionpack (5.2.0) | |||||
actionview (= 5.2.0) | |||||
activesupport (= 5.2.0) | |||||
actionpack (5.2.2) | |||||
actionview (= 5.2.2) | |||||
activesupport (= 5.2.2) | |||||
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) | |||||
activesupport (= 5.2.0) | |||||
actionview (5.2.2) | |||||
activesupport (= 5.2.2) | |||||
builder (~> 3.1) | builder (~> 3.1) | ||||
erubi (~> 1.4) | erubi (~> 1.4) | ||||
rails-dom-testing (~> 2.0) | rails-dom-testing (~> 2.0) | ||||
rails-html-sanitizer (~> 1.0, >= 1.0.3) | rails-html-sanitizer (~> 1.0, >= 1.0.3) | ||||
active_model_serializers (0.10.7) | |||||
active_model_serializers (0.10.8) | |||||
actionpack (>= 4.1, < 6) | actionpack (>= 4.1, < 6) | ||||
activemodel (>= 4.1, < 6) | activemodel (>= 4.1, < 6) | ||||
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) | |||||
activesupport (= 5.2.0) | |||||
activejob (5.2.2) | |||||
activesupport (= 5.2.2) | |||||
globalid (>= 0.3.6) | globalid (>= 0.3.6) | ||||
activemodel (5.2.0) | |||||
activesupport (= 5.2.0) | |||||
activerecord (5.2.0) | |||||
activemodel (= 5.2.0) | |||||
activesupport (= 5.2.0) | |||||
activemodel (5.2.2) | |||||
activesupport (= 5.2.2) | |||||
activerecord (5.2.2) | |||||
activemodel (= 5.2.2) | |||||
activesupport (= 5.2.2) | |||||
arel (>= 9.0) | arel (>= 9.0) | ||||
activestorage (5.2.0) | |||||
actionpack (= 5.2.0) | |||||
activerecord (= 5.2.0) | |||||
activestorage (5.2.2) | |||||
actionpack (= 5.2.2) | |||||
activerecord (= 5.2.2) | |||||
marcel (~> 0.3.1) | marcel (~> 0.3.1) | ||||
activesupport (5.2.0) | |||||
activesupport (5.2.2) | |||||
concurrent-ruby (~> 1.0, >= 1.0.2) | concurrent-ruby (~> 1.0, >= 1.0.2) | ||||
i18n (>= 0.7, < 2) | i18n (>= 0.7, < 2) | ||||
minitest (~> 5.1) | minitest (~> 5.1) | ||||
@@ -66,7 +66,7 @@ GEM | |||||
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.4) | |||||
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 (9.0.0) | ||||
@@ -75,40 +75,42 @@ GEM | |||||
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-core (3.19.0) | |||||
aws-eventstream (1.0.1) | |||||
aws-partitions (1.131.0) | |||||
aws-sdk-core (3.45.0) | |||||
aws-eventstream (~> 1.0) | |||||
aws-partitions (~> 1.0) | aws-partitions (~> 1.0) | ||||
aws-sigv4 (~> 1.0) | aws-sigv4 (~> 1.0) | ||||
jmespath (~> 1.0) | jmespath (~> 1.0) | ||||
aws-sdk-kms (1.5.0) | |||||
aws-sdk-core (~> 3) | |||||
aws-sdk-kms (1.13.0) | |||||
aws-sdk-core (~> 3, >= 3.39.0) | |||||
aws-sigv4 (~> 1.0) | aws-sigv4 (~> 1.0) | ||||
aws-sdk-s3 (1.9.1) | |||||
aws-sdk-core (~> 3) | |||||
aws-sdk-s3 (1.30.1) | |||||
aws-sdk-core (~> 3, >= 3.39.0) | |||||
aws-sdk-kms (~> 1) | aws-sdk-kms (~> 1) | ||||
aws-sigv4 (~> 1.0) | aws-sigv4 (~> 1.0) | ||||
aws-sigv4 (1.0.2) | |||||
aws-sigv4 (1.0.3) | |||||
bcrypt (3.1.12) | bcrypt (3.1.12) | ||||
benchmark-ips (2.7.2) | benchmark-ips (2.7.2) | ||||
better_errors (2.4.0) | |||||
better_errors (2.5.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.8.0) | ||||
debug_inspector (>= 0.0.1) | debug_inspector (>= 0.0.1) | ||||
bootsnap (1.3.0) | |||||
bootsnap (1.3.2) | |||||
msgpack (~> 1.0) | msgpack (~> 1.0) | ||||
brakeman (4.2.1) | |||||
brakeman (4.4.0) | |||||
browser (2.5.3) | browser (2.5.3) | ||||
builder (3.2.3) | builder (3.2.3) | ||||
bullet (5.7.5) | |||||
bullet (5.9.0) | |||||
activesupport (>= 3.0.0) | activesupport (>= 3.0.0) | ||||
uniform_notifier (~> 1.11.0) | |||||
bundler-audit (0.6.0) | |||||
bundler (~> 1.2) | |||||
uniform_notifier (~> 1.11) | |||||
bundler-audit (0.6.1) | |||||
bundler (>= 1.2.0, < 3) | |||||
thor (~> 0.18) | thor (~> 0.18) | ||||
byebug (10.0.2) | byebug (10.0.2) | ||||
capistrano (3.10.2) | |||||
capistrano (3.11.0) | |||||
airbrussh (>= 1.0.0) | airbrussh (>= 1.0.0) | ||||
i18n | i18n | ||||
rake (>= 10.0.0) | rake (>= 10.0.0) | ||||
@@ -116,21 +118,22 @@ GEM | |||||
capistrano-bundler (1.3.0) | capistrano-bundler (1.3.0) | ||||
capistrano (~> 3.1) | capistrano (~> 3.1) | ||||
sshkit (~> 1.2) | sshkit (~> 1.2) | ||||
capistrano-rails (1.3.1) | |||||
capistrano-rails (1.4.0) | |||||
capistrano (~> 3.1) | capistrano (~> 3.1) | ||||
capistrano-bundler (~> 1.1) | capistrano-bundler (~> 1.1) | ||||
capistrano-rbenv (2.1.3) | |||||
capistrano-rbenv (2.1.4) | |||||
capistrano (~> 3.1) | capistrano (~> 3.1) | ||||
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 (3.12.0) | |||||
addressable | addressable | ||||
mini_mime (>= 0.1.3) | mini_mime (>= 0.1.3) | ||||
nokogiri (>= 1.3.3) | |||||
rack (>= 1.0.0) | |||||
rack-test (>= 0.5.4) | |||||
xpath (>= 2.0, < 4.0) | |||||
nokogiri (~> 1.8) | |||||
rack (>= 1.6.0) | |||||
rack-test (>= 0.6.3) | |||||
regexp_parser (~> 1.2) | |||||
xpath (~> 3.2) | |||||
case_transform (0.2) | case_transform (0.2) | ||||
activesupport | activesupport | ||||
charlock_holmes (0.7.6) | charlock_holmes (0.7.6) | ||||
@@ -139,22 +142,21 @@ GEM | |||||
elasticsearch (>= 2.0.0) | elasticsearch (>= 2.0.0) | ||||
elasticsearch-dsl | elasticsearch-dsl | ||||
chunky_png (1.3.10) | chunky_png (1.3.10) | ||||
cld3 (3.2.2) | |||||
cld3 (3.2.3) | |||||
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) | ||||
climate_control (>= 0.0.3, < 1.0) | climate_control (>= 0.0.3, < 1.0) | ||||
coderay (1.1.2) | coderay (1.1.2) | ||||
colorize (0.8.1) | |||||
concurrent-ruby (1.0.5) | |||||
connection_pool (2.2.1) | |||||
concurrent-ruby (1.1.4) | |||||
connection_pool (2.2.2) | |||||
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.4) | ||||
css_parser (1.6.0) | css_parser (1.6.0) | ||||
addressable | addressable | ||||
debug_inspector (0.0.3) | debug_inspector (0.0.3) | ||||
derailed_benchmarks (1.3.4) | |||||
derailed_benchmarks (1.3.5) | |||||
benchmark-ips (~> 2) | benchmark-ips (~> 2) | ||||
get_process_mem (~> 0) | get_process_mem (~> 0) | ||||
heapy (~> 0) | heapy (~> 0) | ||||
@@ -162,7 +164,7 @@ GEM | |||||
rack (>= 1) | rack (>= 1) | ||||
rake (> 10, < 13) | rake (> 10, < 13) | ||||
thor (~> 0.19) | thor (~> 0.19) | ||||
devise (4.4.3) | |||||
devise (4.5.0) | |||||
bcrypt (~> 3.0) | bcrypt (~> 3.0) | ||||
orm_adapter (~> 0.1) | orm_adapter (~> 0.1) | ||||
railties (>= 4.1.0, < 6.0) | railties (>= 4.1.0, < 6.0) | ||||
@@ -174,22 +176,19 @@ GEM | |||||
devise (~> 4.0) | devise (~> 4.0) | ||||
railties (< 5.3) | railties (< 5.3) | ||||
rotp (~> 2.0) | rotp (~> 2.0) | ||||
devise_pam_authenticatable2 (9.1.0) | |||||
devise_pam_authenticatable2 (9.2.0) | |||||
devise (>= 4.0.0) | devise (>= 4.0.0) | ||||
rpam2 (~> 4.0) | rpam2 (~> 4.0) | ||||
diff-lcs (1.3) | diff-lcs (1.3) | ||||
docile (1.3.0) | docile (1.3.0) | ||||
domain_name (0.5.20180417) | domain_name (0.5.20180417) | ||||
unf (>= 0.0.5, < 1.0.0) | unf (>= 0.0.5, < 1.0.0) | ||||
doorkeeper (4.4.2) | |||||
doorkeeper (5.0.2) | |||||
railties (>= 4.2) | railties (>= 4.2) | ||||
dotenv (2.2.2) | |||||
dotenv-rails (2.2.2) | |||||
dotenv (= 2.2.2) | |||||
dotenv (2.6.0) | |||||
dotenv-rails (2.6.0) | |||||
dotenv (= 2.6.0) | |||||
railties (>= 3.2, < 6.0) | railties (>= 3.2, < 6.0) | ||||
easy_translate (0.5.1) | |||||
thread | |||||
thread_safe | |||||
elasticsearch (6.0.2) | elasticsearch (6.0.2) | ||||
elasticsearch-api (= 6.0.2) | elasticsearch-api (= 6.0.2) | ||||
elasticsearch-transport (= 6.0.2) | elasticsearch-transport (= 6.0.2) | ||||
@@ -201,36 +200,38 @@ GEM | |||||
multi_json | multi_json | ||||
encryptor (3.0.0) | encryptor (3.0.0) | ||||
equatable (0.5.0) | equatable (0.5.0) | ||||
erubi (1.7.1) | |||||
et-orbi (1.1.0) | |||||
erubi (1.8.0) | |||||
et-orbi (1.1.6) | |||||
tzinfo | tzinfo | ||||
excon (0.62.0) | excon (0.62.0) | ||||
fabrication (2.20.1) | fabrication (2.20.1) | ||||
faker (1.8.7) | |||||
faker (1.9.1) | |||||
i18n (>= 0.7) | i18n (>= 0.7) | ||||
faraday (0.15.0) | faraday (0.15.0) | ||||
multipart-post (>= 1.2, < 3) | multipart-post (>= 1.2, < 3) | ||||
fast_blank (1.0.0) | fast_blank (1.0.0) | ||||
fastimage (2.1.1) | |||||
ffi (1.9.23) | |||||
fog-core (1.45.0) | |||||
fastimage (2.1.5) | |||||
ffi (1.9.25) | |||||
fog-core (2.1.0) | |||||
builder | builder | ||||
excon (~> 0.58) | excon (~> 0.58) | ||||
formatador (~> 0.2) | formatador (~> 0.2) | ||||
fog-json (1.0.2) | |||||
fog-core (~> 1.0) | |||||
mime-types | |||||
fog-json (1.2.0) | |||||
fog-core | |||||
multi_json (~> 1.10) | multi_json (~> 1.10) | ||||
fog-local (0.5.0) | |||||
fog-core (>= 1.27, < 3.0) | |||||
fog-openstack (0.1.25) | |||||
fog-core (~> 1.40) | |||||
fog-openstack (0.3.7) | |||||
fog-core (>= 1.45, <= 2.1.0) | |||||
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) | |||||
fugit (1.1.6) | |||||
et-orbi (~> 1.1, >= 1.1.6) | |||||
raabro (~> 1.1) | |||||
fuubar (2.3.2) | |||||
rspec-core (~> 3.0) | rspec-core (~> 3.0) | ||||
ruby-progressbar (~> 1.4) | ruby-progressbar (~> 1.4) | ||||
get_process_mem (0.2.1) | |||||
get_process_mem (0.2.3) | |||||
globalid (0.4.1) | globalid (0.4.1) | ||||
activesupport (>= 4.2.0) | activesupport (>= 4.2.0) | ||||
goldfinger (2.1.0) | goldfinger (2.1.0) | ||||
@@ -250,45 +251,49 @@ 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) | |||||
hiredis (0.6.1) | |||||
hitimes (1.2.6) | |||||
hashie (3.6.0) | |||||
heapy (0.1.4) | |||||
highline (2.0.0) | |||||
hiredis (0.6.3) | |||||
hkdf (0.3.0) | hkdf (0.3.0) | ||||
htmlentities (4.3.4) | htmlentities (4.3.4) | ||||
http (3.2.0) | |||||
http (3.3.0) | |||||
addressable (~> 2.3) | addressable (~> 2.3) | ||||
http-cookie (~> 1.0) | http-cookie (~> 1.0) | ||||
http-form_data (~> 2.0) | http-form_data (~> 2.0) | ||||
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 (2.1.1) | |||||
http_accept_language (2.1.1) | http_accept_language (2.1.1) | ||||
httplog (1.0.2) | |||||
colorize (~> 0.8) | |||||
httplog (1.2.0) | |||||
rack (>= 1.0) | rack (>= 1.0) | ||||
i18n (1.1.0) | |||||
rainbow (>= 2.0.0) | |||||
i18n (1.5.2) | |||||
concurrent-ruby (~> 1.0) | concurrent-ruby (~> 1.0) | ||||
i18n-tasks (0.9.21) | |||||
i18n-tasks (0.9.28) | |||||
activesupport (>= 4.0.2) | activesupport (>= 4.0.2) | ||||
ast (>= 2.1.0) | ast (>= 2.1.0) | ||||
easy_translate (>= 0.5.1) | |||||
erubi | erubi | ||||
highline (>= 1.7.3) | |||||
highline (>= 2.0.0) | |||||
i18n | i18n | ||||
parser (>= 2.2.3.0) | parser (>= 2.2.3.0) | ||||
rails-i18n | |||||
rainbow (>= 2.2.2, < 4.0) | rainbow (>= 2.2.2, < 4.0) | ||||
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) | ||||
jaro_winkler (1.5.2) | |||||
jmespath (1.4.0) | jmespath (1.4.0) | ||||
json (2.1.0) | json (2.1.0) | ||||
json-ld (2.2.1) | |||||
json-ld (3.0.2) | |||||
multi_json (~> 1.12) | multi_json (~> 1.12) | ||||
rdf (>= 2.2.8, < 4.0) | rdf (>= 2.2.8, < 4.0) | ||||
json-ld-preloaded (3.0.0) | |||||
json-ld (>= 2.2, < 4.0) | |||||
multi_json (~> 1.12) | |||||
rdf (~> 3.0) | |||||
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) | ||||
@@ -305,7 +310,7 @@ 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.7.0) | |||||
launchy (~> 2.2) | launchy (~> 2.2) | ||||
letter_opener_web (1.3.4) | letter_opener_web (1.3.4) | ||||
actionmailer (>= 3.2) | actionmailer (>= 3.2) | ||||
@@ -317,26 +322,28 @@ GEM | |||||
activesupport (>= 4) | activesupport (>= 4) | ||||
railties (>= 4) | railties (>= 4) | ||||
request_store (~> 1.0) | request_store (~> 1.0) | ||||
loofah (2.2.2) | |||||
loofah (2.2.3) | |||||
crass (~> 1.0.2) | crass (~> 1.0.2) | ||||
nokogiri (>= 1.5.9) | nokogiri (>= 1.5.9) | ||||
mail (2.7.0) | |||||
mail (2.7.1) | |||||
mini_mime (>= 0.1.1) | mini_mime (>= 0.1.1) | ||||
marcel (0.3.2) | |||||
makara (0.4.0) | |||||
activerecord (>= 3.0.0) | |||||
marcel (0.3.3) | |||||
mimemagic (~> 0.3.2) | mimemagic (~> 0.3.2) | ||||
mario-redis-lock (1.2.1) | mario-redis-lock (1.2.1) | ||||
redis (>= 3.0.5) | redis (>= 3.0.5) | ||||
memory_profiler (0.9.10) | |||||
method_source (0.9.0) | |||||
memory_profiler (0.9.12) | |||||
method_source (0.9.2) | |||||
microformats (4.0.7) | microformats (4.0.7) | ||||
json | json | ||||
nokogiri | nokogiri | ||||
mime-types (3.1) | |||||
mime-types (3.2.2) | |||||
mime-types-data (~> 3.2015) | mime-types-data (~> 3.2015) | ||||
mime-types-data (3.2016.0521) | |||||
mime-types-data (3.2018.0812) | |||||
mimemagic (0.3.2) | mimemagic (0.3.2) | ||||
mini_mime (1.0.0) | |||||
mini_portile2 (2.3.0) | |||||
mini_mime (1.0.1) | |||||
mini_portile2 (2.4.0) | |||||
minitest (5.11.3) | minitest (5.11.3) | ||||
msgpack (1.2.4) | msgpack (1.2.4) | ||||
multi_json (1.13.1) | multi_json (1.13.1) | ||||
@@ -345,26 +352,26 @@ GEM | |||||
net-ldap (0.16.1) | 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) | |||||
nio4r (2.3.0) | |||||
nokogiri (1.8.4) | |||||
mini_portile2 (~> 2.3.0) | |||||
nokogumbo (1.5.0) | |||||
nokogiri | |||||
nsa (0.2.4) | |||||
net-ssh (5.0.2) | |||||
nio4r (2.3.1) | |||||
nokogiri (1.10.1) | |||||
mini_portile2 (~> 2.4.0) | |||||
nokogumbo (2.0.0) | |||||
nokogiri (~> 1.8, >= 1.8.4) | |||||
nsa (0.2.7) | |||||
activesupport (>= 4.2, < 6) | activesupport (>= 4.2, < 6) | ||||
concurrent-ruby (~> 1.0.0) | |||||
sidekiq (>= 3.5.0) | |||||
statsd-ruby (~> 1.2.0) | |||||
oj (3.5.1) | |||||
omniauth (1.8.1) | |||||
hashie (>= 3.4.6, < 3.6.0) | |||||
concurrent-ruby (~> 1.0, >= 1.0.2) | |||||
sidekiq (>= 3.5) | |||||
statsd-ruby (~> 1.4, >= 1.4.0) | |||||
oj (3.7.7) | |||||
omniauth (1.9.0) | |||||
hashie (>= 3.4.6, < 3.7.0) | |||||
rack (>= 1.6.2, < 3) | rack (>= 1.6.2, < 3) | ||||
omniauth-cas (1.1.1) | omniauth-cas (1.1.1) | ||||
addressable (~> 2.3) | addressable (~> 2.3) | ||||
nokogiri (~> 1.5) | nokogiri (~> 1.5) | ||||
omniauth (~> 1.2) | omniauth (~> 1.2) | ||||
omniauth-saml (1.10.0) | |||||
omniauth-saml (1.10.1) | |||||
omniauth (~> 1.3, >= 1.3.2) | omniauth (~> 1.3, >= 1.3.2) | ||||
ruby-saml (~> 1.7) | ruby-saml (~> 1.7) | ||||
orm_adapter (0.5.0) | orm_adapter (0.5.0) | ||||
@@ -372,7 +379,7 @@ GEM | |||||
addressable (~> 2.5) | addressable (~> 2.5) | ||||
http (~> 3.0) | http (~> 3.0) | ||||
nokogiri (~> 1.8) | nokogiri (~> 1.8) | ||||
ox (2.9.2) | |||||
ox (2.10.0) | |||||
paperclip (6.0.0) | paperclip (6.0.0) | ||||
activemodel (>= 4.2.0) | activemodel (>= 4.2.0) | ||||
activesupport (>= 4.2.0) | activesupport (>= 4.2.0) | ||||
@@ -383,18 +390,18 @@ GEM | |||||
av (~> 0.9.0) | av (~> 0.9.0) | ||||
paperclip (>= 2.5.2) | paperclip (>= 2.5.2) | ||||
parallel (1.12.1) | parallel (1.12.1) | ||||
parallel_tests (2.21.3) | |||||
parallel_tests (2.27.1) | |||||
parallel | parallel | ||||
parser (2.5.1.0) | |||||
parser (2.6.0.0) | |||||
ast (~> 2.4.0) | ast (~> 2.4.0) | ||||
pastel (0.7.2) | pastel (0.7.2) | ||||
equatable (~> 0.5.0) | equatable (~> 0.5.0) | ||||
tty-color (~> 0.4.0) | tty-color (~> 0.4.0) | ||||
pg (1.0.0) | |||||
pghero (2.1.0) | |||||
pg (1.1.4) | |||||
pghero (2.2.0) | |||||
activerecord | activerecord | ||||
pkg-config (1.3.0) | |||||
powerpack (0.1.1) | |||||
pkg-config (1.3.2) | |||||
powerpack (0.1.2) | |||||
premailer (1.11.1) | premailer (1.11.1) | ||||
addressable | addressable | ||||
css_parser (>= 1.6.0) | css_parser (>= 1.6.0) | ||||
@@ -402,73 +409,74 @@ GEM | |||||
premailer-rails (1.10.2) | premailer-rails (1.10.2) | ||||
actionmailer (>= 3, < 6) | actionmailer (>= 3, < 6) | ||||
premailer (~> 1.7, >= 1.7.9) | premailer (~> 1.7, >= 1.7.9) | ||||
private_address_check (0.4.1) | |||||
pry (0.11.3) | |||||
private_address_check (0.5.0) | |||||
pry (0.12.2) | |||||
coderay (~> 1.1.0) | coderay (~> 1.1.0) | ||||
method_source (~> 0.9.0) | method_source (~> 0.9.0) | ||||
pry-byebug (3.6.0) | pry-byebug (3.6.0) | ||||
byebug (~> 10.0) | byebug (~> 10.0) | ||||
pry (~> 0.10) | pry (~> 0.10) | ||||
pry-rails (0.3.6) | |||||
pry-rails (0.3.9) | |||||
pry (>= 0.10.4) | pry (>= 0.10.4) | ||||
public_suffix (3.0.2) | |||||
puma (3.11.4) | |||||
pundit (1.1.0) | |||||
public_suffix (3.0.3) | |||||
puma (3.12.0) | |||||
pundit (2.0.0) | |||||
activesupport (>= 3.0.0) | activesupport (>= 3.0.0) | ||||
rack (2.0.5) | |||||
rack-attack (5.2.0) | |||||
rack | |||||
raabro (1.1.6) | |||||
rack (2.0.6) | |||||
rack-attack (5.4.2) | |||||
rack (>= 1.0, < 3) | |||||
rack-cors (1.0.2) | rack-cors (1.0.2) | ||||
rack-protection (2.0.1) | |||||
rack-protection (2.0.5) | |||||
rack | rack | ||||
rack-proxy (0.6.4) | rack-proxy (0.6.4) | ||||
rack | rack | ||||
rack-test (1.1.0) | rack-test (1.1.0) | ||||
rack (>= 1.0, < 3) | rack (>= 1.0, < 3) | ||||
rails (5.2.0) | |||||
actioncable (= 5.2.0) | |||||
actionmailer (= 5.2.0) | |||||
actionpack (= 5.2.0) | |||||
actionview (= 5.2.0) | |||||
activejob (= 5.2.0) | |||||
activemodel (= 5.2.0) | |||||
activerecord (= 5.2.0) | |||||
activestorage (= 5.2.0) | |||||
activesupport (= 5.2.0) | |||||
rails (5.2.2) | |||||
actioncable (= 5.2.2) | |||||
actionmailer (= 5.2.2) | |||||
actionpack (= 5.2.2) | |||||
actionview (= 5.2.2) | |||||
activejob (= 5.2.2) | |||||
activemodel (= 5.2.2) | |||||
activerecord (= 5.2.2) | |||||
activestorage (= 5.2.2) | |||||
activesupport (= 5.2.2) | |||||
bundler (>= 1.3.0) | bundler (>= 1.3.0) | ||||
railties (= 5.2.0) | |||||
railties (= 5.2.2) | |||||
sprockets-rails (>= 2.0.0) | sprockets-rails (>= 2.0.0) | ||||
rails-controller-testing (1.0.2) | |||||
actionpack (~> 5.x, >= 5.0.1) | |||||
actionview (~> 5.x, >= 5.0.1) | |||||
activesupport (~> 5.x) | |||||
rails-controller-testing (1.0.4) | |||||
actionpack (>= 5.0.1.x) | |||||
actionview (>= 5.0.1.x) | |||||
activesupport (>= 5.0.1.x) | |||||
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.4) | ||||
loofah (~> 2.2, >= 2.2.2) | loofah (~> 2.2, >= 2.2.2) | ||||
rails-i18n (5.1.1) | |||||
rails-i18n (5.1.2) | |||||
i18n (>= 0.7, < 2) | i18n (>= 0.7, < 2) | ||||
railties (>= 5.0, < 6) | railties (>= 5.0, < 6) | ||||
rails-settings-cached (0.6.6) | rails-settings-cached (0.6.6) | ||||
rails (>= 4.2.0) | rails (>= 4.2.0) | ||||
railties (5.2.0) | |||||
actionpack (= 5.2.0) | |||||
activesupport (= 5.2.0) | |||||
railties (5.2.2) | |||||
actionpack (= 5.2.2) | |||||
activesupport (= 5.2.2) | |||||
method_source | method_source | ||||
rake (>= 0.8.7) | rake (>= 0.8.7) | ||||
thor (>= 0.18.1, < 2.0) | |||||
thor (>= 0.19.0, < 2.0) | |||||
rainbow (3.0.0) | rainbow (3.0.0) | ||||
rake (12.3.1) | |||||
rake (12.3.2) | |||||
rb-fsevent (0.10.3) | rb-fsevent (0.10.3) | ||||
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 (3.0.9) | |||||
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.3) | ||||
rdf (>= 2.2, < 4.0) | rdf (>= 2.2, < 4.0) | ||||
redis (4.0.1) | |||||
redis (4.1.0) | |||||
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) | ||||
@@ -487,6 +495,7 @@ GEM | |||||
redis-store (>= 1.2, < 2) | redis-store (>= 1.2, < 2) | ||||
redis-store (1.5.0) | redis-store (1.5.0) | ||||
redis (>= 2.2, < 5) | redis (>= 2.2, < 5) | ||||
regexp_parser (1.3.0) | |||||
request_store (1.4.1) | request_store (1.4.1) | ||||
rack (>= 1.4) | rack (>= 1.4) | ||||
responders (2.4.0) | responders (2.4.0) | ||||
@@ -496,72 +505,73 @@ GEM | |||||
rpam2 (4.0.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-support (~> 3.7.0) | |||||
rspec-expectations (3.7.0) | |||||
rspec-core (3.8.0) | |||||
rspec-support (~> 3.8.0) | |||||
rspec-expectations (3.8.2) | |||||
diff-lcs (>= 1.2.0, < 2.0) | diff-lcs (>= 1.2.0, < 2.0) | ||||
rspec-support (~> 3.7.0) | |||||
rspec-mocks (3.7.0) | |||||
rspec-support (~> 3.8.0) | |||||
rspec-mocks (3.8.0) | |||||
diff-lcs (>= 1.2.0, < 2.0) | diff-lcs (>= 1.2.0, < 2.0) | ||||
rspec-support (~> 3.7.0) | |||||
rspec-rails (3.7.2) | |||||
rspec-support (~> 3.8.0) | |||||
rspec-rails (3.8.1) | |||||
actionpack (>= 3.0) | actionpack (>= 3.0) | ||||
activesupport (>= 3.0) | activesupport (>= 3.0) | ||||
railties (>= 3.0) | railties (>= 3.0) | ||||
rspec-core (~> 3.7.0) | |||||
rspec-expectations (~> 3.7.0) | |||||
rspec-mocks (~> 3.7.0) | |||||
rspec-support (~> 3.7.0) | |||||
rspec-core (~> 3.8.0) | |||||
rspec-expectations (~> 3.8.0) | |||||
rspec-mocks (~> 3.8.0) | |||||
rspec-support (~> 3.8.0) | |||||
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) | |||||
rubocop (0.55.0) | |||||
rspec-support (3.8.0) | |||||
rubocop (0.63.0) | |||||
jaro_winkler (~> 1.5.1) | |||||
parallel (~> 1.10) | parallel (~> 1.10) | ||||
parser (>= 2.5) | |||||
parser (>= 2.5, != 2.5.1.1) | |||||
powerpack (~> 0.1) | powerpack (~> 0.1) | ||||
rainbow (>= 2.2.2, < 4.0) | rainbow (>= 2.2.2, < 4.0) | ||||
ruby-progressbar (~> 1.7) | ruby-progressbar (~> 1.7) | ||||
unicode-display_width (~> 1.0, >= 1.0.1) | |||||
ruby-progressbar (1.9.0) | |||||
ruby-saml (1.7.2) | |||||
unicode-display_width (~> 1.4.0) | |||||
ruby-progressbar (1.10.0) | |||||
ruby-saml (1.9.0) | |||||
nokogiri (>= 1.5.10) | nokogiri (>= 1.5.10) | ||||
rufus-scheduler (3.4.2) | |||||
et-orbi (~> 1.0) | |||||
rufus-scheduler (3.5.2) | |||||
fugit (~> 1.1, >= 1.1.5) | |||||
safe_yaml (1.0.4) | safe_yaml (1.0.4) | ||||
sanitize (4.6.4) | |||||
sanitize (5.0.0) | |||||
crass (~> 1.0.2) | crass (~> 1.0.2) | ||||
nokogiri (>= 1.4.4) | |||||
nokogumbo (~> 1.4) | |||||
sass (3.5.6) | |||||
nokogiri (>= 1.8.0) | |||||
nokogumbo (~> 2.0) | |||||
sass (3.6.0) | |||||
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.57.1) | |||||
rake (>= 0.9, < 13) | rake (>= 0.9, < 13) | ||||
sass (~> 3.5.5) | |||||
sidekiq (5.1.3) | |||||
concurrent-ruby (~> 1.0) | |||||
connection_pool (~> 2.2, >= 2.2.0) | |||||
sass (~> 3.5, >= 3.5.5) | |||||
sidekiq (5.2.5) | |||||
connection_pool (~> 2.2, >= 2.2.2) | |||||
rack (>= 1.5.0) | |||||
rack-protection (>= 1.5.0) | rack-protection (>= 1.5.0) | ||||
redis (>= 3.3.5, < 5) | redis (>= 3.3.5, < 5) | ||||
sidekiq-bulk (0.1.1) | |||||
activesupport | |||||
sidekiq-bulk (0.2.0) | |||||
sidekiq | sidekiq | ||||
sidekiq-scheduler (2.2.1) | |||||
sidekiq-scheduler (3.0.0) | |||||
redis (>= 3, < 5) | redis (>= 3, < 5) | ||||
rufus-scheduler (~> 3.2) | rufus-scheduler (~> 3.2) | ||||
sidekiq (>= 3) | sidekiq (>= 3) | ||||
tilt (>= 1.4.0) | tilt (>= 1.4.0) | ||||
sidekiq-unique-jobs (5.0.10) | |||||
sidekiq (>= 4.0, <= 6.0) | |||||
sidekiq-unique-jobs (6.0.8) | |||||
concurrent-ruby (~> 1.0, >= 1.0.5) | |||||
sidekiq (>= 4.0, < 6.0) | |||||
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) | |||||
actionpack (> 4) | |||||
activemodel (> 4) | |||||
simple_form (4.1.0) | |||||
actionpack (>= 5.0) | |||||
activemodel (>= 5.0) | |||||
simplecov (0.16.1) | simplecov (0.16.1) | ||||
docile (~> 1.1) | docile (~> 1.1) | ||||
json (>= 1.8, < 3) | json (>= 1.8, < 3) | ||||
@@ -574,71 +584,69 @@ 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.17.0) | |||||
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) | |||||
stackprof (0.2.12) | |||||
statsd-ruby (1.4.0) | |||||
stoplight (2.1.3) | stoplight (2.1.3) | ||||
streamio-ffmpeg (3.0.2) | streamio-ffmpeg (3.0.2) | ||||
multi_json (~> 1.8) | multi_json (~> 1.8) | ||||
strong_migrations (0.2.2) | |||||
strong_migrations (0.3.1) | |||||
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) | terrapin (0.6.0) | ||||
climate_control (>= 0.0.3, < 1.0) | climate_control (>= 0.0.3, < 1.0) | ||||
thor (0.20.0) | |||||
thread (0.2.2) | |||||
thor (0.20.3) | |||||
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) | |||||
timers (4.2.0) | |||||
tty-color (0.4.3) | |||||
tty-command (0.8.2) | |||||
pastel (~> 0.7.0) | pastel (~> 0.7.0) | ||||
tty-cursor (0.5.0) | |||||
tty-prompt (0.16.0) | |||||
tty-cursor (0.6.0) | |||||
tty-prompt (0.18.1) | |||||
necromancer (~> 0.4.0) | necromancer (~> 0.4.0) | ||||
pastel (~> 0.7.0) | pastel (~> 0.7.0) | ||||
timers (~> 4.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-cursor (~> 0.6.0) | |||||
tty-reader (~> 0.5.0) | |||||
tty-reader (0.5.0) | |||||
tty-cursor (~> 0.6.0) | |||||
tty-screen (~> 0.6.4) | tty-screen (~> 0.6.4) | ||||
wisper (~> 2.0.0) | wisper (~> 2.0.0) | ||||
tty-screen (0.6.4) | |||||
tty-screen (0.6.5) | |||||
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.5) | ||||
thread_safe (~> 0.1) | thread_safe (~> 0.1) | ||||
tzinfo-data (1.2018.4) | |||||
tzinfo-data (1.2018.9) | |||||
tzinfo (>= 1.0.0) | tzinfo (>= 1.0.0) | ||||
unf (0.1.4) | unf (0.1.4) | ||||
unf_ext | unf_ext | ||||
unf_ext (0.0.7.5) | unf_ext (0.0.7.5) | ||||
unicode-display_width (1.3.2) | |||||
uniform_notifier (1.11.0) | |||||
unicode-display_width (1.4.1) | |||||
uniform_notifier (1.12.1) | |||||
warden (1.2.7) | warden (1.2.7) | ||||
rack (>= 1.0) | rack (>= 1.0) | ||||
webmock (3.3.0) | |||||
webmock (3.5.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.5.5) | |||||
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.6) | |||||
hkdf (~> 0.2) | hkdf (~> 0.2) | ||||
jwt (~> 2.0) | jwt (~> 2.0) | ||||
websocket-driver (0.7.0) | websocket-driver (0.7.0) | ||||
websocket-extensions (>= 0.1.0) | websocket-extensions (>= 0.1.0) | ||||
websocket-extensions (0.1.3) | websocket-extensions (0.1.3) | ||||
wisper (2.0.0) | wisper (2.0.0) | ||||
xpath (3.0.0) | |||||
xpath (3.2.0) | |||||
nokogiri (~> 1.8) | nokogiri (~> 1.8) | ||||
PLATFORMS | PLATFORMS | ||||
@@ -649,119 +657,121 @@ 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) | |||||
better_errors (~> 2.4) | |||||
aws-sdk-s3 (~> 1.30) | |||||
better_errors (~> 2.5) | |||||
binding_of_caller (~> 0.7) | binding_of_caller (~> 0.7) | ||||
bootsnap (~> 1.3) | bootsnap (~> 1.3) | ||||
brakeman (~> 4.2) | |||||
brakeman (~> 4.4) | |||||
browser | browser | ||||
bullet (~> 5.7) | |||||
bullet (~> 5.9) | |||||
bundler-audit (~> 0.6) | bundler-audit (~> 0.6) | ||||
capistrano (~> 3.10) | |||||
capistrano-rails (~> 1.3) | |||||
capistrano (~> 3.11) | |||||
capistrano-rails (~> 1.4) | |||||
capistrano-rbenv (~> 2.1) | capistrano-rbenv (~> 2.1) | ||||
capistrano-yarn (~> 2.0) | capistrano-yarn (~> 2.0) | ||||
capybara (~> 2.18) | |||||
capybara (~> 3.12) | |||||
charlock_holmes (~> 0.7.6) | charlock_holmes (~> 0.7.6) | ||||
chewy (~> 5.0) | chewy (~> 5.0) | ||||
cld3 (~> 3.2.0) | |||||
cld3 (~> 3.2.3) | |||||
climate_control (~> 0.2) | climate_control (~> 0.2) | ||||
concurrent-ruby | |||||
derailed_benchmarks | derailed_benchmarks | ||||
devise (~> 4.4) | |||||
devise (~> 4.5) | |||||
devise-two-factor (~> 3.0) | devise-two-factor (~> 3.0) | ||||
devise_pam_authenticatable2 (~> 9.1) | |||||
doorkeeper (~> 4.4) | |||||
dotenv-rails (~> 2.2, < 2.3) | |||||
devise_pam_authenticatable2 (~> 9.2) | |||||
doorkeeper (~> 5.0) | |||||
dotenv-rails (~> 2.6) | |||||
fabrication (~> 2.20) | fabrication (~> 2.20) | ||||
faker (~> 1.8) | |||||
faker (~> 1.9) | |||||
fast_blank (~> 1.0) | fast_blank (~> 1.0) | ||||
fastimage | fastimage | ||||
fog-core (~> 1.45) | |||||
fog-local (~> 0.5) | |||||
fog-openstack (~> 0.1) | |||||
fuubar (~> 2.2) | |||||
fog-core (<= 2.1.0) | |||||
fog-openstack (~> 0.3) | |||||
fuubar (~> 2.3) | |||||
goldfinger (~> 2.1) | goldfinger (~> 2.1) | ||||
hamlit-rails (~> 0.2) | hamlit-rails (~> 0.2) | ||||
hiredis (~> 0.6) | hiredis (~> 0.6) | ||||
htmlentities (~> 4.3) | htmlentities (~> 4.3) | ||||
http (~> 3.2) | |||||
http (~> 3.3) | |||||
http_accept_language (~> 2.1) | http_accept_language (~> 2.1) | ||||
http_parser.rb (~> 0.6)! | http_parser.rb (~> 0.6)! | ||||
httplog (~> 1.0) | |||||
httplog (~> 1.2) | |||||
i18n-tasks (~> 0.9) | i18n-tasks (~> 0.9) | ||||
idn-ruby | idn-ruby | ||||
iso-639 | iso-639 | ||||
json-ld (~> 2.2) | |||||
json-ld (~> 3.0) | |||||
json-ld-preloaded (~> 3.0) | |||||
kaminari (~> 1.1) | kaminari (~> 1.1) | ||||
letter_opener (~> 1.4) | |||||
letter_opener (~> 1.7) | |||||
letter_opener_web (~> 1.3) | letter_opener_web (~> 1.3) | ||||
link_header (~> 0.0) | link_header (~> 0.0) | ||||
lograge (~> 0.10) | lograge (~> 0.10) | ||||
makara (~> 0.4) | |||||
mario-redis-lock (~> 1.2) | mario-redis-lock (~> 1.2) | ||||
memory_profiler | memory_profiler | ||||
microformats (~> 4.0) | microformats (~> 4.0) | ||||
mime-types (~> 3.1) | |||||
mime-types (~> 3.2) | |||||
net-ldap (~> 0.10) | net-ldap (~> 0.10) | ||||
nokogiri (~> 1.8) | |||||
nokogiri (~> 1.10) | |||||
nsa (~> 0.2) | nsa (~> 0.2) | ||||
oj (~> 3.5) | |||||
omniauth (~> 1.2) | |||||
oj (~> 3.7) | |||||
omniauth (~> 1.9) | |||||
omniauth-cas (~> 1.1) | omniauth-cas (~> 1.1) | ||||
omniauth-saml (~> 1.10) | omniauth-saml (~> 1.10) | ||||
ostatus2 (~> 2.0) | ostatus2 (~> 2.0) | ||||
ox (~> 2.9) | |||||
ox (~> 2.10) | |||||
paperclip (~> 6.0) | paperclip (~> 6.0) | ||||
paperclip-av-transcoder (~> 0.6) | paperclip-av-transcoder (~> 0.6) | ||||
parallel_tests (~> 2.21) | |||||
pg (~> 1.0) | |||||
pghero (~> 2.1) | |||||
parallel_tests (~> 2.27) | |||||
pg (~> 1.1) | |||||
pghero (~> 2.2) | |||||
pkg-config (~> 1.3) | pkg-config (~> 1.3) | ||||
posix-spawn! | posix-spawn! | ||||
premailer-rails | premailer-rails | ||||
private_address_check (~> 0.4.1) | |||||
private_address_check (~> 0.5) | |||||
pry-byebug (~> 3.6) | pry-byebug (~> 3.6) | ||||
pry-rails (~> 0.3) | pry-rails (~> 0.3) | ||||
puma (~> 3.11) | |||||
pundit (~> 1.1) | |||||
rack-attack (~> 5.2) | |||||
puma (~> 3.12) | |||||
pundit (~> 2.0) | |||||
rack-attack (~> 5.4) | |||||
rack-cors (~> 1.0) | rack-cors (~> 1.0) | ||||
rails (~> 5.2.0) | |||||
rails (~> 5.2.2) | |||||
rails-controller-testing (~> 1.0) | rails-controller-testing (~> 1.0) | ||||
rails-i18n (~> 5.1) | rails-i18n (~> 5.1) | ||||
rails-settings-cached (~> 0.6) | rails-settings-cached (~> 0.6) | ||||
rdf-normalize (~> 0.3) | rdf-normalize (~> 0.3) | ||||
redis (~> 4.0) | |||||
redis (~> 4.1) | |||||
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.8) | |||||
rspec-sidekiq (~> 3.0) | rspec-sidekiq (~> 3.0) | ||||
rubocop (~> 0.55) | |||||
ruby-progressbar (~> 1.4) | |||||
sanitize (~> 4.6) | |||||
rubocop (~> 0.63) | |||||
sanitize (~> 5.0) | |||||
scss_lint (~> 0.57) | scss_lint (~> 0.57) | ||||
sidekiq (~> 5.1) | |||||
sidekiq-bulk (~> 0.1.1) | |||||
sidekiq-scheduler (~> 2.2) | |||||
sidekiq-unique-jobs (~> 5.0) | |||||
sidekiq (~> 5.2) | |||||
sidekiq-bulk (~> 0.2.0) | |||||
sidekiq-scheduler (~> 3.0) | |||||
sidekiq-unique-jobs (~> 6.0) | |||||
simple-navigation (~> 4.0) | simple-navigation (~> 4.0) | ||||
simple_form (~> 4.0) | |||||
simple_form (~> 4.1) | |||||
simplecov (~> 0.16) | simplecov (~> 0.16) | ||||
sprockets-rails (~> 3.2) | sprockets-rails (~> 3.2) | ||||
stackprof | stackprof | ||||
stoplight (~> 2.1.3) | stoplight (~> 2.1.3) | ||||
streamio-ffmpeg (~> 3.0) | streamio-ffmpeg (~> 3.0) | ||||
strong_migrations (~> 0.2) | |||||
strong_migrations (~> 0.3) | |||||
thor (~> 0.20) | |||||
tty-command (~> 0.8) | tty-command (~> 0.8) | ||||
tty-prompt (~> 0.16) | |||||
tty-prompt (~> 0.18) | |||||
twitter-text (~> 1.14) | twitter-text (~> 1.14) | ||||
tzinfo-data (~> 1.2018) | tzinfo-data (~> 1.2018) | ||||
webmock (~> 3.3) | |||||
webpacker (~> 3.4) | |||||
webmock (~> 3.5) | |||||
webpacker (~> 3.5) | |||||
webpush | webpush | ||||
RUBY VERSION | RUBY VERSION | ||||
ruby 2.5.0p0 | |||||
ruby 2.6.0p0 | |||||
BUNDLED WITH | BUNDLED WITH | ||||
1.16.3 | |||||
1.17.3 |
@@ -1,96 +1,95 @@ | |||||
![Mastodon](https://i.imgur.com/NhZc40l.png) | ![Mastodon](https://i.imgur.com/NhZc40l.png) | ||||
======== | ======== | ||||
[![GitHub release](https://img.shields.io/github/release/tootsuite/mastodon.svg)][releases] | |||||
[![Build Status](https://img.shields.io/circleci/project/github/tootsuite/mastodon.svg)][circleci] | [![Build Status](https://img.shields.io/circleci/project/github/tootsuite/mastodon.svg)][circleci] | ||||
[![Code Climate](https://img.shields.io/codeclimate/maintainability/tootsuite/mastodon.svg)][code_climate] | [![Code Climate](https://img.shields.io/codeclimate/maintainability/tootsuite/mastodon.svg)][code_climate] | ||||
[![Translation status](https://weblate.joinmastodon.org/widgets/mastodon/-/svg-badge.svg)][weblate] | |||||
[![Docker Pulls](https://img.shields.io/docker/pulls/tootsuite/mastodon.svg)][docker] | |||||
[releases]: https://github.com/tootsuite/mastodon/releases | |||||
[circleci]: https://circleci.com/gh/tootsuite/mastodon | [circleci]: https://circleci.com/gh/tootsuite/mastodon | ||||
[code_climate]: https://codeclimate.com/github/tootsuite/mastodon | [code_climate]: https://codeclimate.com/github/tootsuite/mastodon | ||||
[weblate]: https://weblate.joinmastodon.org/engage/mastodon/ | |||||
[docker]: https://hub.docker.com/r/tootsuite/mastodon/ | |||||
Mastodon is a **free, open-source social network server** based on **open web protocols** like ActivityPub and OStatus. The social focus of the project is a viable decentralized alternative to commercial social media silos that returns the control of the content distribution channels to the people. The technical focus of the project is a good user interface, a clean REST API for 3rd party apps and robust anti-abuse tools. | |||||
Mastodon is a **free, open-source social network server** based on ActivityPub. Follow friends and discover new ones. Publish anything you want: links, pictures, text, video. All servers of Mastodon are interoperable as a federated network, i.e. users on one server can seamlessly communicate with users from another one. This includes non-Mastodon software that also implements ActivityPub! | |||||
Click on the screenshot below to watch a demo of the UI: | |||||
Click below to **learn more** in a video: | |||||
[![Screenshot](https://i.imgur.com/qrNOiSp.png)][youtube_demo] | |||||
[![Screenshot](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/ezgif-2-60f1b00403.gif)][youtube_demo] | |||||
[youtube_demo]: https://www.youtube.com/watch?v=IPSbNdBmWKE | [youtube_demo]: https://www.youtube.com/watch?v=IPSbNdBmWKE | ||||
**Ruby on Rails** is used for the back-end, while **React.js** and Redux are used for the dynamic front-end. A static front-end for public resources (profiles and statuses) is also provided. | |||||
## Navigation | |||||
If you would like, you can [support the development of this project on Patreon][patreon] or [Liberapay][liberapay]. | |||||
- [Project homepage 🐘](https://joinmastodon.org) | |||||
- [Support the development via Patreon][patreon] | |||||
- [View sponsors](https://joinmastodon.org/sponsors) | |||||
- [Blog](https://blog.joinmastodon.org) | |||||
- [Documentation](https://docs.joinmastodon.org) | |||||
- [Browse Mastodon servers](https://joinmastodon.org/#getting-started) | |||||
- [Browse Mastodon apps](https://joinmastodon.org/apps) | |||||
[patreon]: https://www.patreon.com/user?u=619786 | |||||
[liberapay]: https://liberapay.com/Mastodon/ | |||||
--- | |||||
## Resources | |||||
- [Frequently Asked Questions](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md) | |||||
- [Use this tool to find Twitter friends on Mastodon](https://bridge.joinmastodon.org) | |||||
- [API overview](https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md) | |||||
- [List of Mastodon instances](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/List-of-Mastodon-instances.md) | |||||
- [List of apps](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md) | |||||
- [List of sponsors](https://joinmastodon.org/sponsors) | |||||
[patreon]: https://www.patreon.com/mastodon | |||||
## Features | ## Features | ||||
<img src="https://docs.joinmastodon.org/elephant.svg" align="right" width="30%" /> | |||||
**No vendor lock-in: Fully interoperable with any conforming platform** | **No vendor lock-in: Fully interoperable with any conforming platform** | ||||
It doesn't have to be Mastodon, whatever implements ActivityPub or OStatus is part of the social network! | |||||
It doesn't have to be Mastodon, whatever implements ActivityPub is part of the social network! [Learn more](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/) | |||||
**Real-time timeline updates** | |||||
**Real-time, chronological timeline updates** | |||||
See the updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well! | See the updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well! | ||||
**Federated thread resolving** | |||||
If someone you follow replies to a user unknown to the server, the server fetches the full thread so you can view it without leaving the UI | |||||
**Media attachments like images and short videos** | **Media attachments like images and short videos** | ||||
Upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos are looped - like vines! | Upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos are looped - like vines! | ||||
**OAuth2 and a straightforward REST API** | |||||
**Safety and moderation tools** | |||||
Mastodon acts as an OAuth2 provider so 3rd party apps can use the API | |||||
Private posts, locked accounts, phrase filtering, muting, blocking and all sorts of other features, along with a reporting and moderation system. [Learn more](https://blog.joinmastodon.org/2018/07/cage-the-mastodon/) | |||||
**Fast response times** | |||||
**OAuth2 and a straightforward REST API** | |||||
Mastodon tries to be as fast and responsive as possible, so all long-running tasks are delegated to background processing | |||||
Mastodon acts as an OAuth2 provider so 3rd party apps can use the REST and Streaming APIs, resulting in a rich app ecosystem with a lot of choice! | |||||
**Deployable via Docker** | |||||
## Deployment | |||||
You don't need to mess with dependencies and configuration if you want to try Mastodon, if you have Docker and Docker Compose the deployment is extremely easy | |||||
**Tech stack:** | |||||
--- | |||||
- **Ruby on Rails** powers the REST API and other web pages | |||||
- **React.js** and Redux are used for the dynamic parts of the interface | |||||
- **Node.js** powers the streaming API | |||||
## Development | |||||
**Requirements:** | |||||
Please follow the [development guide](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Development-guide.md) from the documentation repository. | |||||
- **PostgreSQL** 9.5+ | |||||
- **Redis** | |||||
- **Ruby** 2.4+ | |||||
- **Node.js** 8+ | |||||
## Deployment | |||||
The repository includes deployment configurations for **Docker and docker-compose**, but also a few specific platforms like **Heroku**, **Scalingo**, and **Nanobox**. The [**stand-alone** installation guide](https://docs.joinmastodon.org/administration/installation/) is available in the documentation. | |||||
There are guides in the documentation repository for [deploying on various platforms](https://github.com/tootsuite/documentation#running-mastodon). | |||||
A **Vagrant** configuration is included for development purposes. | |||||
## Contributing | ## Contributing | ||||
You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository. [Here are the guidelines for code contributions](CONTRIBUTING.md) | |||||
Mastodon is **free, open source software** licensed under **AGPLv3**. | |||||
You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository, or submit translations using Weblate. To get started, take a look at [CONTRIBUTING.md](CONTRIBUTING.md) | |||||
**IRC channel**: #mastodon on irc.freenode.net | **IRC channel**: #mastodon on irc.freenode.net | ||||
## License | ## License | ||||
Copyright (C) 2016-2018 Eugen Rochko & other Mastodon contributors (see AUTHORS.md) | |||||
Copyright (C) 2016-2018 Eugen Rochko & other Mastodon contributors (see [AUTHORS.md](AUTHORS.md)) | |||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. | This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. | ||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. | ||||
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. | You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
--- | |||||
## Extra credits | |||||
The elephant friend illustrations are created by [Dopatwo](https://mastodon.social/@dopatwo) |
@@ -12,7 +12,7 @@ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - | |||||
sudo apt-add-repository 'deb https://dl.yarnpkg.com/debian/ stable main' | sudo apt-add-repository 'deb https://dl.yarnpkg.com/debian/ stable main' | ||||
# Add repo for NodeJS | # Add repo for NodeJS | ||||
curl -sL https://deb.nodesource.com/setup_6.x | sudo bash - | |||||
curl -sL https://deb.nodesource.com/setup_8.x | sudo bash - | |||||
# Add firewall rule to redirect 80 to PORT and save | # Add firewall rule to redirect 80 to PORT and save | ||||
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{ENV["PORT"]} | sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{ENV["PORT"]} | ||||
@@ -44,7 +44,7 @@ sudo apt-get install \ | |||||
# Install rvm | # Install rvm | ||||
read RUBY_VERSION < .ruby-version | read RUBY_VERSION < .ruby-version | ||||
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 | |||||
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB | |||||
curl -sSL https://raw.githubusercontent.com/rvm/rvm/stable/binscripts/rvm-installer | bash -s stable --ruby=$RUBY_VERSION | curl -sSL https://raw.githubusercontent.com/rvm/rvm/stable/binscripts/rvm-installer | bash -s stable --ruby=$RUBY_VERSION | ||||
source /home/vagrant/.rvm/scripts/rvm | source /home/vagrant/.rvm/scripts/rvm | ||||
@@ -85,6 +85,9 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| | |||||
config.vm.provider :virtualbox do |vb| | config.vm.provider :virtualbox do |vb| | ||||
vb.name = "mastodon" | vb.name = "mastodon" | ||||
vb.customize ["modifyvm", :id, "--memory", "2048"] | vb.customize ["modifyvm", :id, "--memory", "2048"] | ||||
# Increase the number of CPUs. Uncomment and adjust to | |||||
# increase performance | |||||
# vb.customize ["modifyvm", :id, "--cpus", "3"] | |||||
# Disable VirtualBox DNS proxy to skip long-delay IPv6 resolutions. | # Disable VirtualBox DNS proxy to skip long-delay IPv6 resolutions. | ||||
# https://github.com/mitchellh/vagrant/issues/1172 | # https://github.com/mitchellh/vagrant/issues/1172 | ||||
@@ -97,19 +100,22 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| | |||||
end | end | ||||
config.vm.hostname = "mastodon.dev" | |||||
# This uses the vagrant-hostsupdater plugin, and lets you | # This uses the vagrant-hostsupdater plugin, and lets you | ||||
# access the development site at http://mastodon.dev. | |||||
# access the development site at http://mastodon.local. | |||||
# If you change it, also change it in .env.vagrant before provisioning | |||||
# the vagrant server to update the development build. | |||||
# | |||||
# To install: | # To install: | ||||
# $ vagrant plugin install vagrant-hostsupdater | # $ vagrant plugin install vagrant-hostsupdater | ||||
config.vm.hostname = "mastodon.local" | |||||
if defined?(VagrantPlugins::HostsUpdater) | if defined?(VagrantPlugins::HostsUpdater) | ||||
config.vm.network :private_network, ip: "192.168.42.42", nictype: "virtio" | config.vm.network :private_network, ip: "192.168.42.42", nictype: "virtio" | ||||
config.hostsupdater.remove_on_suspend = false | config.hostsupdater.remove_on_suspend = false | ||||
end | end | ||||
if config.vm.networks.any? { |type, options| type == :private_network } | if config.vm.networks.any? { |type, options| type == :private_network } | ||||
config.vm.synced_folder ".", "/vagrant", type: "nfs", mount_options: ['rw', 'vers=3', 'tcp'] | |||||
config.vm.synced_folder ".", "/vagrant", type: "nfs", mount_options: ['rw', 'vers=3', 'tcp', 'actimeo=1'] | |||||
else | else | ||||
config.vm.synced_folder ".", "/vagrant" | config.vm.synced_folder ".", "/vagrant" | ||||
end | end | ||||
@@ -31,7 +31,7 @@ class StatusesIndex < Chewy::Index | |||||
}, | }, | ||||
} | } | ||||
define_type ::Status.without_reblogs do | |||||
define_type ::Status.unscoped.without_reblogs do | |||||
crutch :mentions do |collection| | crutch :mentions do |collection| | ||||
data = ::Mention.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id) | data = ::Mention.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id) | ||||
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) } | data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) } | ||||
@@ -9,9 +9,13 @@ class AboutController < ApplicationController | |||||
@initial_state_json = serializable_resource.to_json | @initial_state_json = serializable_resource.to_json | ||||
end | end | ||||
def more; end | |||||
def more | |||||
render layout: 'public' | |||||
end | |||||
def terms; end | |||||
def terms | |||||
render layout: 'public' | |||||
end | |||||
private | private | ||||
@@ -26,7 +30,7 @@ class AboutController < ApplicationController | |||||
end | end | ||||
def set_body_classes | def set_body_classes | ||||
@body_classes = 'about-body' | |||||
@body_classes = 'with-modals' | |||||
end | end | ||||
def initial_state_params | def initial_state_params | ||||
@@ -10,7 +10,9 @@ class AccountsController < ApplicationController | |||||
def show | def show | ||||
respond_to do |format| | respond_to do |format| | ||||
format.html do | format.html do | ||||
@pinned_statuses = [] | |||||
@body_classes = 'with-modals' | |||||
@pinned_statuses = [] | |||||
@endorsed_accounts = @account.endorsed_accounts.to_a.sample(4) | |||||
if current_account && @account.blocking?(current_account) | if current_account && @account.blocking?(current_account) | ||||
@statuses = [] | @statuses = [] | ||||
@@ -40,7 +42,7 @@ class AccountsController < ApplicationController | |||||
format.json do | format.json do | ||||
skip_session! | skip_session! | ||||
render_cached_json(['activitypub', 'actor', @account.cache_key], content_type: 'application/activity+json') do | |||||
render_cached_json(['activitypub', 'actor', @account], content_type: 'application/activity+json') do | |||||
ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter) | ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter) | ||||
end | end | ||||
end | end | ||||
@@ -50,7 +52,7 @@ class AccountsController < ApplicationController | |||||
private | private | ||||
def show_pinned_statuses? | def show_pinned_statuses? | ||||
[replies_requested?, media_requested?, params[:max_id].present?, params[:since_id].present?].none? | |||||
[replies_requested?, media_requested?, params[:max_id].present?, params[:min_id].present?].none? | |||||
end | end | ||||
def filtered_statuses | def filtered_statuses | ||||
@@ -31,7 +31,7 @@ class ActivityPub::CollectionsController < Api::BaseController | |||||
when 'featured' | when 'featured' | ||||
@account.pinned_statuses.count | @account.pinned_statuses.count | ||||
else | else | ||||
raise ActiveRecord::NotFound | |||||
raise ActiveRecord::RecordNotFound | |||||
end | end | ||||
end | end | ||||
@@ -42,7 +42,7 @@ class ActivityPub::CollectionsController < Api::BaseController | |||||
scope.merge!(@account.pinned_statuses) | scope.merge!(@account.pinned_statuses) | ||||
end | end | ||||
else | else | ||||
raise ActiveRecord::NotFound | |||||
raise ActiveRecord::RecordNotFound | |||||
end | end | ||||
end | end | ||||
@@ -36,6 +36,6 @@ class ActivityPub::InboxesController < Api::BaseController | |||||
end | end | ||||
def process_payload | def process_payload | ||||
ActivityPub::ProcessingWorker.perform_async(signed_request_account.id, body.force_encoding('UTF-8')) | |||||
ActivityPub::ProcessingWorker.perform_async(signed_request_account.id, body.force_encoding('UTF-8'), @account&.id) | |||||
end | end | ||||
end | end |
@@ -0,0 +1,36 @@ | |||||
# frozen_string_literal: true | |||||
module Admin | |||||
class AccountActionsController < BaseController | |||||
before_action :set_account | |||||
def new | |||||
@account_action = Admin::AccountAction.new(type: params[:type], report_id: params[:report_id], send_email_notification: true) | |||||
@warning_presets = AccountWarningPreset.all | |||||
end | |||||
def create | |||||
account_action = Admin::AccountAction.new(resource_params) | |||||
account_action.target_account = @account | |||||
account_action.current_account = current_account | |||||
account_action.save! | |||||
if account_action.with_report? | |||||
redirect_to admin_reports_path | |||||
else | |||||
redirect_to admin_account_path(@account.id) | |||||
end | |||||
end | |||||
private | |||||
def set_account | |||||
@account = Account.find(params[:account_id]) | |||||
end | |||||
def resource_params | |||||
params.require(:admin_account_action).permit(:type, :report_id, :warning_preset_id, :text, :send_email_notification) | |||||
end | |||||
end | |||||
end |
@@ -14,6 +14,7 @@ module Admin | |||||
else | else | ||||
@account = @account_moderation_note.target_account | @account = @account_moderation_note.target_account | ||||
@moderation_notes = @account.targeted_moderation_notes.latest | @moderation_notes = @account.targeted_moderation_notes.latest | ||||
@warnings = @account.targeted_account_warnings.latest.custom | |||||
render template: 'admin/accounts/show' | render template: 'admin/accounts/show' | ||||
end | end | ||||
@@ -2,9 +2,9 @@ | |||||
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, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :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, :memorialize] | |||||
def index | def index | ||||
authorize :account, :index? | authorize :account, :index? | ||||
@@ -13,8 +13,10 @@ module Admin | |||||
def show | def show | ||||
authorize @account, :show? | authorize @account, :show? | ||||
@account_moderation_note = current_account.account_moderation_notes.new(target_account: @account) | @account_moderation_note = current_account.account_moderation_notes.new(target_account: @account) | ||||
@moderation_notes = @account.targeted_moderation_notes.latest | |||||
@moderation_notes = @account.targeted_moderation_notes.latest | |||||
@warnings = @account.targeted_account_warnings.latest.custom | |||||
end | end | ||||
def subscribe | def subscribe | ||||
@@ -43,19 +45,25 @@ module Admin | |||||
redirect_to admin_account_path(@account.id) | redirect_to admin_account_path(@account.id) | ||||
end | end | ||||
def disable | |||||
authorize @account.user, :disable? | |||||
@account.user.disable! | |||||
log_action :disable, @account.user | |||||
def unsilence | |||||
authorize @account, :unsilence? | |||||
@account.unsilence! | |||||
log_action :unsilence, @account | |||||
redirect_to admin_account_path(@account.id) | |||||
end | |||||
def unsuspend | |||||
authorize @account, :unsuspend? | |||||
@account.unsuspend! | |||||
log_action :unsuspend, @account | |||||
redirect_to admin_account_path(@account.id) | redirect_to admin_account_path(@account.id) | ||||
end | end | ||||
def redownload | def redownload | ||||
authorize @account, :redownload? | authorize @account, :redownload? | ||||
@account.reset_avatar! | |||||
@account.reset_header! | |||||
@account.save! | |||||
@account.update!(last_webfingered_at: nil) | |||||
ResolveAccountService.new.call(@account) | |||||
redirect_to admin_account_path(@account.id) | redirect_to admin_account_path(@account.id) | ||||
end | end | ||||
@@ -71,6 +79,17 @@ module Admin | |||||
redirect_to admin_account_path(@account.id) | redirect_to admin_account_path(@account.id) | ||||
end | end | ||||
def remove_header | |||||
authorize @account, :remove_header? | |||||
@account.header = nil | |||||
@account.save! | |||||
log_action :remove_header, @account.user | |||||
redirect_to admin_account_path(@account.id) | |||||
end | |||||
private | private | ||||
def set_account | def set_account | ||||
@@ -94,8 +113,8 @@ module Admin | |||||
:local, | :local, | ||||
:remote, | :remote, | ||||
:by_domain, | :by_domain, | ||||
:active, | |||||
:silenced, | :silenced, | ||||
:recent, | |||||
:suspended, | :suspended, | ||||
:username, | :username, | ||||
:display_name, | :display_name, | ||||
@@ -5,8 +5,19 @@ module Admin | |||||
include Authorization | include Authorization | ||||
include AccountableConcern | include AccountableConcern | ||||
layout 'admin' | |||||
before_action :require_staff! | before_action :require_staff! | ||||
before_action :set_body_classes | |||||
layout 'admin' | |||||
private | |||||
def set_body_classes | |||||
@body_classes = 'admin' | |||||
end | |||||
def set_user | |||||
@user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) | |||||
end | |||||
end | end | ||||
end | end |
@@ -25,10 +25,6 @@ module Admin | |||||
private | private | ||||
def set_user | |||||
@user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) | |||||
end | |||||
def check_confirmation | def check_confirmation | ||||
if @user.confirmed? | if @user.confirmed? | ||||
flash[:error] = I18n.t('admin.accounts.resend_confirmation.already_confirmed') | flash[:error] = I18n.t('admin.accounts.resend_confirmation.already_confirmed') | ||||
@@ -0,0 +1,44 @@ | |||||
# frozen_string_literal: true | |||||
require 'sidekiq/api' | |||||
module Admin | |||||
class DashboardController < BaseController | |||||
def index | |||||
@users_count = User.count | |||||
@registrations_week = Redis.current.get("activity:accounts:local:#{current_week}") || 0 | |||||
@logins_week = Redis.current.pfcount("activity:logins:#{current_week}") | |||||
@interactions_week = Redis.current.get("activity:interactions:#{current_week}") || 0 | |||||
@relay_enabled = Relay.enabled.exists? | |||||
@single_user_mode = Rails.configuration.x.single_user_mode | |||||
@registrations_enabled = Setting.open_registrations | |||||
@deletions_enabled = Setting.open_deletion | |||||
@invites_enabled = Setting.min_invite_role == 'user' | |||||
@search_enabled = Chewy.enabled? | |||||
@version = Mastodon::Version.to_s | |||||
@database_version = ActiveRecord::Base.connection.execute('SELECT VERSION()').first['version'].match(/\A(?:PostgreSQL |)([^\s]+).*\z/)[1] | |||||
@redis_version = redis_info['redis_version'] | |||||
@reports_count = Report.unresolved.count | |||||
@queue_backlog = Sidekiq::Stats.new.enqueued | |||||
@recent_users = User.confirmed.recent.includes(:account).limit(4) | |||||
@database_size = ActiveRecord::Base.connection.execute('SELECT pg_database_size(current_database())').first['pg_database_size'] | |||||
@redis_size = redis_info['used_memory'] | |||||
@ldap_enabled = ENV['LDAP_ENABLED'] == 'true' | |||||
@cas_enabled = ENV['CAS_ENABLED'] == 'true' | |||||
@saml_enabled = ENV['SAML_ENABLED'] == 'true' | |||||
@pam_enabled = ENV['PAM_ENABLED'] == 'true' | |||||
@hidden_service = ENV['ALLOW_ACCESS_TO_HIDDEN_SERVICE'] == 'true' | |||||
@trending_hashtags = TrendingTags.get(7) | |||||
@profile_directory = Setting.profile_directory | |||||
end | |||||
private | |||||
def current_week | |||||
@current_week ||= Time.now.utc.to_date.cweek | |||||
end | |||||
def redis_info | |||||
@redis_info ||= Redis.current.info | |||||
end | |||||
end | |||||
end |
@@ -4,14 +4,9 @@ module Admin | |||||
class DomainBlocksController < BaseController | class DomainBlocksController < BaseController | ||||
before_action :set_domain_block, only: [:show, :destroy] | before_action :set_domain_block, only: [:show, :destroy] | ||||
def index | |||||
authorize :domain_block, :index? | |||||
@domain_blocks = DomainBlock.page(params[:page]) | |||||
end | |||||
def new | def new | ||||
authorize :domain_block, :create? | authorize :domain_block, :create? | ||||
@domain_block = DomainBlock.new | |||||
@domain_block = DomainBlock.new(domain: params[:_domain]) | |||||
end | end | ||||
def create | def create | ||||
@@ -22,7 +17,7 @@ module Admin | |||||
if @domain_block.save | if @domain_block.save | ||||
DomainBlockWorker.perform_async(@domain_block.id) | DomainBlockWorker.perform_async(@domain_block.id) | ||||
log_action :create, @domain_block | log_action :create, @domain_block | ||||
redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.created_msg') | |||||
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg') | |||||
else | else | ||||
render :new | render :new | ||||
end | end | ||||
@@ -36,7 +31,7 @@ module Admin | |||||
authorize @domain_block, :destroy? | authorize @domain_block, :destroy? | ||||
UnblockDomainService.new.call(@domain_block, retroactive_unblock?) | UnblockDomainService.new.call(@domain_block, retroactive_unblock?) | ||||
log_action :destroy, @domain_block | log_action :destroy, @domain_block | ||||
redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.destroyed_msg') | |||||
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.destroyed_msg') | |||||
end | end | ||||
private | private | ||||
@@ -46,7 +41,7 @@ module Admin | |||||
end | end | ||||
def resource_params | def resource_params | ||||
params.require(:domain_block).permit(:domain, :severity, :reject_media, :retroactive) | |||||
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :retroactive) | |||||
end | end | ||||
def retroactive_unblock? | def retroactive_unblock? | ||||
@@ -0,0 +1,18 @@ | |||||
# frozen_string_literal: true | |||||
module Admin | |||||
class FollowersController < BaseController | |||||
before_action :set_account | |||||
PER_PAGE = 40 | |||||
def index | |||||
authorize :account, :index? | |||||
@followers = @account.followers.local.recent.page(params[:page]).per(PER_PAGE) | |||||
end | |||||
def set_account | |||||
@account = Account.find(params[:account_id]) | |||||
end | |||||
end | |||||
end |
@@ -4,14 +4,21 @@ module Admin | |||||
class InstancesController < BaseController | class InstancesController < BaseController | ||||
def index | def index | ||||
authorize :instance, :index? | authorize :instance, :index? | ||||
@instances = ordered_instances | @instances = ordered_instances | ||||
end | end | ||||
def resubscribe | |||||
authorize :instance, :resubscribe? | |||||
params.require(:by_domain) | |||||
Pubsubhubbub::SubscribeWorker.push_bulk(subscribeable_accounts.pluck(:id)) | |||||
redirect_to admin_instances_path | |||||
def show | |||||
authorize :instance, :show? | |||||
@instance = Instance.new(Account.by_domain_accounts.find_by(domain: params[:id]) || DomainBlock.find_by!(domain: params[:id])) | |||||
@following_count = Follow.where(account: Account.where(domain: params[:id])).count | |||||
@followers_count = Follow.where(target_account: Account.where(domain: params[:id])).count | |||||
@reports_count = Report.where(target_account: Account.where(domain: params[:id])).count | |||||
@blocks_count = Block.where(target_account: Account.where(domain: params[:id])).count | |||||
@available = DeliveryFailureTracker.available?(Account.select(:shared_inbox_url).where(domain: params[:id]).first&.shared_inbox_url) | |||||
@media_storage = MediaAttachment.where(account: Account.where(domain: params[:id])).sum(:file_file_size) | |||||
@domain_block = DomainBlock.find_by(domain: params[:id]) | |||||
end | end | ||||
private | private | ||||
@@ -27,17 +34,11 @@ module Admin | |||||
helper_method :paginated_instances | helper_method :paginated_instances | ||||
def ordered_instances | def ordered_instances | ||||
paginated_instances.map { |account| Instance.new(account) } | |||||
end | |||||
def subscribeable_accounts | |||||
Account.with_followers.remote.where(domain: params[:by_domain]) | |||||
paginated_instances.map { |resource| Instance.new(resource) } | |||||
end | end | ||||
def filter_params | def filter_params | ||||
params.permit( | |||||
:domain_name | |||||
) | |||||
params.permit(:limited) | |||||
end | end | ||||
end | end | ||||
end | end |
@@ -30,6 +30,12 @@ module Admin | |||||
redirect_to admin_invites_path | redirect_to admin_invites_path | ||||
end | end | ||||
def deactivate_all | |||||
authorize :invite, :deactivate_all? | |||||
Invite.available.in_batches.update_all(expires_at: Time.now.utc) | |||||
redirect_to admin_invites_path | |||||
end | |||||
private | private | ||||
def resource_params | def resource_params | ||||
@@ -0,0 +1,58 @@ | |||||
# frozen_string_literal: true | |||||
module Admin | |||||
class RelaysController < BaseController | |||||
before_action :set_relay, except: [:index, :new, :create] | |||||
def index | |||||
authorize :relay, :update? | |||||
@relays = Relay.all | |||||
end | |||||
def new | |||||
authorize :relay, :update? | |||||
@relay = Relay.new(inbox_url: Relay::PRESET_RELAY) | |||||
end | |||||
def create | |||||
authorize :relay, :update? | |||||
@relay = Relay.new(resource_params) | |||||
if @relay.save | |||||
@relay.enable! | |||||
redirect_to admin_relays_path | |||||
else | |||||
render action: :new | |||||
end | |||||
end | |||||
def destroy | |||||
authorize :relay, :update? | |||||
@relay.destroy | |||||
redirect_to admin_relays_path | |||||
end | |||||
def enable | |||||
authorize :relay, :update? | |||||
@relay.enable! | |||||
redirect_to admin_relays_path | |||||
end | |||||
def disable | |||||
authorize :relay, :update? | |||||
@relay.disable! | |||||
redirect_to admin_relays_path | |||||
end | |||||
private | |||||
def set_relay | |||||
@relay = Relay.find(params[:id]) | |||||
end | |||||
def resource_params | |||||
params.require(:relay).permit(:inbox_url) | |||||
end | |||||
end | |||||
end |
@@ -13,72 +13,42 @@ module Admin | |||||
authorize @report, :show? | authorize @report, :show? | ||||
@report_note = @report.notes.new | @report_note = @report.notes.new | ||||
@report_notes = (@report.notes.latest + @report.history).sort_by(&:created_at) | |||||
@report_notes = (@report.notes.latest + @report.history + @report.target_account.targeted_account_warnings.latest.custom).sort_by(&:created_at) | |||||
@form = Form::StatusBatch.new | @form = Form::StatusBatch.new | ||||
end | end | ||||
def update | |||||
def assign_to_self | |||||
authorize @report, :update? | authorize @report, :update? | ||||
process_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 | |||||
@report.update!(assigned_account_id: current_account.id) | |||||
log_action :assigned_to_self, @report | |||||
redirect_to admin_report_path(@report) | |||||
end | end | ||||
private | |||||
def process_report | |||||
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' | |||||
@report.resolve!(current_account) | |||||
log_action :resolve, @report | |||||
when 'suspend' | |||||
Admin::SuspensionWorker.perform_async(@report.target_account.id) | |||||
log_action :resolve, @report | |||||
log_action :suspend, @report.target_account | |||||
resolve_all_target_account_reports | |||||
when 'silence' | |||||
@report.target_account.update!(silenced: true) | |||||
log_action :resolve, @report | |||||
log_action :silence, @report.target_account | |||||
resolve_all_target_account_reports | |||||
else | |||||
raise ActiveRecord::RecordNotFound | |||||
end | |||||
@report.reload | |||||
def unassign | |||||
authorize @report, :update? | |||||
@report.update!(assigned_account_id: nil) | |||||
log_action :unassigned, @report | |||||
redirect_to admin_report_path(@report) | |||||
end | end | ||||
def resolve_all_target_account_reports | |||||
unresolved_reports_for_target_account.update_all(action_taken: true, action_taken_by_account_id: current_account.id) | |||||
def reopen | |||||
authorize @report, :update? | |||||
@report.unresolve! | |||||
log_action :reopen, @report | |||||
redirect_to admin_report_path(@report) | |||||
end | end | ||||
def unresolved_reports_for_target_account | |||||
Report.where( | |||||
target_account: @report.target_account | |||||
).unresolved | |||||
def resolve | |||||
authorize @report, :update? | |||||
@report.resolve!(current_account) | |||||
log_action :resolve, @report | |||||
redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg') | |||||
end | end | ||||
private | |||||
def filtered_reports | def filtered_reports | ||||
ReportFilter.new(filter_params).results.order(id: :desc).includes( | |||||
:account, | |||||
:target_account | |||||
) | |||||
ReportFilter.new(filter_params).results.order(id: :desc).includes(:account, :target_account) | |||||
end | end | ||||
def filter_params | def filter_params | ||||
@@ -10,11 +10,5 @@ module Admin | |||||
log_action :reset_password, @user | log_action :reset_password, @user | ||||
redirect_to admin_accounts_path | redirect_to admin_accounts_path | ||||
end | end | ||||
private | |||||
def set_user | |||||
@user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) | |||||
end | |||||
end | end | ||||
end | end |
@@ -17,11 +17,5 @@ module Admin | |||||
log_action :demote, @user | log_action :demote, @user | ||||
redirect_to admin_account_path(@user.account_id) | redirect_to admin_account_path(@user.account_id) | ||||
end | end | ||||
private | |||||
def set_user | |||||
@user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) | |||||
end | |||||
end | end | ||||
end | end |
@@ -6,6 +6,7 @@ module Admin | |||||
site_contact_username | site_contact_username | ||||
site_contact_email | site_contact_email | ||||
site_title | site_title | ||||
site_short_description | |||||
site_description | site_description | ||||
site_extended_description | site_extended_description | ||||
site_terms | site_terms | ||||
@@ -15,13 +16,17 @@ module Admin | |||||
timeline_preview | timeline_preview | ||||
show_staff_badge | show_staff_badge | ||||
bootstrap_timeline_accounts | bootstrap_timeline_accounts | ||||
theme | |||||
thumbnail | thumbnail | ||||
hero | hero | ||||
mascot | |||||
min_invite_role | min_invite_role | ||||
activity_api_enabled | activity_api_enabled | ||||
peers_api_enabled | peers_api_enabled | ||||
show_known_fediverse_at_about_page | show_known_fediverse_at_about_page | ||||
preview_sensitive_media | preview_sensitive_media | ||||
custom_css | |||||
profile_directory | |||||
).freeze | ).freeze | ||||
BOOLEAN_SETTINGS = %w( | BOOLEAN_SETTINGS = %w( | ||||
@@ -33,11 +38,13 @@ module Admin | |||||
peers_api_enabled | peers_api_enabled | ||||
show_known_fediverse_at_about_page | show_known_fediverse_at_about_page | ||||
preview_sensitive_media | preview_sensitive_media | ||||
profile_directory | |||||
).freeze | ).freeze | ||||
UPLOAD_SETTINGS = %w( | UPLOAD_SETTINGS = %w( | ||||
thumbnail | thumbnail | ||||
hero | hero | ||||
mascot | |||||
).freeze | ).freeze | ||||
def edit | def edit | ||||
@@ -1,27 +0,0 @@ | |||||
# frozen_string_literal: true | |||||
module Admin | |||||
class SilencesController < BaseController | |||||
before_action :set_account | |||||
def create | |||||
authorize @account, :silence? | |||||
@account.update!(silenced: true) | |||||
log_action :silence, @account | |||||
redirect_to admin_accounts_path | |||||
end | |||||
def destroy | |||||
authorize @account, :unsilence? | |||||
@account.update!(silenced: false) | |||||
log_action :unsilence, @account | |||||
redirect_to admin_accounts_path | |||||
end | |||||
private | |||||
def set_account | |||||
@account = Account.find(params[:account_id]) | |||||
end | |||||
end | |||||
end |
@@ -22,6 +22,15 @@ module Admin | |||||
@form = Form::StatusBatch.new | @form = Form::StatusBatch.new | ||||
end | end | ||||
def show | |||||
authorize :status, :index? | |||||
@statuses = @account.statuses.where(id: params[:id]) | |||||
authorize @statuses.first, :show? | |||||
@form = Form::StatusBatch.new | |||||
end | |||||
def create | def create | ||||
authorize :status, :update? | authorize :status, :update? | ||||
@@ -29,6 +38,10 @@ module Admin | |||||
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) | ||||
rescue ActionController::ParameterMissing | |||||
flash[:alert] = I18n.t('admin.statuses.no_status_selected') | |||||
redirect_to admin_account_statuses_path(@account.id, current_params) | |||||
end | end | ||||
private | private | ||||
@@ -1,27 +0,0 @@ | |||||
# frozen_string_literal: true | |||||
module Admin | |||||
class SuspensionsController < BaseController | |||||
before_action :set_account | |||||
def create | |||||
authorize @account, :suspend? | |||||
Admin::SuspensionWorker.perform_async(@account.id) | |||||
log_action :suspend, @account | |||||
redirect_to admin_accounts_path | |||||
end | |||||
def destroy | |||||
authorize @account, :unsuspend? | |||||
@account.unsuspend! | |||||
log_action :unsuspend, @account | |||||
redirect_to admin_accounts_path | |||||
end | |||||
private | |||||
def set_account | |||||
@account = Account.find(params[:account_id]) | |||||
end | |||||
end | |||||
end |
@@ -0,0 +1,44 @@ | |||||
# frozen_string_literal: true | |||||
module Admin | |||||
class TagsController < BaseController | |||||
before_action :set_tags, only: :index | |||||
before_action :set_tag, except: :index | |||||
before_action :set_filter_params | |||||
def index | |||||
authorize :tag, :index? | |||||
end | |||||
def hide | |||||
authorize @tag, :hide? | |||||
@tag.account_tag_stat.update!(hidden: true) | |||||
redirect_to admin_tags_path(@filter_params) | |||||
end | |||||
def unhide | |||||
authorize @tag, :unhide? | |||||
@tag.account_tag_stat.update!(hidden: false) | |||||
redirect_to admin_tags_path(@filter_params) | |||||
end | |||||
private | |||||
def set_tags | |||||
@tags = Tag.discoverable | |||||
@tags.merge!(Tag.hidden) if filter_params[:hidden] | |||||
end | |||||
def set_tag | |||||
@tag = Tag.find(params[:id]) | |||||
end | |||||
def set_filter_params | |||||
@filter_params = filter_params.to_hash.symbolize_keys | |||||
end | |||||
def filter_params | |||||
params.permit(:hidden) | |||||
end | |||||
end | |||||
end |
@@ -2,7 +2,7 @@ | |||||
module Admin | module Admin | ||||
class TwoFactorAuthenticationsController < BaseController | class TwoFactorAuthenticationsController < BaseController | ||||
before_action :set_user | |||||
before_action :set_target_user | |||||
def destroy | def destroy | ||||
authorize @user, :disable_2fa? | authorize @user, :disable_2fa? | ||||
@@ -13,7 +13,7 @@ module Admin | |||||
private | private | ||||
def set_user | |||||
def set_target_user | |||||
@user = User.find(params[:user_id]) | @user = User.find(params[:user_id]) | ||||
end | end | ||||
end | end | ||||
@@ -0,0 +1,58 @@ | |||||
# frozen_string_literal: true | |||||
module Admin | |||||
class WarningPresetsController < BaseController | |||||
before_action :set_warning_preset, except: [:index, :create] | |||||
def index | |||||
authorize :account_warning_preset, :index? | |||||
@warning_presets = AccountWarningPreset.all | |||||
@warning_preset = AccountWarningPreset.new | |||||
end | |||||
def create | |||||
authorize :account_warning_preset, :create? | |||||
@warning_preset = AccountWarningPreset.new(warning_preset_params) | |||||
if @warning_preset.save | |||||
redirect_to admin_warning_presets_path | |||||
else | |||||
@warning_presets = AccountWarningPreset.all | |||||
render :index | |||||
end | |||||
end | |||||
def edit | |||||
authorize @warning_preset, :update? | |||||
end | |||||
def update | |||||
authorize @warning_preset, :update? | |||||
if @warning_preset.update(warning_preset_params) | |||||
redirect_to admin_warning_presets_path | |||||
else | |||||
render :edit | |||||
end | |||||
end | |||||
def destroy | |||||
authorize @warning_preset, :destroy? | |||||
@warning_preset.destroy! | |||||
redirect_to admin_warning_presets_path | |||||
end | |||||
private | |||||
def set_warning_preset | |||||
@warning_preset = AccountWarningPreset.find(params[:id]) | |||||
end | |||||
def warning_preset_params | |||||
params.require(:account_warning_preset).permit(:text) | |||||
end | |||||
end | |||||
end |
@@ -7,6 +7,8 @@ class Api::BaseController < ApplicationController | |||||
include RateLimitHeaders | include RateLimitHeaders | ||||
skip_before_action :store_current_location | skip_before_action :store_current_location | ||||
skip_before_action :check_user_permissions | |||||
protect_from_forgery with: :null_session | protect_from_forgery with: :null_session | ||||
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e| | rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e| | ||||
@@ -51,8 +53,8 @@ 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]) | |||||
def params_slice(*keys) | |||||
params.slice(*keys).permit(*keys) | |||||
end | end | ||||
def current_resource_owner | def current_resource_owner | ||||
@@ -66,12 +68,14 @@ class Api::BaseController < ApplicationController | |||||
end | end | ||||
def require_user! | def require_user! | ||||
if current_user && !current_user.disabled? | |||||
set_user_activity | |||||
elsif current_user | |||||
if !current_user | |||||
render json: { error: 'This method requires an authenticated user' }, status: 422 | |||||
elsif current_user.disabled? | |||||
render json: { error: 'Your login is currently disabled' }, status: 403 | render json: { error: 'Your login is currently disabled' }, status: 403 | ||||
elsif !current_user.confirmed? | |||||
render json: { error: 'Email confirmation is not completed' }, status: 403 | |||||
else | else | ||||
render json: { error: 'This method requires an authenticated user' }, status: 422 | |||||
set_user_activity | |||||
end | end | ||||
end | end | ||||
@@ -21,7 +21,7 @@ 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, :locked, :bot, :discoverable, fields_attributes: [:name, :value]) | |||||
end | end | ||||
def user_settings_params | def user_settings_params | ||||
@@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController | |||||
end | end | ||||
def default_accounts | def default_accounts | ||||
Account.includes(:active_relationships).references(:active_relationships) | |||||
Account.includes(:active_relationships, :account_stat).references(:active_relationships) | |||||
end | end | ||||
def paginated_follows | def paginated_follows | ||||
@@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController | |||||
end | end | ||||
def default_accounts | def default_accounts | ||||
Account.includes(:passive_relationships).references(:passive_relationships) | |||||
Account.includes(:passive_relationships, :account_stat).references(:passive_relationships) | |||||
end | end | ||||
def paginated_follows | def paginated_follows | ||||
@@ -0,0 +1,32 @@ | |||||
# frozen_string_literal: true | |||||
class Api::V1::Accounts::PinsController < Api::BaseController | |||||
include Authorization | |||||
before_action -> { doorkeeper_authorize! :write, :'write:accounts' } | |||||
before_action :require_user! | |||||
before_action :set_account | |||||
respond_to :json | |||||
def create | |||||
AccountPin.create!(account: current_account, target_account: @account) | |||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships_presenter | |||||
end | |||||
def destroy | |||||
pin = AccountPin.find_by(account: current_account, target_account: @account) | |||||
pin&.destroy! | |||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships_presenter | |||||
end | |||||
private | |||||
def set_account | |||||
@account = Account.find(params[:account_id]) | |||||
end | |||||
def relationships_presenter | |||||
AccountRelationshipsPresenter.new([@account.id], current_user.account_id) | |||||
end | |||||
end |
@@ -1,7 +1,7 @@ | |||||
# frozen_string_literal: true | # frozen_string_literal: true | ||||
class Api::V1::Accounts::StatusesController < Api::BaseController | class Api::V1::Accounts::StatusesController < Api::BaseController | ||||
before_action -> { doorkeeper_authorize! :read, :'read:statuses' } | |||||
before_action -> { authorize_if_got_token! :read, :'read:statuses' } | |||||
before_action :set_account | before_action :set_account | ||||
after_action :insert_pagination_headers | after_action :insert_pagination_headers | ||||
@@ -28,14 +28,11 @@ class Api::V1::Accounts::StatusesController < Api::BaseController | |||||
def account_statuses | def account_statuses | ||||
statuses = truthy_param?(:pinned) ? pinned_scope : permitted_account_statuses | statuses = truthy_param?(:pinned) ? pinned_scope : permitted_account_statuses | ||||
statuses = statuses.paginate_by_max_id( | |||||
limit_param(DEFAULT_STATUSES_LIMIT), | |||||
params[:max_id], | |||||
params[:since_id] | |||||
) | |||||
statuses = statuses.paginate_by_id(limit_param(DEFAULT_STATUSES_LIMIT), params_slice(:max_id, :since_id, :min_id)) | |||||
statuses.merge!(only_media_scope) if truthy_param?(:only_media) | statuses.merge!(only_media_scope) if truthy_param?(:only_media) | ||||
statuses.merge!(no_replies_scope) if truthy_param?(:exclude_replies) | statuses.merge!(no_replies_scope) if truthy_param?(:exclude_replies) | ||||
statuses.merge!(no_reblogs_scope) if truthy_param?(:exclude_reblogs) | |||||
statuses | statuses | ||||
end | end | ||||
@@ -66,6 +63,10 @@ class Api::V1::Accounts::StatusesController < Api::BaseController | |||||
Status.without_replies | Status.without_replies | ||||
end | end | ||||
def no_reblogs_scope | |||||
Status.without_reblogs | |||||
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.slice(:limit, :only_media, :exclude_replies).permit(:limit, :only_media, :exclude_replies).merge(core_params) | ||||
end | end | ||||
@@ -82,7 +83,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController | |||||
def prev_path | def prev_path | ||||
unless @statuses.empty? | unless @statuses.empty? | ||||
api_v1_account_statuses_url pagination_params(since_id: pagination_since_id) | |||||
api_v1_account_statuses_url pagination_params(min_id: pagination_since_id) | |||||
end | end | ||||
end | end | ||||
@@ -1,14 +1,16 @@ | |||||
# frozen_string_literal: true | # frozen_string_literal: true | ||||
class Api::V1::AccountsController < Api::BaseController | class Api::V1::AccountsController < Api::BaseController | ||||
before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:follow, :unfollow, :block, :unblock, :mute, :unmute] | |||||
before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:create, :follow, :unfollow, :block, :unblock, :mute, :unmute] | |||||
before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, only: [:follow, :unfollow] | before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, only: [:follow, :unfollow] | ||||
before_action -> { doorkeeper_authorize! :follow, :'write:mutes' }, only: [:mute, :unmute] | before_action -> { doorkeeper_authorize! :follow, :'write:mutes' }, only: [:mute, :unmute] | ||||
before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, only: [:block, :unblock] | before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, only: [:block, :unblock] | ||||
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create] | |||||
before_action :require_user!, except: [:show] | |||||
before_action :set_account | |||||
before_action :require_user!, except: [:show, :create] | |||||
before_action :set_account, except: [:create] | |||||
before_action :check_account_suspension, only: [:show] | before_action :check_account_suspension, only: [:show] | ||||
before_action :check_enabled_registrations, only: [:create] | |||||
respond_to :json | respond_to :json | ||||
@@ -16,8 +18,18 @@ class Api::V1::AccountsController < Api::BaseController | |||||
render json: @account, serializer: REST::AccountSerializer | render json: @account, serializer: REST::AccountSerializer | ||||
end | end | ||||
def create | |||||
token = AppSignUpService.new.call(doorkeeper_token.application, account_params) | |||||
response = Doorkeeper::OAuth::TokenResponse.new(token) | |||||
headers.merge!(response.headers) | |||||
self.response_body = Oj.dump(response.body) | |||||
self.status = response.status | |||||
end | |||||
def follow | def follow | ||||
FollowService.new.call(current_user.account, @account.acct, reblogs: truthy_param?(:reblogs)) | |||||
FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(: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: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } } | ||||
@@ -62,4 +74,12 @@ class Api::V1::AccountsController < Api::BaseController | |||||
def check_account_suspension | def check_account_suspension | ||||
gone if @account.suspended? | gone if @account.suspended? | ||||
end | end | ||||
def account_params | |||||
params.permit(:username, :email, :password, :agreement, :locale) | |||||
end | |||||
def check_enabled_registrations | |||||
forbidden if single_user_mode? || !Setting.open_registrations | |||||
end | |||||
end | end |
@@ -19,7 +19,7 @@ class Api::V1::BlocksController < Api::BaseController | |||||
end | end | ||||
def paginated_blocks | def paginated_blocks | ||||
@paginated_blocks ||= Block.eager_load(:target_account) | |||||
@paginated_blocks ||= Block.eager_load(target_account: :account_stat) | |||||
.where(account: current_account) | .where(account: current_account) | ||||
.paginate_by_max_id( | .paginate_by_max_id( | ||||
limit_param(DEFAULT_ACCOUNTS_LIMIT), | limit_param(DEFAULT_ACCOUNTS_LIMIT), | ||||
@@ -0,0 +1,71 @@ | |||||
# frozen_string_literal: true | |||||
class Api::V1::ConversationsController < Api::BaseController | |||||
LIMIT = 20 | |||||
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: :index | |||||
before_action -> { doorkeeper_authorize! :write, :'write:conversations' }, except: :index | |||||
before_action :require_user! | |||||
before_action :set_conversation, except: :index | |||||
after_action :insert_pagination_headers, only: :index | |||||
respond_to :json | |||||
def index | |||||
@conversations = paginated_conversations | |||||
render json: @conversations, each_serializer: REST::ConversationSerializer | |||||
end | |||||
def read | |||||
@conversation.update!(unread: false) | |||||
render json: @conversation, serializer: REST::ConversationSerializer | |||||
end | |||||
def destroy | |||||
@conversation.destroy! | |||||
render_empty | |||||
end | |||||
private | |||||
def set_conversation | |||||
@conversation = AccountConversation.where(account: current_account).find(params[:id]) | |||||
end | |||||
def paginated_conversations | |||||
AccountConversation.where(account: current_account) | |||||
.paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id)) | |||||
end | |||||
def insert_pagination_headers | |||||
set_pagination_headers(next_path, prev_path) | |||||
end | |||||
def next_path | |||||
if records_continue? | |||||
api_v1_conversations_url pagination_params(max_id: pagination_max_id) | |||||
end | |||||
end | |||||
def prev_path | |||||
unless @conversations.empty? | |||||
api_v1_conversations_url pagination_params(min_id: pagination_since_id) | |||||
end | |||||
end | |||||
def pagination_max_id | |||||
@conversations.last.last_status_id | |||||
end | |||||
def pagination_since_id | |||||
@conversations.first.last_status_id | |||||
end | |||||
def records_continue? | |||||
@conversations.size == limit_param(LIMIT) | |||||
end | |||||
def pagination_params(core_params) | |||||
params.slice(:limit).permit(:limit).merge(core_params) | |||||
end | |||||
end |
@@ -4,6 +4,8 @@ class Api::V1::CustomEmojisController < Api::BaseController | |||||
respond_to :json | respond_to :json | ||||
def index | def index | ||||
render json: CustomEmoji.local.where(disabled: false), each_serializer: REST::CustomEmojiSerializer | |||||
render_cached_json('api:v1:custom_emojis', expires_in: 1.minute) do | |||||
ActiveModelSerializers::SerializableResource.new(CustomEmoji.local.where(disabled: false), each_serializer: REST::CustomEmojiSerializer) | |||||
end | |||||
end | end | ||||
end | end |
@@ -0,0 +1,72 @@ | |||||
# frozen_string_literal: true | |||||
class Api::V1::EndorsementsController < Api::BaseController | |||||
before_action -> { doorkeeper_authorize! :read, :'read:accounts' } | |||||
before_action :require_user! | |||||
after_action :insert_pagination_headers | |||||
respond_to :json | |||||
def index | |||||
@accounts = load_accounts | |||||
render json: @accounts, each_serializer: REST::AccountSerializer | |||||
end | |||||
private | |||||
def load_accounts | |||||
if unlimited? | |||||
endorsed_accounts.all | |||||
else | |||||
endorsed_accounts.paginate_by_max_id( | |||||
limit_param(DEFAULT_ACCOUNTS_LIMIT), | |||||
params[:max_id], | |||||
params[:since_id] | |||||
) | |||||
end | |||||
end | |||||
def endorsed_accounts | |||||
current_account.endorsed_accounts.includes(:account_stat) | |||||
end | |||||
def insert_pagination_headers | |||||
set_pagination_headers(next_path, prev_path) | |||||
end | |||||
def next_path | |||||
return if unlimited? | |||||
if records_continue? | |||||
api_v1_endorsements_url pagination_params(max_id: pagination_max_id) | |||||
end | |||||
end | |||||
def prev_path | |||||
return if unlimited? | |||||
unless @accounts.empty? | |||||
api_v1_endorsements_url pagination_params(since_id: pagination_since_id) | |||||
end | |||||
end | |||||
def pagination_max_id | |||||
@accounts.last.id | |||||
end | |||||
def pagination_since_id | |||||
@accounts.first.id | |||||
end | |||||
def records_continue? | |||||
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) | |||||
end | |||||
def pagination_params(core_params) | |||||
params.slice(:limit).permit(:limit).merge(core_params) | |||||
end | |||||
def unlimited? | |||||
params[:limit] == '0' | |||||
end | |||||
end |
@@ -26,10 +26,9 @@ class Api::V1::FavouritesController < Api::BaseController | |||||
end | end | ||||
def results | def results | ||||
@_results ||= account_favourites.paginate_by_max_id( | |||||
@_results ||= account_favourites.paginate_by_id( | |||||
limit_param(DEFAULT_STATUSES_LIMIT), | limit_param(DEFAULT_STATUSES_LIMIT), | ||||
params[:max_id], | |||||
params[:since_id] | |||||
params_slice(:max_id, :since_id, :min_id) | |||||
) | ) | ||||
end | end | ||||
@@ -49,7 +48,7 @@ class Api::V1::FavouritesController < Api::BaseController | |||||
def prev_path | def prev_path | ||||
unless results.empty? | unless results.empty? | ||||
api_v1_favourites_url pagination_params(since_id: pagination_since_id) | |||||
api_v1_favourites_url pagination_params(min_id: pagination_since_id) | |||||
end | end | ||||
end | end | ||||
@@ -13,6 +13,7 @@ class Api::V1::FollowRequestsController < Api::BaseController | |||||
def authorize | def authorize | ||||
AuthorizeFollowService.new.call(account, current_account) | AuthorizeFollowService.new.call(account, current_account) | ||||
NotifyService.new.call(current_account, Follow.find_by(account: account, target_account: current_account)) | |||||
render_empty | render_empty | ||||
end | end | ||||
@@ -32,7 +33,7 @@ class Api::V1::FollowRequestsController < Api::BaseController | |||||
end | end | ||||
def default_accounts | def default_accounts | ||||
Account.includes(:follow_requests).references(:follow_requests) | |||||
Account.includes(:follow_requests, :account_stat).references(:follow_requests) | |||||
end | end | ||||
def paginated_follow_requests | def paginated_follow_requests | ||||
@@ -4,6 +4,8 @@ class Api::V1::InstancesController < Api::BaseController | |||||
respond_to :json | respond_to :json | ||||
def show | def show | ||||
render json: {}, serializer: REST::InstanceSerializer | |||||
render_cached_json('api:v1:instances', expires_in: 5.minutes) do | |||||
ActiveModelSerializers::SerializableResource.new({}, serializer: REST::InstanceSerializer) | |||||
end | |||||
end | end | ||||
end | end |
@@ -1,7 +1,7 @@ | |||||
# frozen_string_literal: true | # frozen_string_literal: true | ||||
class Api::V1::Lists::AccountsController < Api::BaseController | class Api::V1::Lists::AccountsController < Api::BaseController | ||||
before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:show] | |||||
before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:show] | |||||
before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:show] | before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:show] | ||||
before_action :require_user! | before_action :require_user! | ||||
@@ -37,9 +37,9 @@ class Api::V1::Lists::AccountsController < Api::BaseController | |||||
def load_accounts | def load_accounts | ||||
if unlimited? | if unlimited? | ||||
@list.accounts.all | |||||
@list.accounts.includes(:account_stat).all | |||||
else | else | ||||
@list.accounts.paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id]) | |||||
@list.accounts.includes(:account_stat).paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id]) | |||||
end | end | ||||
end | end | ||||
@@ -1,7 +1,7 @@ | |||||
# frozen_string_literal: true | # frozen_string_literal: true | ||||
class Api::V1::ListsController < Api::BaseController | class Api::V1::ListsController < Api::BaseController | ||||
before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:index, :show] | |||||
before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:index, :show] | |||||
before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:index, :show] | before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:index, :show] | ||||
before_action :require_user! | before_action :require_user! | ||||
@@ -15,19 +15,17 @@ class Api::V1::MutesController < Api::BaseController | |||||
private | private | ||||
def load_accounts | def load_accounts | ||||
default_accounts.merge(paginated_mutes).to_a | |||||
end | |||||
def default_accounts | |||||
Account.includes(:muted_by).references(:muted_by) | |||||
paginated_mutes.map(&:target_account) | |||||
end | end | ||||
def paginated_mutes | def paginated_mutes | ||||
Mute.where(account: current_account).paginate_by_max_id( | |||||
limit_param(DEFAULT_ACCOUNTS_LIMIT), | |||||
params[:max_id], | |||||
params[:since_id] | |||||
) | |||||
@paginated_mutes ||= Mute.eager_load(:target_account) | |||||
.where(account: current_account) | |||||
.paginate_by_max_id( | |||||
limit_param(DEFAULT_ACCOUNTS_LIMIT), | |||||
params[:max_id], | |||||
params[:since_id] | |||||
) | |||||
end | end | ||||
def insert_pagination_headers | def insert_pagination_headers | ||||
@@ -41,21 +39,21 @@ class Api::V1::MutesController < Api::BaseController | |||||
end | end | ||||
def prev_path | def prev_path | ||||
unless @accounts.empty? | |||||
unless paginated_mutes.empty? | |||||
api_v1_mutes_url pagination_params(since_id: pagination_since_id) | api_v1_mutes_url pagination_params(since_id: pagination_since_id) | ||||
end | end | ||||
end | end | ||||
def pagination_max_id | def pagination_max_id | ||||
@accounts.last.muted_by_ids.last | |||||
paginated_mutes.last.id | |||||
end | end | ||||
def pagination_since_id | def pagination_since_id | ||||
@accounts.first.muted_by_ids.first | |||||
paginated_mutes.first.id | |||||
end | end | ||||
def records_continue? | def records_continue? | ||||
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) | |||||
paginated_mutes.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) | |||||
end | end | ||||
def pagination_params(core_params) | def pagination_params(core_params) | ||||
@@ -37,10 +37,9 @@ class Api::V1::NotificationsController < Api::BaseController | |||||
end | end | ||||
def paginated_notifications | def paginated_notifications | ||||
browserable_account_notifications.paginate_by_max_id( | |||||
browserable_account_notifications.paginate_by_id( | |||||
limit_param(DEFAULT_NOTIFICATIONS_LIMIT), | limit_param(DEFAULT_NOTIFICATIONS_LIMIT), | ||||
params[:max_id], | |||||
params[:since_id] | |||||
params_slice(:max_id, :since_id, :min_id) | |||||
) | ) | ||||
end | end | ||||
@@ -64,7 +63,7 @@ class Api::V1::NotificationsController < Api::BaseController | |||||
def prev_path | def prev_path | ||||
unless @notifications.empty? | unless @notifications.empty? | ||||
api_v1_notifications_url pagination_params(since_id: pagination_since_id) | |||||
api_v1_notifications_url pagination_params(min_id: pagination_since_id) | |||||
end | end | ||||
end | end | ||||
@@ -1,17 +1,11 @@ | |||||
# frozen_string_literal: true | # frozen_string_literal: true | ||||
class Api::V1::ReportsController < Api::BaseController | class Api::V1::ReportsController < Api::BaseController | ||||
before_action -> { doorkeeper_authorize! :read, :'read:reports' }, except: [:create] | |||||
before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create] | before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create] | ||||
before_action :require_user! | before_action :require_user! | ||||
respond_to :json | respond_to :json | ||||
def index | |||||
@reports = current_account.reports | |||||
render json: @reports, each_serializer: REST::ReportSerializer | |||||
end | |||||
def create | def create | ||||
@report = ReportService.new.call( | @report = ReportService.new.call( | ||||
current_account, | current_account, | ||||
@@ -27,7 +21,7 @@ class Api::V1::ReportsController < Api::BaseController | |||||
private | private | ||||
def reported_status_ids | def reported_status_ids | ||||
Status.find(status_ids).pluck(:id) | |||||
reported_account.statuses.find(status_ids).pluck(:id) | |||||
end | end | ||||
def status_ids | def status_ids | ||||
@@ -0,0 +1,77 @@ | |||||
# frozen_string_literal: true | |||||
class Api::V1::ScheduledStatusesController < Api::BaseController | |||||
include Authorization | |||||
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, except: [:update, :destroy] | |||||
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:update, :destroy] | |||||
before_action :set_statuses, only: :index | |||||
before_action :set_status, except: :index | |||||
after_action :insert_pagination_headers, only: :index | |||||
def index | |||||
render json: @statuses, each_serializer: REST::ScheduledStatusSerializer | |||||
end | |||||
def show | |||||
render json: @status, serializer: REST::ScheduledStatusSerializer | |||||
end | |||||
def update | |||||
@status.update!(scheduled_status_params) | |||||
render json: @status, serializer: REST::ScheduledStatusSerializer | |||||
end | |||||
def destroy | |||||
@status.destroy! | |||||
render_empty | |||||
end | |||||
private | |||||
def set_statuses | |||||
@statuses = current_account.scheduled_statuses.paginate_by_id(limit_param(DEFAULT_STATUSES_LIMIT), params_slice(:max_id, :since_id, :min_id)) | |||||
end | |||||
def set_status | |||||
@status = current_account.scheduled_statuses.find(params[:id]) | |||||
end | |||||
def scheduled_status_params | |||||
params.permit(:scheduled_at) | |||||
end | |||||
def pagination_params(core_params) | |||||
params.slice(:limit).permit(:limit).merge(core_params) | |||||
end | |||||
def insert_pagination_headers | |||||
set_pagination_headers(next_path, prev_path) | |||||
end | |||||
def next_path | |||||
if records_continue? | |||||
api_v1_scheduled_statuses_url pagination_params(max_id: pagination_max_id) | |||||
end | |||||
end | |||||
def prev_path | |||||
unless @statuses.empty? | |||||
api_v1_scheduled_statuses_url pagination_params(min_id: pagination_since_id) | |||||
end | |||||
end | |||||
def records_continue? | |||||
@statuses.size == limit_param(DEFAULT_STATUSES_LIMIT) | |||||
end | |||||
def pagination_max_id | |||||
@statuses.last.id | |||||
end | |||||
def pagination_since_id | |||||
@statuses.first.id | |||||
end | |||||
end |
@@ -22,7 +22,7 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController | |||||
def default_accounts | def default_accounts | ||||
Account | Account | ||||
.includes(:favourites) | |||||
.includes(:favourites, :account_stat) | |||||
.references(:favourites) | .references(:favourites) | ||||
.where(favourites: { status_id: @status.id }) | .where(favourites: { status_id: @status.id }) | ||||
end | end | ||||
@@ -21,11 +21,11 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController | |||||
end | end | ||||
def default_accounts | def default_accounts | ||||
Account.includes(:statuses).references(:statuses) | |||||
Account.includes(:statuses, :account_stat).references(:statuses) | |||||
end | end | ||||
def paginated_statuses | def paginated_statuses | ||||
Status.where(reblog_of_id: @status.id).paginate_by_max_id( | |||||
Status.where(reblog_of_id: @status.id).where(visibility: [:public, :unlisted]).paginate_by_max_id( | |||||
limit_param(DEFAULT_ACCOUNTS_LIMIT), | limit_param(DEFAULT_ACCOUNTS_LIMIT), | ||||
params[:max_id], | params[:max_id], | ||||
params[:since_id] | params[:since_id] | ||||
@@ -17,8 +17,7 @@ class Api::V1::StatusesController < Api::BaseController | |||||
CONTEXT_LIMIT = 4_096 | CONTEXT_LIMIT = 4_096 | ||||
def show | def show | ||||
cached = Rails.cache.read(@status.cache_key) | |||||
@status = cached unless cached.nil? | |||||
@status = cache_collection([@status], Status).first | |||||
render json: @status, serializer: REST::StatusSerializer | render json: @status, serializer: REST::StatusSerializer | ||||
end | end | ||||
@@ -46,16 +45,17 @@ class Api::V1::StatusesController < Api::BaseController | |||||
def create | def create | ||||
@status = PostStatusService.new.call(current_user.account, | @status = PostStatusService.new.call(current_user.account, | ||||
status_params[:status], | |||||
status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]), | |||||
text: status_params[:status], | |||||
thread: status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]), | |||||
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], | ||||
visibility: status_params[:visibility], | visibility: status_params[:visibility], | ||||
scheduled_at: status_params[:scheduled_at], | |||||
application: doorkeeper_token.application, | application: doorkeeper_token.application, | ||||
idempotency: request.headers['Idempotency-Key']) | idempotency: request.headers['Idempotency-Key']) | ||||
render json: @status, serializer: REST::StatusSerializer | |||||
render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer | |||||
end | end | ||||
def destroy | def destroy | ||||
@@ -78,7 +78,7 @@ 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, :sensitive, :spoiler_text, :visibility, :scheduled_at, media_ids: []) | |||||
end | end | ||||
def pagination_params(core_params) | def pagination_params(core_params) | ||||
@@ -30,7 +30,8 @@ class Api::V1::Timelines::HomeController < Api::BaseController | |||||
account_home_feed.get( | account_home_feed.get( | ||||
limit_param(DEFAULT_STATUSES_LIMIT), | limit_param(DEFAULT_STATUSES_LIMIT), | ||||
params[:max_id], | params[:max_id], | ||||
params[:since_id] | |||||
params[:since_id], | |||||
params[:min_id] | |||||
) | ) | ||||
end | end | ||||
@@ -51,7 +52,7 @@ class Api::V1::Timelines::HomeController < Api::BaseController | |||||
end | end | ||||
def prev_path | def prev_path | ||||
api_v1_timelines_home_url pagination_params(since_id: pagination_since_id) | |||||
api_v1_timelines_home_url pagination_params(min_id: pagination_since_id) | |||||
end | end | ||||
def pagination_max_id | def pagination_max_id | ||||
@@ -32,7 +32,8 @@ class Api::V1::Timelines::ListController < Api::BaseController | |||||
list_feed.get( | list_feed.get( | ||||
limit_param(DEFAULT_STATUSES_LIMIT), | limit_param(DEFAULT_STATUSES_LIMIT), | ||||
params[:max_id], | params[:max_id], | ||||
params[:since_id] | |||||
params[:since_id], | |||||
params[:min_id] | |||||
) | ) | ||||
end | end | ||||
@@ -53,7 +54,7 @@ class Api::V1::Timelines::ListController < Api::BaseController | |||||
end | end | ||||
def prev_path | def prev_path | ||||
api_v1_timelines_list_url params[:id], pagination_params(since_id: pagination_since_id) | |||||
api_v1_timelines_list_url params[:id], pagination_params(min_id: pagination_since_id) | |||||
end | end | ||||
def pagination_max_id | def pagination_max_id | ||||
@@ -21,10 +21,9 @@ class Api::V1::Timelines::PublicController < Api::BaseController | |||||
end | end | ||||
def public_statuses | def public_statuses | ||||
statuses = public_timeline_statuses.paginate_by_max_id( | |||||
statuses = public_timeline_statuses.paginate_by_id( | |||||
limit_param(DEFAULT_STATUSES_LIMIT), | limit_param(DEFAULT_STATUSES_LIMIT), | ||||
params[:max_id], | |||||
params[:since_id] | |||||
params_slice(:max_id, :since_id, :min_id) | |||||
) | ) | ||||
if truthy_param?(:only_media) | if truthy_param?(:only_media) | ||||
@@ -53,7 +52,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController | |||||
end | end | ||||
def prev_path | def prev_path | ||||
api_v1_timelines_public_url pagination_params(since_id: pagination_since_id) | |||||
api_v1_timelines_public_url pagination_params(min_id: pagination_since_id) | |||||
end | end | ||||
def pagination_max_id | def pagination_max_id | ||||
@@ -29,10 +29,9 @@ class Api::V1::Timelines::TagController < Api::BaseController | |||||
if @tag.nil? | if @tag.nil? | ||||
[] | [] | ||||
else | else | ||||
statuses = tag_timeline_statuses.paginate_by_max_id( | |||||
statuses = tag_timeline_statuses.paginate_by_id( | |||||
limit_param(DEFAULT_STATUSES_LIMIT), | limit_param(DEFAULT_STATUSES_LIMIT), | ||||
params[:max_id], | |||||
params[:since_id] | |||||
params_slice(:max_id, :since_id, :min_id) | |||||
) | ) | ||||
if truthy_param?(:only_media) | if truthy_param?(:only_media) | ||||
@@ -46,7 +45,7 @@ class Api::V1::Timelines::TagController < Api::BaseController | |||||
end | end | ||||
def tag_timeline_statuses | def tag_timeline_statuses | ||||
Status.as_tag_timeline(@tag, current_account, truthy_param?(:local)) | |||||
HashtagQueryService.new.call(@tag, params.slice(:any, :all, :none), current_account, truthy_param?(:local)) | |||||
end | end | ||||
def insert_pagination_headers | def insert_pagination_headers | ||||
@@ -62,7 +61,7 @@ class Api::V1::Timelines::TagController < Api::BaseController | |||||
end | end | ||||
def prev_path | def prev_path | ||||
api_v1_timelines_tag_url params[:id], pagination_params(since_id: pagination_since_id) | |||||
api_v1_timelines_tag_url params[:id], pagination_params(min_id: pagination_since_id) | |||||
end | end | ||||
def pagination_max_id | def pagination_max_id | ||||
@@ -10,6 +10,7 @@ class Api::Web::EmbedsController < Api::Web::BaseController | |||||
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 = FetchOEmbedService.new.call(params[:url]) | ||||
oembed[:html] = Formatter.instance.sanitize(oembed[:html], Sanitize::Config::MASTODON_OEMBED) if oembed[:html].present? | |||||
if oembed | if oembed | ||||
render json: oembed | render json: oembed | ||||
@@ -24,7 +24,7 @@ class ApplicationController < ActionController::Base | |||||
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? | ||||
before_action :check_suspension, if: :user_signed_in? | |||||
before_action :check_user_permissions, if: :user_signed_in? | |||||
def raise_not_found | def raise_not_found | ||||
raise ActionController::RoutingError, "No route matches #{params[:unmatched_route]}" | raise ActionController::RoutingError, "No route matches #{params[:unmatched_route]}" | ||||
@@ -48,8 +48,8 @@ class ApplicationController < ActionController::Base | |||||
forbidden unless current_user&.staff? | forbidden unless current_user&.staff? | ||||
end | end | ||||
def check_suspension | |||||
forbidden if current_user.account.suspended? | |||||
def check_user_permissions | |||||
forbidden if current_user.disabled? || current_user.account.suspended? | |||||
end | end | ||||
def after_sign_out_path_for(_resource_or_scope) | def after_sign_out_path_for(_resource_or_scope) | ||||
@@ -58,6 +58,10 @@ class ApplicationController < ActionController::Base | |||||
protected | protected | ||||
def truthy_param?(key) | |||||
ActiveModel::Type::Boolean.new.cast(params[key]) | |||||
end | |||||
def forbidden | def forbidden | ||||
respond_with_error(403) | respond_with_error(403) | ||||
end | end | ||||
@@ -95,7 +99,7 @@ class ApplicationController < ActionController::Base | |||||
end | end | ||||
def current_theme | def current_theme | ||||
return Setting.default_settings['theme'] unless Themes.instance.names.include? current_user&.setting_theme | |||||
return Setting.theme unless Themes.instance.names.include? current_user&.setting_theme | |||||
current_user.setting_theme | current_user.setting_theme | ||||
end | end | ||||
@@ -103,29 +107,26 @@ class ApplicationController < ActionController::Base | |||||
return raw unless klass.respond_to?(:with_includes) | return raw unless klass.respond_to?(:with_includes) | ||||
raw = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation) | raw = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation) | ||||
uncached_ids = [] | |||||
cached_keys_with_value = Rails.cache.read_multi(*raw.map(&:cache_key)) | |||||
raw.each do |item| | |||||
uncached_ids << item.id unless cached_keys_with_value.key?(item.cache_key) | |||||
end | |||||
cached_keys_with_value = Rails.cache.read_multi(*raw).transform_keys(&:id) | |||||
uncached_ids = raw.map(&:id) - cached_keys_with_value.keys | |||||
klass.reload_stale_associations!(cached_keys_with_value.values) if klass.respond_to?(:reload_stale_associations!) | klass.reload_stale_associations!(cached_keys_with_value.values) if klass.respond_to?(:reload_stale_associations!) | ||||
unless uncached_ids.empty? | unless uncached_ids.empty? | ||||
uncached = klass.where(id: uncached_ids).with_includes.map { |item| [item.id, item] }.to_h | |||||
uncached = klass.where(id: uncached_ids).with_includes.each_with_object({}) { |item, h| h[item.id] = item } | |||||
uncached.each_value do |item| | uncached.each_value do |item| | ||||
Rails.cache.write(item.cache_key, item) | |||||
Rails.cache.write(item, item) | |||||
end | end | ||||
end | end | ||||
raw.map { |item| cached_keys_with_value[item.cache_key] || uncached[item.id] }.compact | |||||
raw.map { |item| cached_keys_with_value[item.id] || uncached[item.id] }.compact | |||||
end | end | ||||
def respond_with_error(code) | def respond_with_error(code) | ||||
respond_to do |format| | respond_to do |format| | ||||
format.any { head code } | format.any { head code } | ||||
format.html do | format.html do | ||||
set_locale | set_locale | ||||
render "errors/#{code}", layout: 'error', status: code | render "errors/#{code}", layout: 'error', status: code | ||||
@@ -135,7 +136,6 @@ class ApplicationController < ActionController::Base | |||||
def render_cached_json(cache_key, **options) | def render_cached_json(cache_key, **options) | ||||
options[:expires_in] ||= 3.minutes | 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 | cache_public = options.key?(:public) ? options.delete(:public) : true | ||||
content_type = options.delete(:content_type) || 'application/json' | content_type = options.delete(:content_type) || 'application/json' | ||||
@@ -3,11 +3,12 @@ | |||||
class Auth::ConfirmationsController < Devise::ConfirmationsController | class Auth::ConfirmationsController < Devise::ConfirmationsController | ||||
layout 'auth' | layout 'auth' | ||||
before_action :set_body_classes | |||||
before_action :set_user, only: [:finish_signup] | before_action :set_user, only: [:finish_signup] | ||||
# GET/PATCH /users/:id/finish_signup | |||||
def finish_signup | def finish_signup | ||||
return unless request.patch? && params[:user] | return unless request.patch? && params[:user] | ||||
if @user.update(user_params) | if @user.update(user_params) | ||||
@user.skip_reconfirmation! | @user.skip_reconfirmation! | ||||
bypass_sign_in(@user) | bypass_sign_in(@user) | ||||
@@ -23,7 +24,19 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController | |||||
@user = current_user | @user = current_user | ||||
end | end | ||||
def set_body_classes | |||||
@body_classes = 'lighter' | |||||
end | |||||
def user_params | def user_params | ||||
params.require(:user).permit(:email) | params.require(:user).permit(:email) | ||||
end | end | ||||
def after_confirmation_path_for(_resource_name, user) | |||||
if user.created_by_application && truthy_param?(:redirect_to_app) | |||||
user.created_by_application.redirect_uri | |||||
else | |||||
super | |||||
end | |||||
end | |||||
end | end |
@@ -2,6 +2,7 @@ | |||||
class Auth::PasswordsController < Devise::PasswordsController | class Auth::PasswordsController < Devise::PasswordsController | ||||
before_action :check_validity_of_reset_password_token, only: :edit | before_action :check_validity_of_reset_password_token, only: :edit | ||||
before_action :set_body_classes | |||||
layout 'auth' | layout 'auth' | ||||
@@ -14,6 +15,10 @@ class Auth::PasswordsController < Devise::PasswordsController | |||||
end | end | ||||
end | end | ||||
def set_body_classes | |||||
@body_classes = 'lighter' | |||||
end | |||||
def reset_password_token_is_valid? | def reset_password_token_is_valid? | ||||
resource_class.with_reset_password_token(params[:reset_password_token]).present? | resource_class.with_reset_password_token(params[:reset_password_token]).present? | ||||
end | end | ||||
@@ -8,6 +8,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController | |||||
before_action :configure_sign_up_params, only: [:create] | before_action :configure_sign_up_params, only: [:create] | ||||
before_action :set_sessions, only: [:edit, :update] | before_action :set_sessions, only: [:edit, :update] | ||||
before_action :set_instance_presenter, only: [:new, :create, :update] | before_action :set_instance_presenter, only: [:new, :create, :update] | ||||
before_action :set_body_classes, only: [:new, :create, :edit, :update] | |||||
def destroy | def destroy | ||||
not_found | not_found | ||||
@@ -25,6 +26,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController | |||||
resource.locale = I18n.locale | resource.locale = I18n.locale | ||||
resource.invite_code = params[:invite_code] if resource.invite_code.blank? | resource.invite_code = params[:invite_code] if resource.invite_code.blank? | ||||
resource.agreement = true | |||||
resource.build_account if resource.account.nil? | resource.build_account if resource.account.nil? | ||||
end | end | ||||
@@ -79,6 +81,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController | |||||
@instance_presenter = InstancePresenter.new | @instance_presenter = InstancePresenter.new | ||||
end | end | ||||
def set_body_classes | |||||
@body_classes = %w(edit update).include?(action_name) ? 'admin' : 'lighter' | |||||
end | |||||
def set_invite | def set_invite | ||||
@invite = invite_code.present? ? Invite.find_by(code: invite_code) : nil | @invite = invite_code.present? ? Invite.find_by(code: invite_code) : nil | ||||
end | end | ||||
@@ -6,9 +6,10 @@ class Auth::SessionsController < Devise::SessionsController | |||||
layout 'auth' | layout 'auth' | ||||
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_user_permissions, 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] | ||||
before_action :set_instance_presenter, only: [:new] | before_action :set_instance_presenter, only: [:new] | ||||
before_action :set_body_classes | |||||
def new | def new | ||||
Devise.omniauth_configs.each do |provider, config| | Devise.omniauth_configs.each do |provider, config| | ||||
@@ -26,8 +27,10 @@ class Auth::SessionsController < Devise::SessionsController | |||||
end | end | ||||
def destroy | def destroy | ||||
tmp_stored_location = stored_location_for(:user) | |||||
super | super | ||||
flash.delete(:notice) | flash.delete(:notice) | ||||
store_location_for(:user, tmp_stored_location) if continue_after? | |||||
end | end | ||||
protected | protected | ||||
@@ -109,6 +112,10 @@ class Auth::SessionsController < Devise::SessionsController | |||||
@instance_presenter = InstancePresenter.new | @instance_presenter = InstancePresenter.new | ||||
end | end | ||||
def set_body_classes | |||||
@body_classes = 'lighter' | |||||
end | |||||
def home_paths(resource) | def home_paths(resource) | ||||
paths = [about_path] | paths = [about_path] | ||||
if single_user_mode? && resource.is_a?(User) | if single_user_mode? && resource.is_a?(User) | ||||
@@ -116,4 +123,8 @@ class Auth::SessionsController < Devise::SessionsController | |||||
end | end | ||||
paths | paths | ||||
end | end | ||||
def continue_after? | |||||
truthy_param?(:continue) | |||||
end | |||||
end | end |
@@ -1,66 +0,0 @@ | |||||
# frozen_string_literal: true | |||||
class AuthorizeFollowsController < ApplicationController | |||||
layout 'modal' | |||||
before_action :authenticate_user! | |||||
before_action :set_body_classes | |||||
def show | |||||
@account = located_account || render(:error) | |||||
end | |||||
def create | |||||
@account = follow_attempt.try(:target_account) | |||||
if @account.nil? | |||||
render :error | |||||
else | |||||
render :success | |||||
end | |||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError | |||||
render :error | |||||
end | |||||
private | |||||
def follow_attempt | |||||
FollowService.new.call(current_account, acct_without_prefix) | |||||
end | |||||
def located_account | |||||
if acct_param_is_url? | |||||
account_from_remote_fetch | |||||
else | |||||
account_from_remote_follow | |||||
end | |||||
end | |||||
def account_from_remote_fetch | |||||
FetchRemoteAccountService.new.call(acct_without_prefix) | |||||
end | |||||
def account_from_remote_follow | |||||
ResolveAccountService.new.call(acct_without_prefix) | |||||
end | |||||
def acct_param_is_url? | |||||
parsed_uri.path && %w(http https).include?(parsed_uri.scheme) | |||||
end | |||||
def parsed_uri | |||||
Addressable::URI.parse(acct_without_prefix).normalize | |||||
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 |
@@ -0,0 +1,66 @@ | |||||
# frozen_string_literal: true | |||||
class AuthorizeInteractionsController < ApplicationController | |||||
include Authorization | |||||
layout 'modal' | |||||
before_action :authenticate_user! | |||||
before_action :set_body_classes | |||||
before_action :set_resource | |||||
def show | |||||
if @resource.is_a?(Account) | |||||
render :show | |||||
elsif @resource.is_a?(Status) | |||||
redirect_to web_url("statuses/#{@resource.id}") | |||||
else | |||||
render :error | |||||
end | |||||
end | |||||
def create | |||||
if @resource.is_a?(Account) && FollowService.new.call(current_account, @resource) | |||||
render :success | |||||
else | |||||
render :error | |||||
end | |||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError | |||||
render :error | |||||
end | |||||
private | |||||
def set_resource | |||||
@resource = located_resource || render(:error) | |||||
authorize(@resource, :show?) if @resource.is_a?(Status) | |||||
end | |||||
def located_resource | |||||
if uri_param_is_url? | |||||
ResolveURLService.new.call(uri_param) | |||||
else | |||||
account_from_remote_follow | |||||
end | |||||
end | |||||
def account_from_remote_follow | |||||
ResolveAccountService.new.call(uri_param) | |||||
end | |||||
def uri_param_is_url? | |||||
parsed_uri.path && %w(http https).include?(parsed_uri.scheme) | |||||
end | |||||
def parsed_uri | |||||
Addressable::URI.parse(uri_param).normalize | |||||
end | |||||
def uri_param | |||||
params[:uri] || params.fetch(:acct, '').gsub(/\Aacct:/, '') | |||||
end | |||||
def set_body_classes | |||||
@body_classes = 'modal-layout' | |||||
end | |||||
end |
@@ -8,6 +8,7 @@ module AccountControllerConcern | |||||
included do | included do | ||||
layout 'public' | layout 'public' | ||||
before_action :set_account | before_action :set_account | ||||
before_action :set_instance_presenter | |||||
before_action :set_link_headers | before_action :set_link_headers | ||||
before_action :check_account_suspension | before_action :check_account_suspension | ||||
end | end | ||||
@@ -18,6 +19,10 @@ module AccountControllerConcern | |||||
@account = Account.find_local!(params[:account_username]) | @account = Account.find_local!(params[:account_username]) | ||||
end | end | ||||
def set_instance_presenter | |||||
@instance_presenter = InstancePresenter.new | |||||
end | |||||
def set_link_headers | def set_link_headers | ||||
response.headers['Link'] = LinkHeader.new( | response.headers['Link'] = LinkHeader.new( | ||||
[ | [ | ||||
@@ -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 |
@@ -22,6 +22,12 @@ module SignatureVerification | |||||
return | return | ||||
end | end | ||||
if request.headers['Date'].present? && !matches_time_window? | |||||
@signature_verification_failure_reason = 'Signed request date outside acceptable time window' | |||||
@signed_request_account = nil | |||||
return | |||||
end | |||||
raw_signature = request.headers['Signature'] | raw_signature = request.headers['Signature'] | ||||
signature_params = {} | signature_params = {} | ||||
@@ -37,7 +43,13 @@ module SignatureVerification | |||||
return | return | ||||
end | end | ||||
account = account_from_key_id(signature_params['keyId']) | |||||
account_stoplight = Stoplight("source:#{request.ip}") { account_from_key_id(signature_params['keyId']) } | |||||
.with_fallback { nil } | |||||
.with_threshold(1) | |||||
.with_cool_off_time(5.minutes.seconds) | |||||
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) } | |||||
account = account_stoplight.run | |||||
if account.nil? | if account.nil? | ||||
@signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}" | @signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}" | ||||
@@ -48,23 +60,26 @@ module SignatureVerification | |||||
signature = Base64.decode64(signature_params['signature']) | signature = Base64.decode64(signature_params['signature']) | ||||
compare_signed_string = build_signed_string(signature_params['headers']) | compare_signed_string = build_signed_string(signature_params['headers']) | ||||
if account.keypair.public_key.verify(OpenSSL::Digest::SHA256.new, signature, compare_signed_string) | |||||
@signed_request_account = account | |||||
@signed_request_account | |||||
elsif account.possibly_stale? | |||||
account = account.refresh! | |||||
return account unless verify_signature(account, signature, compare_signed_string).nil? | |||||
if account.keypair.public_key.verify(OpenSSL::Digest::SHA256.new, signature, compare_signed_string) | |||||
@signed_request_account = account | |||||
@signed_request_account | |||||
else | |||||
@signature_verification_failure_reason = "Verification failed for #{account.username}@#{account.domain} #{account.uri}" | |||||
@signed_request_account = nil | |||||
end | |||||
else | |||||
@signature_verification_failure_reason = "Verification failed for #{account.username}@#{account.domain} #{account.uri}" | |||||
account_stoplight = Stoplight("source:#{request.ip}") { account.possibly_stale? ? account.refresh! : account_refresh_key(account) } | |||||
.with_fallback { nil } | |||||
.with_threshold(1) | |||||
.with_cool_off_time(5.minutes.seconds) | |||||
.with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) } | |||||
account = account_stoplight.run | |||||
if account.nil? | |||||
@signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}" | |||||
@signed_request_account = nil | @signed_request_account = nil | ||||
return | |||||
end | end | ||||
return account unless verify_signature(account, signature, compare_signed_string).nil? | |||||
@signature_verification_failure_reason = "Verification failed for #{account.username}@#{account.domain} #{account.uri}" | |||||
@signed_request_account = nil | |||||
end | end | ||||
def request_body | def request_body | ||||
@@ -73,10 +88,19 @@ module SignatureVerification | |||||
private | private | ||||
def verify_signature(account, signature, compare_signed_string) | |||||
if account.keypair.public_key.verify(OpenSSL::Digest::SHA256.new, signature, compare_signed_string) | |||||
@signed_request_account = account | |||||
@signed_request_account | |||||
end | |||||
rescue OpenSSL::PKey::RSAError | |||||
nil | |||||
end | |||||
def build_signed_string(signed_headers) | def build_signed_string(signed_headers) | ||||
signed_headers = 'date' if signed_headers.blank? | signed_headers = 'date' if signed_headers.blank? | ||||
signed_headers.split(' ').map do |signed_header| | |||||
signed_headers.downcase.split(' ').map do |signed_header| | |||||
if signed_header == Request::REQUEST_TARGET | if signed_header == Request::REQUEST_TARGET | ||||
"#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}" | "#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}" | ||||
elsif signed_header == 'digest' | elsif signed_header == 'digest' | ||||
@@ -89,12 +113,12 @@ module SignatureVerification | |||||
def matches_time_window? | def matches_time_window? | ||||
begin | begin | ||||
time_sent = DateTime.httpdate(request.headers['Date']) | |||||
time_sent = Time.httpdate(request.headers['Date']) | |||||
rescue ArgumentError | rescue ArgumentError | ||||
return false | return false | ||||
end | end | ||||
(Time.now.utc - time_sent).abs <= 30 | |||||
(Time.now.utc - time_sent).abs <= 12.hours | |||||
end | end | ||||
def body_digest | def body_digest | ||||
@@ -119,4 +143,9 @@ module SignatureVerification | |||||
account | account | ||||
end | end | ||||
end | end | ||||
def account_refresh_key(account) | |||||
return if account.local? || !account.activitypub? | |||||
ActivityPub::FetchRemoteAccountService.new.call(account.uri, only_key: true) | |||||
end | |||||
end | end |
@@ -0,0 +1,10 @@ | |||||
# frozen_string_literal: true | |||||
class CustomCssController < ApplicationController | |||||
before_action :set_cache_headers | |||||
def show | |||||
skip_session! | |||||
render plain: Setting.custom_css || '', content_type: 'text/css' | |||||
end | |||||
end |
@@ -0,0 +1,43 @@ | |||||
# frozen_string_literal: true | |||||
class DirectoriesController < ApplicationController | |||||
layout 'public' | |||||
before_action :check_enabled | |||||
before_action :set_instance_presenter | |||||
before_action :set_tag, only: :show | |||||
before_action :set_tags | |||||
before_action :set_accounts | |||||
def index | |||||
render :index | |||||
end | |||||
def show | |||||
render :index | |||||
end | |||||
private | |||||
def check_enabled | |||||
return not_found unless Setting.profile_directory | |||||
end | |||||
def set_tag | |||||
@tag = Tag.discoverable.find_by!(name: params[:id].downcase) | |||||
end | |||||
def set_tags | |||||
@tags = Tag.discoverable.limit(30).reject { |tag| tag.cached_sample_accounts.empty? } | |||||
end | |||||
def set_accounts | |||||
@accounts = Account.discoverable.page(params[:page]).per(40).tap do |query| | |||||
query.merge!(Account.tagged_with(@tag.id)) if @tag | |||||
end | |||||
end | |||||
def set_instance_presenter | |||||
@instance_presenter = InstancePresenter.new | |||||
end | |||||
end |
@@ -9,7 +9,7 @@ class EmojisController < ApplicationController | |||||
format.json do | format.json do | ||||
skip_session! | skip_session! | ||||
render_cached_json(['activitypub', 'emoji', @emoji.cache_key], content_type: 'application/activity+json') do | |||||
render_cached_json(['activitypub', 'emoji', @emoji], content_type: 'application/activity+json') do | |||||
ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter) | ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter) | ||||
end | end | ||||
end | end | ||||
@@ -7,6 +7,7 @@ class FiltersController < ApplicationController | |||||
before_action :set_filters, only: :index | before_action :set_filters, only: :index | ||||
before_action :set_filter, only: [:edit, :update, :destroy] | before_action :set_filter, only: [:edit, :update, :destroy] | ||||
before_action :set_body_classes | |||||
def index | def index | ||||
@filters = current_account.custom_filters | @filters = current_account.custom_filters | ||||
@@ -52,6 +53,10 @@ class FiltersController < ApplicationController | |||||
end | end | ||||
def resource_params | def resource_params | ||||
params.require(:custom_filter).permit(:phrase, :expires_in, :irreversible, context: []) | |||||
params.require(:custom_filter).permit(:phrase, :expires_in, :irreversible, :whole_word, context: []) | |||||
end | |||||
def set_body_classes | |||||
@body_classes = 'admin' | |||||
end | end | ||||
end | end |
@@ -58,7 +58,7 @@ class HomeController < ApplicationController | |||||
if request.path.start_with?('/web') | if request.path.start_with?('/web') | ||||
new_user_session_path | new_user_session_path | ||||
elsif single_user_mode? | elsif single_user_mode? | ||||
short_account_path(Account.first) | |||||
short_account_path(Account.local.where(suspended: false).first) | |||||
else | else | ||||
about_path | about_path | ||||
end | end | ||||
@@ -8,7 +8,7 @@ class IntentsController < ApplicationController | |||||
if uri.scheme == 'web+mastodon' | if uri.scheme == 'web+mastodon' | ||||
case uri.host | case uri.host | ||||
when 'follow' | when 'follow' | ||||
return redirect_to authorize_follow_path(acct: uri.query_values['uri'].gsub(/\Aacct:/, '')) | |||||
return redirect_to authorize_interaction_path(uri: uri.query_values['uri'].gsub(/\Aacct:/, '')) | |||||
when 'share' | when 'share' | ||||
return redirect_to share_path(text: uri.query_values['text']) | return redirect_to share_path(text: uri.query_values['text']) | ||||
end | end | ||||
@@ -6,6 +6,7 @@ class InvitesController < ApplicationController | |||||
layout 'admin' | layout 'admin' | ||||
before_action :authenticate_user! | before_action :authenticate_user! | ||||
before_action :set_body_classes | |||||
def index | def index | ||||
authorize :invite, :create? | authorize :invite, :create? | ||||
@@ -38,10 +39,14 @@ class InvitesController < ApplicationController | |||||
private | private | ||||
def invites | def invites | ||||
Invite.where(user: current_user) | |||||
Invite.where(user: current_user).order(id: :desc) | |||||
end | end | ||||
def resource_params | def resource_params | ||||
params.require(:invite).permit(:max_uses, :expires_in, :autofollow) | params.require(:invite).permit(:max_uses, :expires_in, :autofollow) | ||||
end | end | ||||
def set_body_classes | |||||
@body_classes = 'admin' | |||||
end | |||||
end | end |
@@ -6,12 +6,17 @@ class MediaController < ApplicationController | |||||
before_action :set_media_attachment | before_action :set_media_attachment | ||||
before_action :verify_permitted_status! | before_action :verify_permitted_status! | ||||
content_security_policy only: :player do |p| | |||||
p.frame_ancestors(false) | |||||
end | |||||
def show | def show | ||||
redirect_to @media_attachment.file.url(:original) | redirect_to @media_attachment.file.url(:original) | ||||
end | end | ||||
def player | def player | ||||
@body_classes = 'player' | @body_classes = 'player' | ||||
response.headers['X-Frame-Options'] = 'ALLOWALL' | |||||
raise ActiveRecord::RecordNotFound unless @media_attachment.video? || @media_attachment.gifv? | raise ActiveRecord::RecordNotFound unless @media_attachment.video? || @media_attachment.gifv? | ||||
end | end | ||||
@@ -13,4 +13,18 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController | |||||
def store_current_location | def store_current_location | ||||
store_location_for(:user, request.url) | store_location_for(:user, request.url) | ||||
end | end | ||||
def render_success | |||||
if skip_authorization? || (matching_token? && !truthy_param?('force_login')) | |||||
redirect_or_render authorize_response | |||||
elsif Doorkeeper.configuration.api_only | |||||
render json: pre_auth | |||||
else | |||||
render :new | |||||
end | |||||
end | |||||
def truthy_param?(key) | |||||
ActiveModel::Type::Boolean.new.cast(params[key]) | |||||
end | |||||
end | end |