Compare commits

..

2 Commits

Author SHA1 Message Date
Surinna Curtis
4aa8d9d149 Remove workaround for fixed bug in SettingToggle
SettingToggle was toggling itself in response to keydown of space, and then the keyup was doing it again
2017-09-02 08:24:55 -05:00
Surinna Curtis
6ba67f92c9 UploadArea should only preventDefault for Escape
This will make accessibility for some things less effortful, since we won't have to define a prior event handler to do whatever should be happening by default.
2017-09-02 08:24:49 -05:00
6027 changed files with 15041 additions and 82195 deletions

View File

@@ -1,36 +1,21 @@
version: "2"
checks:
argument-count:
enabled: false
complex-logic:
enabled: false
file-lines:
enabled: false
method-complexity:
enabled: false
method-count:
enabled: false
method-lines:
enabled: false
nested-control-flow:
enabled: false
return-statements:
enabled: false
similar-code:
enabled: false
identical-code:
enabled: false
plugins:
engines:
brakeman:
enabled: true
bundler-audit:
enabled: true
duplication:
enabled: false
eslint:
enabled: true
rubocop:
enabled: true
scss-lint:
enabled: true
exclude_patterns:
ratings:
paths:
- "**.rb"
- "**.js"
- "**.scss"
exclude_paths:
- spec/
- vendor/asset

View File

@@ -35,17 +35,6 @@ PAPERCLIP_SECRET=$PAPERCLIP_SECRET
SECRET_KEY_BASE=$SECRET_KEY_BASE
OTP_SECRET=$OTP_SECRET
# VAPID keys (used for push notifications)
# You can generate the keys using the following command (first is the private key, second is the public one)
# You should only generate this once per instance. If you later decide to change it, all push subscription will
# be invalidated, requiring the users to access the website again to resubscribe.
#
# Generate with `rake mastodon:webpush:generate_vapid_key` task (`nanobox run bundle exec rake mastodon:webpush:generate_vapid_key`)
#
# For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html
VAPID_PRIVATE_KEY=$VAPID_PRIVATE_KEY
VAPID_PUBLIC_KEY=$VAPID_PUBLIC_KEY
# Registrations
# Single user mode will disable registrations and redirect frontpage to the first profile
# SINGLE_USER_MODE=true
@@ -73,7 +62,7 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
#SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt
#SMTP_OPENSSL_VERIFY_MODE=peer
#SMTP_ENABLE_STARTTLS_AUTO=true
#SMTP_TLS=true
# Optional user upload path and URL (images, avatars). Default is :rails_root/public/system. If you set this variable, you are responsible for making your HTTP server (eg. nginx) serve these files.
# PAPERCLIP_ROOT_PATH=/var/lib/mastodon/public-system
@@ -102,23 +91,6 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
# S3_ENDPOINT=
# S3_SIGNATURE_VERSION=
# Swift (optional)
# SWIFT_ENABLED=true
# SWIFT_USERNAME=
# For Keystone V3, the value for SWIFT_TENANT should be the project name
# SWIFT_TENANT=
# SWIFT_PASSWORD=
# Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid
# issues with token rate-limiting during high load.
# SWIFT_AUTH_URL=
# SWIFT_CONTAINER=
# SWIFT_OBJECT_URL=
# SWIFT_REGION=
# Defaults to 'default'
# SWIFT_DOMAIN_NAME=
# Defaults to 60 seconds. Set to 0 to disable
# SWIFT_CACHE_TTL=
# Optional alias for S3 if you want to use Cloudfront or Cloudflare in front
# S3_CLOUDFRONT_HOST=

View File

@@ -1,6 +1,5 @@
# Service dependencies
# You may set REDIS_URL instead for more advanced options
# You may also set REDIS_NAMESPACE to share Redis between multiple Mastodon servers
REDIS_HOST=redis
REDIS_PORT=6379
# You may set DATABASE_URL instead for more advanced options
@@ -11,11 +10,10 @@ DB_PASS=
DB_PORT=5432
# Federation
# Note: Changing LOCAL_DOMAIN at a later time will cause unwanted side effects, including breaking all existing federation.
# Note: Changing LOCAL_DOMAIN or LOCAL_HTTPS at a later time will cause unwanted side effects.
# LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com.
LOCAL_DOMAIN=example.com
# Changing LOCAL_HTTPS in production is no longer supported. (Mastodon will always serve https:// links)
LOCAL_HTTPS=true
# Use this only if you need to run mastodon on a different domain than the one used for federation.
# You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md
@@ -28,7 +26,7 @@ LOCAL_DOMAIN=example.com
# ALTERNATE_DOMAINS=example1.com,example2.com
# Application secrets
# Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
# Generate each with the `rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
PAPERCLIP_SECRET=
SECRET_KEY_BASE=
OTP_SECRET=
@@ -38,7 +36,7 @@ OTP_SECRET=
# You should only generate this once per instance. If you later decide to change it, all push subscription will
# be invalidated, requiring the users to access the website again to resubscribe.
#
# Generate with `RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose)
# Generate with `rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose)
#
# For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html
VAPID_PRIVATE_KEY=
@@ -100,23 +98,6 @@ SMTP_FROM_ADDRESS=notifications@example.com
# S3_ENDPOINT=
# S3_SIGNATURE_VERSION=
# Swift (optional)
# SWIFT_ENABLED=true
# SWIFT_USERNAME=
# For Keystone V3, the value for SWIFT_TENANT should be the project name
# SWIFT_TENANT=
# SWIFT_PASSWORD=
# Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid
# issues with token rate-limiting during high load.
# SWIFT_AUTH_URL=
# SWIFT_CONTAINER=
# SWIFT_OBJECT_URL=
# SWIFT_REGION=
# Defaults to 'default'
# SWIFT_DOMAIN_NAME=
# Defaults to 60 seconds. Set to 0 to disable
# SWIFT_CACHE_TTL=
# Optional alias for S3 if you want to use Cloudfront or Cloudflare in front
# S3_CLOUDFRONT_HOST=
@@ -135,6 +116,3 @@ STREAMING_CLUSTER_NUM=1
# If you use Docker, you may want to assign UID/GID manually.
# UID=1000
# GID=1000
# Maximum allowed character count
# MAX_TOOT_CHARS=500

View File

@@ -5,14 +5,12 @@ env:
browser: true
node: true
es6: true
jest: true
parser: babel-eslint
plugins:
- react
- jsx-a11y
- import
parserOptions:
sourceType: module
@@ -23,19 +21,8 @@ parserOptions:
modules: true
spread: true
settings:
import/extensions:
- .js
import/ignore:
- node_modules
- \\.(css|scss|json)$
import/resolver:
node:
moduleDirectory:
- node_modules
- app/javascript
rules:
brace-style: warn
comma-dangle:
- error
@@ -138,17 +125,3 @@ rules:
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

32
.github/CODEOWNERS vendored
View File

@@ -1,32 +0,0 @@
# CODEOWNERS for tootsuite/mastodon
# Translators
# To add translator, copy these lines, replace `fr` with appropriate language code and replace `@żelipapą` with user's GitHub nickname preceded by `@` sign or e-mail address.
# /app/javascript/mastodon/locales/fr.json @żelipapą
# /app/views/user_mailer/*.fr.html.erb @żelipapą
# /app/views/user_mailer/*.fr.text.erb @żelipapą
# /config/locales/*.fr.yml @żelipapą
# /config/locales/fr.yml @żelipapą
# Polish
/app/javascript/mastodon/locales/pl.json @m4sk1n
/app/views/user_mailer/*.pl.html.erb @m4sk1n
/app/views/user_mailer/*.pl.text.erb @m4sk1n
/config/locales/*.pl.yml @m4sk1n
/config/locales/pl.yml @m4sk1n
# French
/app/javascript/mastodon/locales/fr.json @aldarone
/app/javascript/mastodon/locales/whitelist_fr.json @aldarone
/app/views/user_mailer/*.fr.html.erb @aldarone
/app/views/user_mailer/*.fr.text.erb @aldarone
/config/locales/*.fr.yml @aldarone
/config/locales/fr.yml @aldarone
# Dutch
/app/javascript/mastodon/locales/nl.json @jeroenpraat
/app/javascript/mastodon/locales/whitelist_nl.json @jeroenpraat
/app/views/user_mailer/*.nl.html.erb @jeroenpraat
/app/views/user_mailer/*.nl.text.erb @jeroenpraat
/config/locales/*.nl.yml @jeroenpraat
/config/locales/nl.yml @jeroenpraat

0
.gitmodules vendored
View File

View File

@@ -1 +1 @@
2.4.2
2.4.1

View File

@@ -26,25 +26,25 @@ addons:
postgresql: 9.4
apt:
sources:
- ubuntu-toolchain-r-test
- trusty-media
- sourceline: deb https://dl.yarnpkg.com/debian/ stable main
key_url: https://dl.yarnpkg.com/debian/pubkey.gpg
packages:
- ffmpeg
- libicu-dev
- g++-6
- libprotobuf-dev
- protobuf-compiler
- yarn
- libicu-dev
rvm:
- 2.3.4
- 2.4.2
- 2.4.1
services:
- redis-server
install:
- nvm install
- npm install -g yarn
- bundle install --path=vendor/bundle --without development production --retry=3 --jobs=16
- yarn install
@@ -55,5 +55,5 @@ before_script:
script:
- travis_retry bundle exec parallel_test spec/ --group-by filesize --type rspec
- yarn test
- bundle exec i18n-tasks check-normalized && bundle exec i18n-tasks unused
- npm test
- bundle exec i18n-tasks unused

View File

@@ -1,46 +0,0 @@
# test directories
__tests__
test
tests
powered-test
# asset directories
docs
doc
website
images
# assets
# examples
example
examples
# code coverage directories
coverage
.nyc_output
# build scripts
Makefile
Gulpfile.js
Gruntfile.js
# configs
.tern-project
.gitattributes
.editorconfig
.*ignore
.eslintrc
.jshintrc
.flowconfig
.documentup.json
.yarn-metadata.json
.*.yml
*.yml
# misc
*.gz
*.md
# for specific ignore
!.svgo.yml

View File

@@ -1,5 +1,4 @@
ffmpeg
libicu[0-9][0-9]
libicu-dev
libidn11
libidn11-dev

15
CODEOWNERS Normal file
View File

@@ -0,0 +1,15 @@
# CODEOWNERS for tootsuite/mastodon
# Translators
# To add translator, copy these lines, replace `fr` with appropriate language code and replace `@żelipapą` with user's GitHub nickname preceded by `@` sign or e-mail address.
# /app/javascript/mastodon/locales/fr.json @żelipapą
# /app/views/user_mailer/*.fr.html.erb @żelipapą
# /app/views/user_mailer/*.fr.text.erb @żelipapą
# /config/locales/*.fr.yml @żelipapą
# /config/locales/fr.yml @żelipapą
/app/javascript/mastodon/locales/pl.json @m4sk1n
/app/views/user_mailer/*.pl.html.erb @m4sk1n
/app/views/user_mailer/*.pl.text.erb @m4sk1n
/config/locales/*.pl.yml @m4sk1n
/config/locales/pl.yml @m4sk1n

View File

@@ -1,46 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at beatrix.bitrot@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -1,36 +1,3 @@
# Contributing to Mastodon Glitch Edition #
Thank you for your interest in contributing to the `glitch-soc` project!
Here are some guidelines, and ways you can help.
> (This document is a bit of a work-in-progress, so please bear with us.
> If you don't see what you're looking for here, please don't hesitate to reach out!)
## Planning ##
Right now a lot of the planning for this project takes place in our development Discord, or through GitHub Issues and Projects.
We're working on ways to improve the planning structure and better solicit feedback, and if you feel like you can help in this respect, feel free to give us a holler.
## Documentation ##
The documentation for this repository is available at [`glitch-soc/docs`](https://github.com/glitch-soc/docs) (online at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/)).
Right now, we've mostly focused on the features that make this fork different from upstream in some manner.
Adding screenshots, improving descriptions, and so forth are all ways to help contribute to the project even if you don't know any code.
## Frontend Development ##
Check out [the documentation here](https://glitch-soc.github.io/docs/contributing/frontend/) for more information.
## Backend Development ##
See the guidelines below.
- - -
You should also try to follow the guidelines set out in the original `CONTRIBUTING.md` from `tootsuite/mastodon`, reproduced below.
<blockquote>
CONTRIBUTING
============
@@ -82,5 +49,3 @@ It is expected that you have a working development environment set up (see back-
* If you are introducing new strings, they must be using localization methods
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.
</blockquote>

View File

@@ -1,4 +1,4 @@
FROM ruby:2.4.2-alpine3.6
FROM ruby:2.4.1-alpine3.6
LABEL maintainer="https://github.com/tootsuite/mastodon" \
description="A GNU Social-compatible microblogging server"
@@ -7,8 +7,6 @@ ENV UID=991 GID=991 \
RAILS_SERVE_STATIC_FILES=true \
RAILS_ENV=production NODE_ENV=production
ARG YARN_VERSION=1.3.2
ARG YARN_DOWNLOAD_SHA256=6cfe82e530ef0837212f13e45c1565ba53f5199eec2527b85ecbcd88bf26821d
ARG LIBICONV_VERSION=1.15
ARG LIBICONV_DOWNLOAD_SHA256=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178
@@ -21,7 +19,6 @@ RUN apk -U upgrade \
build-base \
icu-dev \
libidn-dev \
libressl \
libtool \
postgresql-dev \
protobuf-dev \
@@ -35,21 +32,16 @@ RUN apk -U upgrade \
imagemagick \
libidn \
libpq \
nodejs \
nodejs-npm \
nodejs \
protobuf \
su-exec \
tini \
yarn \
&& 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 \
&& wget -O libiconv.tar.gz "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-$LIBICONV_VERSION.tar.gz" \
&& wget -O libiconv.tar.gz "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-$LIBICONV_VERSION.tar.gz" \
&& echo "$LIBICONV_DOWNLOAD_SHA256 *libiconv.tar.gz" | sha256sum -c - \
&& mkdir -p /tmp/src \
&& tar -xzf libiconv.tar.gz -C /tmp/src \
&& rm libiconv.tar.gz \
&& cd /tmp/src/libiconv-$LIBICONV_VERSION \
@@ -60,12 +52,11 @@ RUN apk -U upgrade \
&& cd /mastodon \
&& rm -rf /tmp/* /var/cache/apk/*
COPY Gemfile Gemfile.lock package.json yarn.lock .yarnclean /mastodon/
COPY Gemfile Gemfile.lock package.json yarn.lock /mastodon/
RUN bundle config build.nokogiri --with-iconv-lib=/usr/local/lib --with-iconv-include=/usr/local/include \
&& bundle install -j$(getconf _NPROCESSORS_ONLN) --deployment --without test development \
&& yarn --pure-lockfile \
&& yarn cache clean
&& yarn --ignore-optional --pure-lockfile
COPY . /mastodon

52
Gemfile
View File

@@ -5,8 +5,8 @@ ruby '>= 2.3.0', '< 2.5.0'
gem 'pkg-config', '~> 1.2'
gem 'puma', '~> 3.10'
gem 'rails', '~> 5.1.4'
gem 'puma', '~> 3.8'
gem 'rails', '~> 5.1.0'
gem 'uglifier', '~> 3.2'
gem 'hamlit-rails', '~> 0.2'
@@ -14,22 +14,17 @@ gem 'pg', '~> 0.20'
gem 'pghero', '~> 1.7'
gem 'dotenv-rails', '~> 2.2'
gem 'aws-sdk', '~> 2.10', require: false
gem 'fog-core', '~> 1.45'
gem 'fog-local', '~> 0.4', require: false
gem 'fog-openstack', '~> 0.1', require: false
gem 'aws-sdk', '~> 2.9'
gem 'paperclip', '~> 5.1'
gem 'paperclip-av-transcoder', '~> 0.6'
gem 'posix-spawn'
gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.5'
gem 'bootsnap'
gem 'browser'
gem 'charlock_holmes', '~> 0.7.5'
gem 'iso-639'
gem 'cld3', '~> 3.2.0'
gem 'devise', '~> 4.3'
gem 'cld3', '~> 3.1'
gem 'devise', '~> 4.2'
gem 'devise-two-factor', '~> 3.0'
gem 'doorkeeper', '~> 4.2'
gem 'fast_blank', '~> 1.0'
@@ -41,15 +36,15 @@ gem 'http', '~> 2.2'
gem 'http_accept_language', '~> 2.1'
gem 'httplog', '~> 0.99'
gem 'idn-ruby', require: 'idn'
gem 'kaminari', '~> 1.1'
gem 'kaminari', '~> 1.0'
gem 'link_header', '~> 0.0'
gem 'mime-types', '~> 3.1'
gem 'nokogiri', '~> 1.8'
gem 'nsa', '~> 0.2'
gem 'oj', '~> 3.3'
gem 'nokogiri', '~> 1.7'
gem 'oj', '~> 3.0'
gem 'ostatus2', '~> 2.0'
gem 'ox', '~> 2.8'
gem 'ox', '~> 2.5'
gem 'pundit', '~> 1.1'
gem 'rabl', '~> 0.13'
gem 'rack-attack', '~> 5.0'
gem 'rack-cors', '~> 0.4', require: 'rack/cors'
gem 'rack-timeout', '~> 0.4'
@@ -59,7 +54,6 @@ gem 'redis', '~> 3.3', require: ['redis', 'redis/connection/hiredis']
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'rqrcode', '~> 0.10'
gem 'ruby-oembed', '~> 0.12', require: 'oembed'
gem 'ruby-progressbar', '~> 1.4'
gem 'sanitize', '~> 4.4'
gem 'sidekiq', '~> 5.0'
gem 'sidekiq-scheduler', '~> 2.1'
@@ -68,25 +62,25 @@ gem 'sidekiq-bulk', '~>0.1.1'
gem 'simple-navigation', '~> 4.0'
gem 'simple_form', '~> 3.4'
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
gem 'strong_migrations'
gem 'statsd-instrument', '~> 2.1'
gem 'twitter-text', '~> 1.14'
gem 'tzinfo-data', '~> 1.2017'
gem 'webpacker', '~> 3.0'
gem 'webpacker', '~> 2.0'
gem 'webpush'
gem 'json-ld-preloaded', '~> 2.2.1'
gem 'rdf-normalize', '~> 0.3.1'
group :development, :test do
gem 'fabrication', '~> 2.18'
gem 'fabrication', '~> 2.16'
gem 'fuubar', '~> 2.2'
gem 'i18n-tasks', '~> 0.9', require: false
gem 'pry-rails', '~> 0.3'
gem 'rspec-rails', '~> 3.7'
gem 'rspec-rails', '~> 3.6'
end
group :test do
gem 'capybara', '~> 2.15'
gem 'capybara', '~> 2.14'
gem 'climate_control', '~> 0.2'
gem 'faker', '~> 1.7'
gem 'microformats', '~> 4.0'
@@ -94,29 +88,29 @@ group :test do
gem 'rspec-sidekiq', '~> 3.0'
gem 'simplecov', '~> 0.14', require: false
gem 'webmock', '~> 3.0'
gem 'parallel_tests', '~> 2.17'
gem 'parallel_tests', '~> 2.14'
end
group :development do
gem 'active_record_query_trace', '~> 1.5'
gem 'annotate', '~> 2.7'
gem 'better_errors', '~> 2.4'
gem 'better_errors', '~> 2.1'
gem 'binding_of_caller', '~> 0.7'
gem 'bullet', '~> 5.5'
gem 'letter_opener', '~> 1.4'
gem 'letter_opener_web', '~> 1.3'
gem 'rubocop', require: false
gem 'brakeman', '~> 4.0', require: false
gem 'bundler-audit', '~> 0.6', require: false
gem 'scss_lint', '~> 0.55', require: false
gem 'brakeman', '~> 3.6', require: false
gem 'bundler-audit', '~> 0.5', require: false
gem 'scss_lint', '~> 0.53', require: false
gem 'capistrano', '~> 3.10'
gem 'capistrano-rails', '~> 1.3'
gem 'capistrano', '~> 3.8'
gem 'capistrano-rails', '~> 1.2'
gem 'capistrano-rbenv', '~> 2.1'
gem 'capistrano-yarn', '~> 2.0'
end
group :production do
gem 'lograge', '~> 0.7'
gem 'lograge', '~> 0.5'
gem 'redis-rails', '~> 5.0'
end

View File

@@ -1,45 +1,45 @@
GEM
remote: https://rubygems.org/
specs:
actioncable (5.1.4)
actionpack (= 5.1.4)
actioncable (5.1.3)
actionpack (= 5.1.3)
nio4r (~> 2.0)
websocket-driver (~> 0.6.1)
actionmailer (5.1.4)
actionpack (= 5.1.4)
actionview (= 5.1.4)
activejob (= 5.1.4)
actionmailer (5.1.3)
actionpack (= 5.1.3)
actionview (= 5.1.3)
activejob (= 5.1.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.1.4)
actionview (= 5.1.4)
activesupport (= 5.1.4)
actionpack (5.1.3)
actionview (= 5.1.3)
activesupport (= 5.1.3)
rack (~> 2.0)
rack-test (>= 0.6.3)
rack-test (~> 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.1.4)
activesupport (= 5.1.4)
actionview (5.1.3)
activesupport (= 5.1.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_model_serializers (0.10.7)
active_model_serializers (0.10.6)
actionpack (>= 4.1, < 6)
activemodel (>= 4.1, < 6)
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
jsonapi-renderer (>= 0.1.1.beta1, < 0.2)
active_record_query_trace (1.5.4)
activejob (5.1.4)
activesupport (= 5.1.4)
activejob (5.1.3)
activesupport (= 5.1.3)
globalid (>= 0.3.6)
activemodel (5.1.4)
activesupport (= 5.1.4)
activerecord (5.1.4)
activemodel (= 5.1.4)
activesupport (= 5.1.4)
activemodel (5.1.3)
activesupport (= 5.1.3)
activerecord (5.1.3)
activemodel (= 5.1.3)
activesupport (= 5.1.3)
arel (~> 8.0)
activesupport (5.1.4)
activesupport (5.1.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
minitest (~> 5.1)
@@ -57,51 +57,51 @@ GEM
encryptor (~> 3.0.0)
av (0.9.0)
cocaine (~> 0.5.3)
aws-sdk (2.10.100)
aws-sdk-resources (= 2.10.100)
aws-sdk-core (2.10.100)
aws-sdk (2.10.21)
aws-sdk-resources (= 2.10.21)
aws-sdk-core (2.10.21)
aws-sigv4 (~> 1.0)
jmespath (~> 1.0)
aws-sdk-resources (2.10.100)
aws-sdk-core (= 2.10.100)
aws-sigv4 (1.0.2)
aws-sdk-resources (2.10.21)
aws-sdk-core (= 2.10.21)
aws-sigv4 (1.0.1)
bcrypt (3.1.11)
better_errors (2.4.0)
better_errors (2.1.1)
coderay (>= 1.0.0)
erubi (>= 1.0.0)
erubis (>= 2.6.6)
rack (>= 0.9.0)
binding_of_caller (0.7.3)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
bootsnap (1.1.5)
bootsnap (1.1.2)
msgpack (~> 1.0)
brakeman (4.0.1)
browser (2.5.2)
brakeman (3.7.2)
browser (2.4.0)
builder (3.2.3)
bullet (5.6.1)
bullet (5.5.1)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.10.0)
bundler-audit (0.6.0)
bundler (~> 1.2)
thor (~> 0.18)
capistrano (3.10.0)
capistrano (3.8.2)
airbrussh (>= 1.0.0)
i18n
rake (>= 10.0.0)
sshkit (>= 1.9.0)
capistrano-bundler (1.3.0)
capistrano-bundler (1.2.0)
capistrano (~> 3.1)
sshkit (~> 1.2)
capistrano-rails (1.3.1)
capistrano-rails (1.3.0)
capistrano (~> 3.1)
capistrano-bundler (~> 1.1)
capistrano-rbenv (2.1.3)
capistrano-rbenv (2.1.1)
capistrano (~> 3.1)
sshkit (~> 1.3)
capistrano-yarn (2.0.2)
capistrano (~> 3.0)
capybara (2.16.1)
capybara (2.14.4)
addressable
mini_mime (>= 0.1.3)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
@@ -110,18 +110,18 @@ GEM
activesupport
charlock_holmes (0.7.5)
chunky_png (1.3.8)
cld3 (3.2.1)
cld3 (3.1.3)
ffi (>= 1.1.0, < 1.10.0)
climate_control (0.2.0)
cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0)
coderay (1.1.2)
coderay (1.1.1)
colorize (0.8.1)
concurrent-ruby (1.0.5)
connection_pool (2.2.1)
crack (0.4.3)
safe_yaml (~> 1.0.0)
crass (1.0.3)
crass (1.0.2)
debug_inspector (0.0.3)
devise (4.3.0)
bcrypt (~> 3.0)
@@ -129,11 +129,11 @@ GEM
railties (>= 4.1.0, < 5.2)
responders
warden (~> 1.2.3)
devise-two-factor (3.0.2)
activesupport (< 5.2)
devise-two-factor (3.0.0)
activesupport
attr_encrypted (>= 1.3, < 4, != 2)
devise (~> 4.0)
railties (< 5.2)
railties
rotp (~> 2.0)
diff-lcs (1.3)
docile (1.1.5)
@@ -150,41 +150,27 @@ GEM
thread
thread_safe
encryptor (3.0.0)
erubi (1.7.0)
et-orbi (1.0.8)
erubi (1.6.1)
erubis (2.7.0)
et-orbi (1.0.5)
tzinfo
excon (0.59.0)
execjs (2.7.0)
fabrication (2.18.0)
faker (1.8.4)
fabrication (2.16.2)
faker (1.7.3)
i18n (~> 0.5)
fast_blank (1.0.0)
ffi (1.9.18)
fog-core (1.45.0)
builder
excon (~> 0.58)
formatador (~> 0.2)
fog-json (1.0.2)
fog-core (~> 1.0)
multi_json (~> 1.10)
fog-local (0.4.0)
fog-core (~> 1.27)
fog-openstack (0.1.22)
fog-core (>= 1.40)
fog-json (>= 1.0)
ipaddress (>= 0.8)
formatador (0.2.5)
fuubar (2.2.0)
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
globalid (0.4.1)
globalid (0.4.0)
activesupport (>= 4.2.0)
goldfinger (2.0.1)
addressable (~> 2.5)
http (~> 2.2)
nokogiri (~> 1.8)
oj (~> 3.0)
hamlit (2.8.5)
hamlit (2.8.4)
temple (>= 0.8.0)
thor
tilt
@@ -195,8 +181,8 @@ GEM
railties (>= 4.0.1)
hamster (3.0.0)
concurrent-ruby (~> 1.0)
hashdiff (0.3.7)
highline (1.7.10)
hashdiff (0.3.5)
highline (1.7.8)
hiredis (0.6.1)
hkdf (0.3.0)
htmlentities (4.3.4)
@@ -213,44 +199,41 @@ GEM
httplog (0.99.7)
colorize
rack
i18n (0.9.1)
concurrent-ruby (~> 1.0)
i18n-tasks (0.9.19)
i18n (0.8.6)
i18n-tasks (0.9.16)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
easy_translate (>= 0.5.0)
erubi
erubis
highline (>= 1.7.3)
i18n
parser (>= 2.2.3.0)
rainbow (~> 2.2)
terminal-table (>= 1.5.1)
idn-ruby (0.1.0)
ipaddress (0.8.3)
iso-639 (0.2.8)
jmespath (1.3.1)
json (2.1.0)
json-ld (2.1.7)
json-ld (2.1.5)
multi_json (~> 1.12)
rdf (~> 2.2, >= 2.2.8)
json-ld-preloaded (2.2.2)
rdf (~> 2.2)
json-ld-preloaded (2.2.1)
json-ld (~> 2.1, >= 2.1.5)
multi_json (~> 1.11)
rdf (~> 2.2)
jsonapi-renderer (0.2.0)
jwt (2.1.0)
kaminari (1.1.1)
jsonapi-renderer (0.1.3)
jwt (1.5.6)
kaminari (1.0.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.1.1)
kaminari-activerecord (= 1.1.1)
kaminari-core (= 1.1.1)
kaminari-actionview (1.1.1)
kaminari-actionview (= 1.0.1)
kaminari-activerecord (= 1.0.1)
kaminari-core (= 1.0.1)
kaminari-actionview (1.0.1)
actionview
kaminari-core (= 1.1.1)
kaminari-activerecord (1.1.1)
kaminari-core (= 1.0.1)
kaminari-activerecord (1.0.1)
activerecord
kaminari-core (= 1.1.1)
kaminari-core (1.1.1)
kaminari-core (= 1.0.1)
kaminari-core (1.0.1)
launchy (2.4.3)
addressable (~> 2.3)
letter_opener (1.4.1)
@@ -260,19 +243,17 @@ GEM
letter_opener (~> 1.0)
railties (>= 3.2)
link_header (0.0.8)
lograge (0.7.1)
lograge (0.5.1)
actionpack (>= 4, < 5.2)
activesupport (>= 4, < 5.2)
railties (>= 4, < 5.2)
request_store (~> 1.0)
loofah (2.1.1)
crass (~> 1.0.2)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.7.0)
mini_mime (>= 0.1.1)
mail (2.6.6)
mime-types (>= 1.16, < 4)
mario-redis-lock (1.2.0)
redis (~> 3, >= 3.0.5)
method_source (0.9.0)
method_source (0.8.2)
microformats (4.0.7)
json
nokogiri
@@ -280,33 +261,27 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
mini_mime (1.0.0)
mini_portile2 (2.3.0)
mini_portile2 (2.2.0)
minitest (5.10.3)
msgpack (1.1.0)
multi_json (1.12.2)
multi_json (1.12.1)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (4.2.0)
net-ssh (4.1.0)
nio4r (2.1.0)
nokogiri (1.8.1)
mini_portile2 (~> 2.3.0)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
nokogumbo (1.4.13)
nokogiri
nsa (0.2.4)
activesupport (>= 4.2, < 6)
concurrent-ruby (~> 1.0.0)
sidekiq (>= 3.5.0)
statsd-ruby (~> 1.2.0)
oj (3.3.9)
openssl (2.0.6)
oj (3.3.4)
openssl (2.0.4)
orm_adapter (0.5.0)
ostatus2 (2.0.1)
addressable (~> 2.4)
http (~> 2.0)
nokogiri (~> 1.6)
openssl (~> 2.0)
ox (2.8.2)
ox (2.5.0)
paperclip (5.1.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
@@ -316,48 +291,48 @@ GEM
paperclip-av-transcoder (0.6.4)
av (~> 0.9.0)
paperclip (>= 2.5.2)
parallel (1.12.0)
parallel_tests (2.19.0)
parallel (1.11.2)
parallel_tests (2.14.2)
parallel
parser (2.4.0.2)
ast (~> 2.3)
parser (2.4.0.0)
ast (~> 2.2)
pg (0.21.0)
pghero (1.7.0)
activerecord
pkg-config (1.2.8)
posix-spawn (0.3.13)
pkg-config (1.2.4)
powerpack (0.1.1)
pry (0.11.3)
pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pry-rails (0.3.6)
pry (>= 0.10.4)
public_suffix (3.0.1)
puma (3.11.0)
public_suffix (3.0.0)
puma (3.9.1)
pundit (1.1.0)
activesupport (>= 3.0.0)
rabl (0.13.1)
activesupport (>= 2.3.14)
rack (2.0.3)
rack-attack (5.0.1)
rack
rack-cors (0.4.1)
rack-protection (2.0.0)
rack
rack-proxy (0.6.2)
rack
rack-test (0.8.2)
rack (>= 1.0, < 3)
rack-test (0.6.3)
rack (>= 1.0)
rack-timeout (0.4.2)
rails (5.1.4)
actioncable (= 5.1.4)
actionmailer (= 5.1.4)
actionpack (= 5.1.4)
actionview (= 5.1.4)
activejob (= 5.1.4)
activemodel (= 5.1.4)
activerecord (= 5.1.4)
activesupport (= 5.1.4)
rails (5.1.3)
actioncable (= 5.1.3)
actionmailer (= 5.1.3)
actionpack (= 5.1.3)
actionview (= 5.1.3)
activejob (= 5.1.3)
activemodel (= 5.1.3)
activerecord (= 5.1.3)
activesupport (= 5.1.3)
bundler (>= 1.3.0)
railties (= 5.1.4)
railties (= 5.1.3)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1)
@@ -373,78 +348,74 @@ GEM
railties (~> 5.0)
rails-settings-cached (0.6.6)
rails (>= 4.2.0)
railties (5.1.4)
actionpack (= 5.1.4)
activesupport (= 5.1.4)
railties (5.1.3)
actionpack (= 5.1.3)
activesupport (= 5.1.3)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.2.2)
rake
rake (12.3.0)
rb-fsevent (0.10.2)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
rdf (2.2.12)
rake (12.0.0)
rdf (2.2.8)
hamster (~> 3.0)
link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.3.2)
rdf (~> 2.0)
redis (3.3.5)
redis-actionpack (5.0.2)
redis (3.3.3)
redis-actionpack (5.0.1)
actionpack (>= 4.0, < 6)
redis-rack (>= 1, < 3)
redis-store (>= 1.1.0, < 2)
redis-activesupport (5.0.4)
redis-store (>= 1.1.0, < 1.4.0)
redis-activesupport (5.0.3)
activesupport (>= 3, < 6)
redis-store (>= 1.3, < 2)
redis-namespace (1.6.0)
redis (>= 3.0.4)
redis-rack (2.0.3)
redis-store (~> 1.3.0)
redis-namespace (1.5.3)
redis (~> 3.0, >= 3.0.4)
redis-rack (2.0.2)
rack (>= 1.5, < 3)
redis-store (>= 1.2, < 2)
redis-store (>= 1.2, < 1.4)
redis-rails (5.0.2)
redis-actionpack (>= 5.0, < 6)
redis-activesupport (>= 5.0, < 6)
redis-store (>= 1.2, < 2)
redis-store (1.4.1)
redis (>= 2.2, < 5)
request_store (1.3.2)
redis-store (1.3.0)
redis (>= 2.2)
responders (2.4.0)
actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 5.3)
rotp (2.1.2)
rqrcode (0.10.1)
chunky_png (~> 1.0)
rspec-core (3.7.0)
rspec-support (~> 3.7.0)
rspec-expectations (3.7.0)
rspec-core (3.6.0)
rspec-support (~> 3.6.0)
rspec-expectations (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-mocks (3.7.0)
rspec-support (~> 3.6.0)
rspec-mocks (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-rails (3.7.2)
rspec-support (~> 3.6.0)
rspec-rails (3.6.0)
actionpack (>= 3.0)
activesupport (>= 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.6.0)
rspec-expectations (~> 3.6.0)
rspec-mocks (~> 3.6.0)
rspec-support (~> 3.6.0)
rspec-sidekiq (3.0.3)
rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0)
rspec-support (3.7.0)
rubocop (0.51.0)
rspec-support (3.6.0)
rubocop (0.49.1)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 2.2.2, < 3.0)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-oembed (0.12.0)
ruby-progressbar (1.9.0)
ruby-progressbar (1.8.1)
rufus-scheduler (3.4.2)
et-orbi (~> 1.0)
safe_yaml (1.0.4)
@@ -452,28 +423,24 @@ GEM
crass (~> 1.0.2)
nokogiri (>= 1.4.4)
nokogumbo (~> 1.4.1)
sass (3.5.3)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
scss_lint (0.56.0)
sass (3.4.24)
scss_lint (0.54.0)
rake (>= 0.9, < 13)
sass (~> 3.5.3)
sidekiq (5.0.5)
sass (~> 3.4.20)
sidekiq (5.0.4)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0)
redis (>= 3.3.4, < 5)
redis (~> 3.3, >= 3.3.3)
sidekiq-bulk (0.1.1)
activesupport
sidekiq
sidekiq-scheduler (2.1.10)
redis (>= 3, < 5)
sidekiq-scheduler (2.1.8)
redis (~> 3)
rufus-scheduler (~> 3.2)
sidekiq (>= 3)
tilt (>= 1.4.0)
sidekiq-unique-jobs (5.0.10)
sidekiq-unique-jobs (5.0.9)
sidekiq (>= 4.0, <= 6.0)
thor (~> 0)
simple-navigation (4.0.5)
@@ -481,24 +448,23 @@ GEM
simple_form (3.5.0)
actionpack (> 4, < 5.2)
activemodel (> 4, < 5.2)
simplecov (0.15.1)
simplecov (0.14.1)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
simplecov-html (0.10.1)
slop (3.6.0)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
sprockets-rails (3.2.0)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sshkit (1.15.1)
sshkit (1.13.1)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
statsd-ruby (1.2.1)
strong_migrations (0.1.9)
activerecord (>= 3.2.0)
statsd-instrument (2.1.4)
temple (0.8.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
@@ -508,9 +474,9 @@ GEM
tilt (2.0.8)
twitter-text (1.14.7)
unf (~> 0.1.0)
tzinfo (1.2.4)
tzinfo (1.2.3)
thread_safe (~> 0.1)
tzinfo-data (1.2017.3)
tzinfo-data (1.2017.2)
tzinfo (>= 1.0.0)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
@@ -521,20 +487,20 @@ GEM
uniform_notifier (1.10.0)
warden (1.2.7)
rack (>= 1.0)
webmock (3.1.1)
webmock (3.0.1)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
webpacker (3.0.2)
webpacker (2.0)
activesupport (>= 4.2)
rack-proxy (>= 0.6.1)
multi_json (~> 1.2)
railties (>= 4.2)
webpush (0.3.3)
webpush (0.3.2)
hkdf (~> 0.2)
jwt (~> 2.0)
jwt
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
websocket-extensions (0.1.2)
xpath (2.1.0)
nokogiri (~> 1.3)
@@ -546,32 +512,29 @@ DEPENDENCIES
active_record_query_trace (~> 1.5)
addressable (~> 2.5)
annotate (~> 2.7)
aws-sdk (~> 2.10)
better_errors (~> 2.4)
aws-sdk (~> 2.9)
better_errors (~> 2.1)
binding_of_caller (~> 0.7)
bootsnap
brakeman (~> 4.0)
brakeman (~> 3.6)
browser
bullet (~> 5.5)
bundler-audit (~> 0.6)
capistrano (~> 3.10)
capistrano-rails (~> 1.3)
bundler-audit (~> 0.5)
capistrano (~> 3.8)
capistrano-rails (~> 1.2)
capistrano-rbenv (~> 2.1)
capistrano-yarn (~> 2.0)
capybara (~> 2.15)
capybara (~> 2.14)
charlock_holmes (~> 0.7.5)
cld3 (~> 3.2.0)
cld3 (~> 3.1)
climate_control (~> 0.2)
devise (~> 4.3)
devise (~> 4.2)
devise-two-factor (~> 3.0)
doorkeeper (~> 4.2)
dotenv-rails (~> 2.2)
fabrication (~> 2.18)
fabrication (~> 2.16)
faker (~> 1.7)
fast_blank (~> 1.0)
fog-core (~> 1.45)
fog-local (~> 0.4)
fog-openstack (~> 0.1)
fuubar (~> 2.2)
goldfinger (~> 2.0)
hamlit-rails (~> 0.2)
@@ -582,35 +545,33 @@ DEPENDENCIES
httplog (~> 0.99)
i18n-tasks (~> 0.9)
idn-ruby
iso-639
json-ld-preloaded (~> 2.2.1)
kaminari (~> 1.1)
kaminari (~> 1.0)
letter_opener (~> 1.4)
letter_opener_web (~> 1.3)
link_header (~> 0.0)
lograge (~> 0.7)
lograge (~> 0.5)
mario-redis-lock (~> 1.2)
microformats (~> 4.0)
mime-types (~> 3.1)
nokogiri (~> 1.8)
nsa (~> 0.2)
oj (~> 3.3)
nokogiri (~> 1.7)
oj (~> 3.0)
ostatus2 (~> 2.0)
ox (~> 2.8)
ox (~> 2.5)
paperclip (~> 5.1)
paperclip-av-transcoder (~> 0.6)
parallel_tests (~> 2.17)
parallel_tests (~> 2.14)
pg (~> 0.20)
pghero (~> 1.7)
pkg-config (~> 1.2)
posix-spawn
pry-rails (~> 0.3)
puma (~> 3.10)
puma (~> 3.8)
pundit (~> 1.1)
rabl (~> 0.13)
rack-attack (~> 5.0)
rack-cors (~> 0.4)
rack-timeout (~> 0.4)
rails (~> 5.1.4)
rails (~> 5.1.0)
rails-controller-testing (~> 1.0)
rails-i18n (~> 5.0)
rails-settings-cached (~> 0.6)
@@ -619,13 +580,12 @@ DEPENDENCIES
redis-namespace (~> 1.5)
redis-rails (~> 5.0)
rqrcode (~> 0.10)
rspec-rails (~> 3.7)
rspec-rails (~> 3.6)
rspec-sidekiq (~> 3.0)
rubocop
ruby-oembed (~> 0.12)
ruby-progressbar (~> 1.4)
sanitize (~> 4.4)
scss_lint (~> 0.55)
scss_lint (~> 0.53)
sidekiq (~> 5.0)
sidekiq-bulk (~> 0.1.1)
sidekiq-scheduler (~> 2.1)
@@ -634,16 +594,16 @@ DEPENDENCIES
simple_form (~> 3.4)
simplecov (~> 0.14)
sprockets-rails (~> 3.2)
strong_migrations
statsd-instrument (~> 2.1)
twitter-text (~> 1.14)
tzinfo-data (~> 1.2017)
uglifier (~> 3.2)
webmock (~> 3.0)
webpacker (~> 3.0)
webpacker (~> 2.0)
webpush
RUBY VERSION
ruby 2.4.2p198
ruby 2.4.1p111
BUNDLED WITH
1.16.1
1.15.4

View File

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

View File

@@ -1,10 +1,70 @@
# Mastodon Glitch Edition #
![Mastodon](https://i.imgur.com/NhZc40l.png)
========
> Now with automated deploys!
[![Build Status](http://img.shields.io/travis/tootsuite/mastodon.svg)][travis]
[![Code Climate](https://img.shields.io/codeclimate/github/tootsuite/mastodon.svg)][code_climate]
[![Build Status](https://travis-ci.org/glitch-soc/mastodon.svg?branch=master)](https://travis-ci.org/glitch-soc/mastodon)
[travis]: https://travis-ci.org/tootsuite/mastodon
[code_climate]: https://codeclimate.com/github/tootsuite/mastodon
So here's the deal: we all work on this code, and then it runs on dev.glitch.social and anyone who uses that does so absolutely at their own risk. can you dig it?
Mastodon is a free, open-source social network server. A decentralized solution to commercial platforms, it avoids the risks of a single company monopolizing your communication. Anyone can run Mastodon and participate in the social network seamlessly.
- You can view documentation for this project at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/).
- And contributing guidelines are available [here](CONTRIBUTING.md) and [here](https://glitch-soc.github.io/docs/contributing/).
An alternative implementation of the GNU social project. Based on [ActivityStreams](https://en.wikipedia.org/wiki/Activity_Streams_(format)), [Webfinger](https://en.wikipedia.org/wiki/WebFinger), [WebSub](https://en.wikipedia.org/wiki/WebSub) and [Salmon](https://en.wikipedia.org/wiki/Salmon_(protocol)).
Click on the screenshot to watch a demo of the UI:
[![Screenshot](https://i.imgur.com/pG3Nnz3.jpg)][youtube_demo]
[youtube_demo]: https://www.youtube.com/watch?v=YO1jQ8_rAMU
The project focus is a clean REST API and a good user interface. 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.
If you would like, you can [support the development of this project on Patreon][patreon]. Alternatively, you can donate to this BTC address: `17j2g7vpgHhLuXhN4bueZFCvdxxieyRVWd`
[patreon]: https://www.patreon.com/user?u=619786
## Resources
- [List of Mastodon instances](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/List-of-Mastodon-instances.md)
- [Use this tool to find Twitter friends on Mastodon](https://mastodon-bridge.herokuapp.com)
- [API overview](https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md)
- [Frequently Asked Questions](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md)
- [List of apps](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md)
## Features
- **Fully interoperable with GNU social and any OStatus platform**
Whatever implements Atom feeds, ActivityStreams, Salmon, WebSub and Webfinger is part of the network
- **Real-time timeline updates**
See the updates of people you're following appear in real-time in the UI via WebSockets
- **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 WebM**
Upload and view images and WebM videos attached to the updates
- **OAuth2 and a straightforward REST API**
Mastodon acts as an OAuth2 provider so 3rd party apps can use the API, which is RESTful and simple
- **Background processing for long-running tasks**
Mastodon tries to be as fast and responsive as possible, so all long-running tasks that can be delegated to background processing, are
- **Deployable via Docker**
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
## Development
Please follow the [development guide](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Development-guide.md) from the documentation repository.
## Deployment
There are guides in the documentation repository for [deploying on various platforms](https://github.com/tootsuite/documentation#running-mastodon).
## 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)
**IRC channel**: #mastodon on irc.freenode.net
## Extra credits
- The [Emoji One](https://github.com/Ranks/emojione) pack has been used for the emojis
- The error page image courtesy of [Dopatwo](https://www.youtube.com/user/dopatwo)
![Mastodon error image](https://mastodon.social/oops.png)

2
Vagrantfile vendored
View File

@@ -83,7 +83,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.provider :virtualbox do |vb|
vb.name = "mastodon"
vb.customize ["modifyvm", :id, "--memory", "4096"]
vb.customize ["modifyvm", :id, "--memory", "2048"]
# Disable VirtualBox DNS proxy to skip long-delay IPv6 resolutions.
# https://github.com/mitchellh/vagrant/issues/1172

View File

@@ -1,7 +1,6 @@
# frozen_string_literal: true
class AboutController < ApplicationController
before_action :set_pack
before_action :set_body_classes
before_action :set_instance_presenter, only: [:show, :more, :terms]
@@ -22,10 +21,6 @@ class AboutController < ApplicationController
helper_method :new_user
def set_pack
use_pack action_name == 'show' ? 'about' : 'common'
end
def set_instance_presenter
@instance_presenter = InstancePresenter.new
end

View File

@@ -7,7 +7,6 @@ class AccountsController < ApplicationController
def show
respond_to do |format|
format.html do
use_pack 'public'
@pinned_statuses = []
if current_account && @account.blocking?(current_account)
@@ -15,7 +14,7 @@ class AccountsController < ApplicationController
return
end
@pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses?
@pinned_statuses = cache_collection(@account.pinned_statuses, Status) unless media_requested?
@statuses = filtered_statuses.paginate_by_max_id(20, params[:max_id], params[:since_id])
@statuses = cache_collection(@statuses, Status)
@next_url = next_url unless @statuses.empty?
@@ -23,24 +22,17 @@ class AccountsController < ApplicationController
format.atom do
@entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id])
render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? }))
render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.to_a))
end
format.json do
render json: @account,
serializer: ActivityPub::ActorSerializer,
adapter: ActivityPub::Adapter,
content_type: 'application/activity+json'
render json: @account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
end
end
private
def show_pinned_statuses?
[replies_requested?, media_requested?, params[:max_id].present?, params[:since_id].present?].none?
end
def filtered_statuses
default_statuses.tap do |statuses|
statuses.merge!(only_media_scope) if media_requested?
@@ -49,7 +41,7 @@ class AccountsController < ApplicationController
end
def default_statuses
@account.statuses.not_local_only.where(visibility: [:public, :unlisted])
@account.statuses.where(visibility: [:public, :unlisted])
end
def only_media_scope

View File

@@ -1,18 +0,0 @@
# frozen_string_literal: true
class ActivityPub::FollowsController < Api::BaseController
include SignatureVerification
def show
render(
json: FollowRequest.includes(:account).references(:account).find_by!(
id: params.require(:id),
accounts: { domain: nil, username: params.require(:account_username) },
target_account: signed_request_account
),
serializer: ActivityPub::FollowSerializer,
adapter: ActivityPub::Adapter,
content_type: 'application/activity+json'
)
end
end

View File

@@ -9,9 +9,9 @@ class ActivityPub::InboxesController < Api::BaseController
if signed_request_account
upgrade_account
process_payload
head 202
head 201
else
[signature_verification_failure_reason, 401]
head 202
end
end
@@ -26,13 +26,8 @@ class ActivityPub::InboxesController < Api::BaseController
end
def upgrade_account
if signed_request_account.ostatus?
signed_request_account.update(last_webfingered_at: nil)
ResolveRemoteAccountWorker.perform_async(signed_request_account.acct)
end
Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id) if signed_request_account.subscribed?
DeliveryFailureTracker.track_inverse_success!(signed_request_account)
return unless signed_request_account.subscribed?
Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id)
end
def process_payload

View File

@@ -1,41 +0,0 @@
# frozen_string_literal: true
module Admin
class AccountModerationNotesController < BaseController
before_action :set_account_moderation_note, only: [:destroy]
def create
authorize AccountModerationNote, :create?
@account_moderation_note = current_account.account_moderation_notes.new(resource_params)
if @account_moderation_note.save
redirect_to admin_account_path(@account_moderation_note.target_account_id), notice: I18n.t('admin.account_moderation_notes.created_msg')
else
@account = @account_moderation_note.target_account
@moderation_notes = @account.targeted_moderation_notes.latest
render template: 'admin/accounts/show'
end
end
def destroy
authorize @account_moderation_note, :destroy?
@account_moderation_note.destroy!
redirect_to admin_account_path(@account_moderation_note.target_account_id), notice: I18n.t('admin.account_moderation_notes.destroyed_msg')
end
private
def resource_params
params.require(:account_moderation_note).permit(
:content,
:target_account_id
)
end
def set_account_moderation_note
@account_moderation_note = AccountModerationNote.find(params[:id])
end
end
end

View File

@@ -2,57 +2,26 @@
module Admin
class AccountsController < BaseController
before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :enable, :disable, :memorialize]
before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload]
before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload]
before_action :require_local_account!, only: [:enable, :disable, :memorialize]
def index
authorize :account, :index?
@accounts = filtered_accounts.page(params[:page])
end
def show
authorize @account, :show?
@account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)
@moderation_notes = @account.targeted_moderation_notes.latest
end
def show; end
def subscribe
authorize @account, :subscribe?
Pubsubhubbub::SubscribeWorker.perform_async(@account.id)
redirect_to admin_account_path(@account.id)
end
def unsubscribe
authorize @account, :unsubscribe?
Pubsubhubbub::UnsubscribeWorker.perform_async(@account.id)
redirect_to admin_account_path(@account.id)
end
def memorialize
authorize @account, :memorialize?
@account.memorialize!
log_action :memorialize, @account
redirect_to admin_account_path(@account.id)
end
def enable
authorize @account.user, :enable?
@account.user.enable!
log_action :enable, @account.user
redirect_to admin_account_path(@account.id)
end
def disable
authorize @account.user, :disable?
@account.user.disable!
log_action :disable, @account.user
redirect_to admin_account_path(@account.id)
end
def redownload
authorize @account, :redownload?
@account.reset_avatar!
@account.reset_header!
@account.save!
@@ -70,10 +39,6 @@ module Admin
redirect_to admin_account_path(@account.id) if @account.local?
end
def require_local_account!
redirect_to admin_account_path(@account.id) unless @account.local? && @account.user.present?
end
def filtered_accounts
AccountFilter.new(filter_params).results
end
@@ -89,8 +54,7 @@ module Admin
:username,
:display_name,
:email,
:ip,
:staff
:ip
)
end
end

View File

@@ -1,9 +0,0 @@
# frozen_string_literal: true
module Admin
class ActionLogsController < BaseController
def index
@action_logs = Admin::ActionLog.page(params[:page])
end
end
end

View File

@@ -2,16 +2,8 @@
module Admin
class BaseController < ApplicationController
include Authorization
include AccountableConcern
before_action :require_admin!
layout 'admin'
before_action :require_staff!
before_action :set_pack
def set_pack
use_pack 'admin'
end
end
end

View File

@@ -2,19 +2,15 @@
module Admin
class ConfirmationsController < BaseController
before_action :set_user
def create
authorize @user, :confirm?
@user.confirm!
log_action :confirm, @user
account_user.confirm
redirect_to admin_accounts_path
end
private
def set_user
@user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
def account_user
Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
end
end
end

View File

@@ -1,111 +0,0 @@
# frozen_string_literal: true
module Admin
class CustomEmojisController < BaseController
before_action :set_custom_emoji, except: [:index, :new, :create]
before_action :set_filter_params
def index
authorize :custom_emoji, :index?
@custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page])
end
def new
authorize :custom_emoji, :create?
@custom_emoji = CustomEmoji.new
end
def create
authorize :custom_emoji, :create?
@custom_emoji = CustomEmoji.new(resource_params)
if @custom_emoji.save
log_action :create, @custom_emoji
redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.created_msg')
else
render :new
end
end
def update
authorize @custom_emoji, :update?
if @custom_emoji.update(resource_params)
log_action :update, @custom_emoji
flash[:notice] = I18n.t('admin.custom_emojis.updated_msg')
else
flash[:alert] = I18n.t('admin.custom_emojis.update_failed_msg')
end
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end
def destroy
authorize @custom_emoji, :destroy?
@custom_emoji.destroy!
log_action :destroy, @custom_emoji
flash[:notice] = I18n.t('admin.custom_emojis.destroyed_msg')
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end
def copy
authorize @custom_emoji, :copy?
emoji = CustomEmoji.find_or_initialize_by(domain: nil,
shortcode: @custom_emoji.shortcode)
emoji.image = @custom_emoji.image
if emoji.save
log_action :create, emoji
flash[:notice] = I18n.t('admin.custom_emojis.copied_msg')
else
flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg')
end
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end
def enable
authorize @custom_emoji, :enable?
@custom_emoji.update!(disabled: false)
log_action :enable, @custom_emoji
flash[:notice] = I18n.t('admin.custom_emojis.enabled_msg')
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end
def disable
authorize @custom_emoji, :disable?
@custom_emoji.update!(disabled: true)
log_action :disable, @custom_emoji
flash[:notice] = I18n.t('admin.custom_emojis.disabled_msg')
redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params)
end
private
def set_custom_emoji
@custom_emoji = CustomEmoji.find(params[:id])
end
def set_filter_params
@filter_params = filter_params.to_hash.symbolize_keys
end
def resource_params
params.require(:custom_emoji).permit(:shortcode, :image, :visible_in_picker)
end
def filtered_custom_emojis
CustomEmojiFilter.new(filter_params).results
end
def filter_params
params.permit(
:local,
:remote,
:by_domain,
:shortcode
)
end
end
end

View File

@@ -5,37 +5,28 @@ module Admin
before_action :set_domain_block, only: [:show, :destroy]
def index
authorize :domain_block, :index?
@domain_blocks = DomainBlock.page(params[:page])
end
def new
authorize :domain_block, :create?
@domain_block = DomainBlock.new
end
def create
authorize :domain_block, :create?
@domain_block = DomainBlock.new(resource_params)
if @domain_block.save
DomainBlockWorker.perform_async(@domain_block.id)
log_action :create, @domain_block
redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.created_msg')
else
render :new
end
end
def show
authorize @domain_block, :show?
end
def show; end
def destroy
authorize @domain_block, :destroy?
UnblockDomainService.new.call(@domain_block, retroactive_unblock?)
log_action :destroy, @domain_block
redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.destroyed_msg')
end

View File

@@ -1,47 +0,0 @@
# frozen_string_literal: true
module Admin
class EmailDomainBlocksController < BaseController
before_action :set_email_domain_block, only: [:show, :destroy]
def index
authorize :email_domain_block, :index?
@email_domain_blocks = EmailDomainBlock.page(params[:page])
end
def new
authorize :email_domain_block, :create?
@email_domain_block = EmailDomainBlock.new
end
def create
authorize :email_domain_block, :create?
@email_domain_block = EmailDomainBlock.new(resource_params)
if @email_domain_block.save
log_action :create, @email_domain_block
redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg')
else
render :new
end
end
def destroy
authorize @email_domain_block, :destroy?
@email_domain_block.destroy!
log_action :destroy, @email_domain_block
redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.destroyed_msg')
end
private
def set_email_domain_block
@email_domain_block = EmailDomainBlock.find(params[:id])
end
def resource_params
params.require(:email_domain_block).permit(:domain)
end
end
end

View File

@@ -3,12 +3,10 @@
module Admin
class InstancesController < BaseController
def index
authorize :instance, :index?
@instances = ordered_instances
end
def resubscribe
authorize :instance, :resubscribe?
params.require(:by_domain)
Pubsubhubbub::SubscribeWorker.push_bulk(subscribeable_accounts.pluck(:id))
redirect_to admin_instances_path
@@ -16,12 +14,8 @@ module Admin
private
def filtered_instances
InstanceFilter.new(filter_params).results
end
def paginated_instances
filtered_instances.page(params[:page])
Account.remote.by_domain_accounts.page(params[:page])
end
helper_method :paginated_instances
@@ -33,11 +27,5 @@ module Admin
def subscribeable_accounts
Account.with_followers.remote.where(domain: params[:by_domain])
end
def filter_params
params.permit(
:domain_name
)
end
end
end

View File

@@ -1,47 +0,0 @@
# frozen_string_literal: true
module Admin
class InvitesController < BaseController
def index
authorize :invite, :index?
@invites = filtered_invites.includes(user: :account).page(params[:page])
@invite = Invite.new
end
def create
authorize :invite, :create?
@invite = Invite.new(resource_params)
@invite.user = current_user
if @invite.save
redirect_to admin_invites_path
else
@invites = Invite.page(params[:page])
render :index
end
end
def destroy
@invite = Invite.find(params[:id])
authorize @invite, :destroy?
@invite.expire!
redirect_to admin_invites_path
end
private
def resource_params
params.require(:invite).permit(:max_uses, :expires_in)
end
def filtered_invites
InviteFilter.new(filter_params).results
end
def filter_params
params.permit(:available, :expired)
end
end
end

View File

@@ -2,29 +2,26 @@
module Admin
class ReportedStatusesController < BaseController
include Authorization
before_action :set_report
before_action :set_status, only: [:update, :destroy]
def create
authorize :status, :update?
@form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account))
flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
@form = Form::StatusBatch.new(form_status_batch_params)
flash[:alert] = t('admin.statuses.failed_to_execute') unless @form.save
redirect_to admin_report_path(@report)
end
def update
authorize @status, :update?
@status.update!(status_params)
log_action :update, @status
@status.update(status_params)
redirect_to admin_report_path(@report)
end
def destroy
authorize @status, :destroy?
RemovalWorker.perform_async(@status.id)
log_action :destroy, @status
render json: @status
end

View File

@@ -5,17 +5,14 @@ module Admin
before_action :set_report, except: [:index]
def index
authorize :report, :index?
@reports = filtered_reports.page(params[:page])
end
def show
authorize @report, :show?
@form = Form::StatusBatch.new
end
def update
authorize @report, :update?
process_report
redirect_to admin_report_path(@report)
end
@@ -25,17 +22,12 @@ module Admin
def process_report
case params[:outcome].to_s
when 'resolve'
@report.update!(action_taken_by_current_attributes)
log_action :resolve, @report
@report.update(action_taken_by_current_attributes)
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
@report.target_account.update(silenced: true)
resolve_all_target_account_reports
else
raise ActiveRecord::RecordNotFound

View File

@@ -2,19 +2,17 @@
module Admin
class ResetsController < BaseController
before_action :set_user
before_action :set_account
def create
authorize @user, :reset_password?
@user.send_reset_password_instructions
log_action :reset_password, @user
@account.user.send_reset_password_instructions
redirect_to admin_accounts_path
end
private
def set_user
@user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
def set_account
@account = Account.find(params[:account_id])
end
end
end

View File

@@ -1,27 +0,0 @@
# frozen_string_literal: true
module Admin
class RolesController < BaseController
before_action :set_user
def promote
authorize @user, :promote?
@user.promote!
log_action :promote, @user
redirect_to admin_account_path(@user.account_id)
end
def demote
authorize @user, :demote?
@user.demote!
log_action :demote, @user
redirect_to admin_account_path(@user.account_id)
end
private
def set_user
@user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
end
end
end

View File

@@ -13,44 +13,23 @@ module Admin
closed_registrations_message
open_deletion
timeline_preview
show_staff_badge
bootstrap_timeline_accounts
thumbnail
min_invite_role
activity_api_enabled
peers_api_enabled
).freeze
BOOLEAN_SETTINGS = %w(
open_registrations
open_deletion
timeline_preview
show_staff_badge
activity_api_enabled
peers_api_enabled
).freeze
UPLOAD_SETTINGS = %w(
thumbnail
).freeze
def edit
authorize :settings, :show?
@admin_settings = Form::AdminSettings.new
end
def update
authorize :settings, :update?
settings_params.each do |key, value|
if UPLOAD_SETTINGS.include?(key)
upload = SiteUpload.where(var: key).first_or_initialize(var: key)
upload.update(file: value)
else
setting = Setting.where(var: key).first_or_initialize(var: key)
setting.update(value: value_for_update(key, value))
end
end
flash[:notice] = I18n.t('generic.changes_saved_msg')
redirect_to edit_admin_settings_path

View File

@@ -5,16 +5,12 @@ module Admin
before_action :set_account
def create
authorize @account, :silence?
@account.update!(silenced: true)
log_action :silence, @account
@account.update(silenced: true)
redirect_to admin_accounts_path
end
def destroy
authorize @account, :unsilence?
@account.update!(silenced: false)
log_action :unsilence, @account
@account.update(silenced: false)
redirect_to admin_accounts_path
end

View File

@@ -2,6 +2,8 @@
module Admin
class StatusesController < BaseController
include Authorization
helper_method :current_params
before_action :set_account
@@ -10,39 +12,31 @@ module Admin
PER_PAGE = 20
def index
authorize :status, :index?
@statuses = @account.statuses
if params[:media]
account_media_status_ids = @account.media_attachments.attached.reorder(nil).select(:status_id).distinct
@statuses.merge!(Status.where(id: account_media_status_ids))
end
@statuses = @statuses.preload(:media_attachments, :mentions).page(params[:page]).per(PER_PAGE)
@form = Form::StatusBatch.new
end
def create
authorize :status, :update?
@form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account))
flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
@form = Form::StatusBatch.new(form_status_batch_params)
flash[:alert] = t('admin.statuses.failed_to_execute') unless @form.save
redirect_to admin_account_statuses_path(@account.id, current_params)
end
def update
authorize @status, :update?
@status.update!(status_params)
log_action :update, @status
@status.update(status_params)
redirect_to admin_account_statuses_path(@account.id, current_params)
end
def destroy
authorize @status, :destroy?
RemovalWorker.perform_async(@status.id)
log_action :destroy, @status
render json: @status
end
@@ -66,7 +60,6 @@ module Admin
def current_params
page = (params[:page] || 1).to_i
{
media: params[:media],
page: page > 1 && page,

View File

@@ -3,7 +3,6 @@
module Admin
class SubscriptionsController < BaseController
def index
authorize :subscription, :index?
@subscriptions = ordered_subscriptions.page(requested_page)
end

View File

@@ -5,16 +5,12 @@ module Admin
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
@account.update(suspended: false)
redirect_to admin_accounts_path
end

View File

@@ -5,9 +5,7 @@ module Admin
before_action :set_user
def destroy
authorize @user, :disable_2fa?
@user.disable_two_factor!
log_action :disable_2fa, @user
redirect_to admin_accounts_path
end

View File

@@ -72,4 +72,19 @@ class Api::BaseController < ApplicationController
def render_empty
render json: {}, status: 200
end
def set_maps(statuses) # rubocop:disable Style/AccessorMethodName
if current_account.nil?
@reblogs_map = {}
@favourites_map = {}
@mutes_map = {}
return
end
status_ids = statuses.compact.flat_map { |s| [s.id, s.reblog_of_id] }.uniq
conversation_ids = statuses.compact.map(&:conversation_id).compact.uniq
@reblogs_map = Status.reblogs_map(status_ids, current_account)
@favourites_map = Status.favourites_map(status_ids, current_account)
@mutes_map = Status.mutes_map(conversation_ids, current_account)
end
end

View File

@@ -7,11 +7,9 @@ class Api::SalmonController < Api::BaseController
def update
if verify_payload?
process_salmon
head 202
elsif payload.present?
[signature_verification_failure_reason, 401]
head 201
else
head 400
head 202
end
end

View File

@@ -1,20 +0,0 @@
# frozen_string_literal: true
class Api::V1::Accounts::ListsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }
before_action :require_user!
before_action :set_account
respond_to :json
def index
@lists = @account.lists.where(account: current_account)
render json: @lists, each_serializer: REST::ListSerializer
end
private
def set_account
@account = Account.find(params[:account_id])
end
end

View File

@@ -7,10 +7,7 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController
respond_to :json
def index
accounts = Account.where(id: account_ids).select('id')
# .where doesn't guarantee that our results are in the same order
# we requested them, so return the "right" order to the requestor.
@accounts = accounts.index_by(&:id).values_at(*account_ids)
@accounts = Account.where(id: account_ids).select('id')
render json: @accounts, each_serializer: REST::RelationshipSerializer, relationships: relationships
end

View File

@@ -17,13 +17,12 @@ class Api::V1::Accounts::SearchController < Api::BaseController
AccountSearchService.new.call(
params[:q],
limit_param(DEFAULT_ACCOUNTS_LIMIT),
current_account,
resolve: truthy_param?(:resolve),
following: truthy_param?(:following)
resolving_search?,
current_account
)
end
def truthy_param?(key)
params[key] == 'true'
def resolving_search?
params[:resolve] == 'true'
end
end

View File

@@ -13,11 +13,8 @@ class Api::V1::AccountsController < Api::BaseController
end
def follow
FollowService.new.call(current_user.account, @account.acct, reblogs: params[:reblogs])
options = @account.locked? ? {} : { following_map: { @account.id => { reblogs: params[:reblogs] } }, requested_map: { @account.id => false } }
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(options)
FollowService.new.call(current_user.account, @account.acct)
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
end
def block
@@ -26,7 +23,7 @@ class Api::V1::AccountsController < Api::BaseController
end
def mute
MuteService.new.call(current_user.account, @account, notifications: params[:notifications])
MuteService.new.call(current_user.account, @account)
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
end
@@ -51,7 +48,7 @@ class Api::V1::AccountsController < Api::BaseController
@account = Account.find(params[:id])
end
def relationships(**options)
AccountRelationshipsPresenter.new([@account.id], current_user.account_id, options)
def relationships
AccountRelationshipsPresenter.new([@account.id], current_user.account_id)
end
end

View File

@@ -1,11 +0,0 @@
# frozen_string_literal: true
class Api::V1::Apps::CredentialsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }
respond_to :json
def show
render json: doorkeeper_token.application, serializer: REST::StatusSerializer::ApplicationSerializer
end
end

View File

@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Api::V1::AppsController < Api::BaseController
respond_to :json
def create
@app = Doorkeeper::Application.create!(application_options)
render json: @app, serializer: REST::ApplicationSerializer

View File

@@ -15,13 +15,15 @@ class Api::V1::BlocksController < Api::BaseController
private
def load_accounts
paginated_blocks.map(&:target_account)
default_accounts.merge(paginated_blocks).to_a
end
def default_accounts
Account.includes(:blocked_by).references(:blocked_by)
end
def paginated_blocks
@paginated_blocks ||= Block.eager_load(:target_account)
.where(account: current_account)
.paginate_by_max_id(
Block.where(account: current_account).paginate_by_max_id(
limit_param(DEFAULT_ACCOUNTS_LIMIT),
params[:max_id],
params[:since_id]
@@ -39,21 +41,21 @@ class Api::V1::BlocksController < Api::BaseController
end
def prev_path
unless paginated_blocks.empty?
unless @accounts.empty?
api_v1_blocks_url pagination_params(since_id: pagination_since_id)
end
end
def pagination_max_id
paginated_blocks.last.id
@accounts.last.blocked_by_ids.last
end
def pagination_since_id
paginated_blocks.first.id
@accounts.first.blocked_by_ids.first
end
def records_continue?
paginated_blocks.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
end
def pagination_params(core_params)

View File

@@ -1,9 +0,0 @@
# frozen_string_literal: true
class Api::V1::CustomEmojisController < Api::BaseController
respond_to :json
def index
render json: CustomEmoji.local.where(disabled: false), each_serializer: REST::CustomEmojiSerializer
end
end

View File

@@ -10,12 +10,6 @@ class Api::V1::FollowsController < Api::BaseController
raise ActiveRecord::RecordNotFound if follow_params[:uri].blank?
@account = FollowService.new.call(current_user.account, target_uri).try(:target_account)
if @account.nil?
username, domain = target_uri.split('@')
@account = Account.find_remote!(username, domain)
end
render json: @account, serializer: REST::AccountSerializer
end

View File

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

View File

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

View File

@@ -1,97 +0,0 @@
# frozen_string_literal: true
class Api::V1::Lists::AccountsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }, only: [:show]
before_action -> { doorkeeper_authorize! :write }, except: [:show]
before_action :require_user!
before_action :set_list
after_action :insert_pagination_headers, only: :show
def show
@accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer
end
def create
ApplicationRecord.transaction do
list_accounts.each do |account|
@list.accounts << account
end
end
render_empty
end
def destroy
ListAccount.where(list: @list, account_id: account_ids).destroy_all
render_empty
end
private
def set_list
@list = List.where(account: current_account).find(params[:list_id])
end
def load_accounts
if unlimited?
@list.accounts.all
else
@list.accounts.paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id])
end
end
def list_accounts
Account.find(account_ids)
end
def account_ids
Array(resource_params[:account_ids])
end
def resource_params
params.permit(account_ids: [])
end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path
return if unlimited?
if records_continue?
api_v1_list_accounts_url pagination_params(max_id: pagination_max_id)
end
end
def prev_path
return if unlimited?
unless @accounts.empty?
api_v1_list_accounts_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.permit(:limit).merge(core_params)
end
def unlimited?
params[:limit] == '0'
end
end

View File

@@ -1,43 +0,0 @@
# frozen_string_literal: true
class Api::V1::ListsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :write }, except: [:index, :show]
before_action :require_user!
before_action :set_list, except: [:index, :create]
def index
@lists = List.where(account: current_account).all
render json: @lists, each_serializer: REST::ListSerializer
end
def show
render json: @list, serializer: REST::ListSerializer
end
def create
@list = List.create!(list_params.merge(account: current_account))
render json: @list, serializer: REST::ListSerializer
end
def update
@list.update!(list_params)
render json: @list, serializer: REST::ListSerializer
end
def destroy
@list.destroy!
render_empty
end
private
def set_list
@list = List.where(account: current_account).find(params[:id])
end
def list_params
params.permit(:title)
end
end

View File

@@ -10,7 +10,7 @@ class Api::V1::MediaController < Api::BaseController
respond_to :json
def create
@media = current_account.media_attachments.create!(media_params)
@media = current_account.media_attachments.create!(file: media_params[:file])
render json: @media, serializer: REST::MediaAttachmentSerializer
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
render json: file_type_error, status: 422
@@ -18,16 +18,10 @@ class Api::V1::MediaController < Api::BaseController
render json: processing_error, status: 500
end
def update
@media = current_account.media_attachments.where(status_id: nil).find(params[:id])
@media.update!(media_params)
render json: @media, serializer: REST::MediaAttachmentSerializer
end
private
def media_params
params.permit(:file, :description)
params.permit(:file)
end
def file_type_error

View File

@@ -8,15 +8,10 @@ class Api::V1::MutesController < Api::BaseController
respond_to :json
def index
@data = @accounts = load_accounts
@accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer
end
def details
@data = @mutes = load_mutes
render json: @mutes, each_serializer: REST::MuteSerializer
end
private
def load_accounts
@@ -27,10 +22,6 @@ class Api::V1::MutesController < Api::BaseController
Account.includes(:muted_by).references(:muted_by)
end
def load_mutes
paginated_mutes.includes(:account, :target_account).to_a
end
def paginated_mutes
Mute.where(account: current_account).paginate_by_max_id(
limit_param(DEFAULT_ACCOUNTS_LIMIT),
@@ -45,34 +36,26 @@ class Api::V1::MutesController < Api::BaseController
def next_path
if records_continue?
url_for pagination_params(max_id: pagination_max_id)
api_v1_mutes_url pagination_params(max_id: pagination_max_id)
end
end
def prev_path
unless@data.empty?
url_for pagination_params(since_id: pagination_since_id)
unless @accounts.empty?
api_v1_mutes_url pagination_params(since_id: pagination_since_id)
end
end
def pagination_max_id
if params[:action] == "details"
@mutes.last.id
else
@accounts.last.muted_by_ids.last
end
end
def pagination_since_id
if params[:action] == "details"
@mutes.first.id
else
@accounts.first.muted_by_ids.first
end
end
def records_continue?
@data.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
@accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT)
end
def pagination_params(core_params)

View File

@@ -24,20 +24,11 @@ class Api::V1::NotificationsController < Api::BaseController
render_empty
end
def destroy
dismiss
end
def dismiss
current_account.notifications.find_by!(id: params[:id]).destroy!
render_empty
end
def destroy_multiple
current_account.notifications.where(id: params[:ids]).destroy_all
render_empty
end
private
def load_notifications

View File

@@ -19,7 +19,7 @@ class Api::V1::ReportsController < Api::BaseController
comment: report_params[:comment]
)
User.staff.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later }
User.admins.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later }
render json: @report, serializer: REST::ReportSerializer
end

View File

@@ -1,9 +1,7 @@
# frozen_string_literal: true
class Api::V1::SearchController < Api::BaseController
include Authorization
RESULTS_LIMIT = 10
RESULTS_LIMIT = 5
before_action -> { doorkeeper_authorize! :read }
before_action :require_user!
@@ -11,24 +9,12 @@ class Api::V1::SearchController < Api::BaseController
respond_to :json
def index
@search = Search.new(search)
@search = Search.new(search_results)
render json: @search, serializer: REST::SearchSerializer
end
private
def search
search_results.tap do |search|
search[:statuses].keep_if do |status|
begin
authorize status, :show?
rescue Mastodon::NotPermittedError
false
end
end
end
end
def search_results
SearchService.new.call(
params[:q],

View File

@@ -1,60 +0,0 @@
# frozen_string_literal: true
class Api::V1::Timelines::DirectController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }, only: [:show]
before_action :require_user!, only: [:show]
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
respond_to :json
def show
@statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
end
private
def load_statuses
cached_direct_statuses
end
def cached_direct_statuses
cache_collection direct_statuses, Status
end
def direct_statuses
direct_timeline_statuses.paginate_by_max_id(
limit_param(DEFAULT_STATUSES_LIMIT),
params[:max_id],
params[:since_id]
)
end
def direct_timeline_statuses
Status.as_direct_timeline(current_account)
end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def pagination_params(core_params)
params.permit(:local, :limit).merge(core_params)
end
def next_path
api_v1_timelines_direct_url pagination_params(max_id: pagination_max_id)
end
def prev_path
api_v1_timelines_direct_url pagination_params(since_id: pagination_since_id)
end
def pagination_max_id
@statuses.last.id
end
def pagination_since_id
@statuses.first.id
end
end

View File

@@ -31,7 +31,7 @@ class Api::V1::Timelines::HomeController < Api::BaseController
end
def account_home_feed
HomeFeed.new(current_account)
Feed.new(:home, current_account)
end
def insert_pagination_headers

View File

@@ -1,66 +0,0 @@
# frozen_string_literal: true
class Api::V1::Timelines::ListController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }
before_action :require_user!
before_action :set_list
before_action :set_statuses
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
def show
render json: @statuses,
each_serializer: REST::StatusSerializer,
relationships: StatusRelationshipsPresenter.new(@statuses, current_user.account_id)
end
private
def set_list
@list = List.where(account: current_account).find(params[:id])
end
def set_statuses
@statuses = cached_list_statuses
end
def cached_list_statuses
cache_collection list_statuses, Status
end
def list_statuses
list_feed.get(
limit_param(DEFAULT_STATUSES_LIMIT),
params[:max_id],
params[:since_id]
)
end
def list_feed
ListFeed.new(@list)
end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def pagination_params(core_params)
params.permit(:limit).merge(core_params)
end
def next_path
api_v1_timelines_list_url params[:id], pagination_params(max_id: pagination_max_id)
end
def prev_path
api_v1_timelines_list_url params[:id], pagination_params(since_id: pagination_since_id)
end
def pagination_max_id
@statuses.last.id
end
def pagination_since_id
@statuses.first.id
end
end

View File

@@ -28,8 +28,6 @@ class Api::Web::PushSubscriptionsController < Api::BaseController
},
}
data.deep_merge!(params[:data]) if params[:data]
web_subscription = ::Web::PushSubscription.create!(
endpoint: params[:subscription][:endpoint],
key_p256dh: params[:subscription][:keys][:p256dh],

View File

@@ -12,14 +12,11 @@ class ApplicationController < ActionController::Base
helper_method :current_account
helper_method :current_session
helper_method :current_flavour
helper_method :current_skin
helper_method :single_user_mode?
rescue_from ActionController::RoutingError, with: :not_found
rescue_from ActiveRecord::RecordNotFound, with: :not_found
rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity
rescue_from Mastodon::NotPermittedError, with: :forbidden
before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?
before_action :check_suspension, if: :user_signed_in?
@@ -42,10 +39,6 @@ class ApplicationController < ActionController::Base
redirect_to root_path unless current_user&.admin?
end
def require_staff!
redirect_to root_path unless current_user&.staff?
end
def check_suspension
forbidden if current_user.account.suspended?
end
@@ -54,75 +47,6 @@ class ApplicationController < ActionController::Base
new_user_session_path
end
def pack(data, pack_name, skin = 'default')
return nil unless pack?(data, pack_name)
pack_data = {
common: pack_name == 'common' ? nil : resolve_pack(data['name'] ? Themes.instance.flavour(current_flavour) : Themes.instance.core, 'common', skin),
flavour: data['name'],
pack: pack_name,
preload: nil,
skin: nil,
supported_locales: data['locales'],
}
if data['pack'][pack_name].is_a?(Hash)
pack_data[:common] = nil if data['pack'][pack_name]['use_common'] == false
pack_data[:pack] = nil unless data['pack'][pack_name]['filename']
if data['pack'][pack_name]['preload']
pack_data[:preload] = [data['pack'][pack_name]['preload']] if data['pack'][pack_name]['preload'].is_a?(String)
pack_data[:preload] = data['pack'][pack_name]['preload'] if data['pack'][pack_name]['preload'].is_a?(Array)
end
if skin != 'default' && data['skin'][skin]
pack_data[:skin] = skin if data['skin'][skin].include?(pack_name)
else # default skin
pack_data[:skin] = 'default' if data['pack'][pack_name]['stylesheet']
end
end
pack_data
end
def pack?(data, pack_name)
if data['pack'].is_a?(Hash) && data['pack'].key?(pack_name)
return true if data['pack'][pack_name].is_a?(String) || data['pack'][pack_name].is_a?(Hash)
end
false
end
def nil_pack(data, pack_name, skin = 'default')
{
common: pack_name == 'common' ? nil : resolve_pack(data['name'] ? Themes.instance.flavour(current_flavour) : Themes.instance.core, 'common', skin),
flavour: data['name'],
pack: nil,
preload: nil,
skin: nil,
supported_locales: data['locales'],
}
end
def resolve_pack(data, pack_name, skin = 'default')
result = pack(data, pack_name, skin)
unless result
if data['name'] && data.key?('fallback')
if data['fallback'].nil?
return nil_pack(data, pack_name, skin)
elsif data['fallback'].is_a?(String) && Themes.instance.flavour(data['fallback'])
return resolve_pack(Themes.instance.flavour(data['fallback']), pack_name)
elsif data['fallback'].is_a?(Array)
data['fallback'].each do |fallback|
return resolve_pack(Themes.instance.flavour(fallback), pack_name) if Themes.instance.flavour(fallback)
end
end
return nil_pack(data, pack_name, skin)
end
return data.key?('name') && data['name'] != Setting.default_settings['flavour'] ? resolve_pack(Themes.instance.flavour(Setting.default_settings['flavour']), pack_name) : nil_pack(data, pack_name, skin)
end
result
end
def use_pack(pack_name)
@core = resolve_pack(Themes.instance.core, pack_name)
@theme = resolve_pack(Themes.instance.flavour(current_flavour), pack_name, current_skin)
end
protected
def forbidden
@@ -153,16 +77,6 @@ class ApplicationController < ActionController::Base
@current_session ||= SessionActivation.find_by(session_id: cookies.signed['_session_id'])
end
def current_flavour
return Setting.default_settings['flavour'] unless Themes.instance.flavours.include? current_user&.setting_flavour
current_user.setting_flavour
end
def current_skin
return 'default' unless Themes.instance.skins_for(current_flavour).include? current_user&.setting_skin
current_user.setting_skin
end
def cache_collection(raw, klass)
return raw unless klass.respond_to?(:with_includes)
@@ -179,7 +93,7 @@ class ApplicationController < ActionController::Base
unless uncached_ids.empty?
uncached = klass.where(id: uncached_ids).with_includes.map { |item| [item.id, item] }.to_h
uncached.each_value do |item|
uncached.values.each do |item|
Rails.cache.write(item.cache_key, item)
end
end
@@ -196,13 +110,4 @@ class ApplicationController < ActionController::Base
end
end
end
def render_cached_json(cache_key, **options)
data = Rails.cache.fetch(cache_key, { raw: true }.merge(options)) do
yield.to_json
end
expires_in options[:expires_in], public: true
render json: data
end
end

View File

@@ -2,12 +2,4 @@
class Auth::ConfirmationsController < Devise::ConfirmationsController
layout 'auth'
before_action :set_pack
private
def set_pack
use_pack 'auth'
end
end

View File

@@ -2,7 +2,6 @@
class Auth::PasswordsController < Devise::PasswordsController
before_action :check_validity_of_reset_password_token, only: :edit
before_action :set_pack
layout 'auth'
@@ -18,8 +17,4 @@ class Auth::PasswordsController < Devise::PasswordsController
def reset_password_token_is_valid?
resource_class.with_reset_password_token(params[:reset_password_token]).present?
end
def set_pack
use_pack 'auth'
end
end

View File

@@ -5,9 +5,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
before_action :check_enabled_registrations, only: [:new, :create]
before_action :configure_sign_up_params, only: [:create]
before_action :set_pack
before_action :set_sessions, only: [:edit, :update]
before_action :set_instance_presenter, only: [:new, :create, :update]
def destroy
not_found
@@ -17,16 +15,13 @@ class Auth::RegistrationsController < Devise::RegistrationsController
def build_resource(hash = nil)
super(hash)
resource.locale = I18n.locale
resource.invite_code = params[:invite_code] if resource.invite_code.blank?
resource.build_account if resource.account.nil?
end
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up) do |u|
u.permit({ account_attributes: [:username] }, :email, :password, :password_confirmation, :invite_code)
u.permit({ account_attributes: [:username] }, :email, :password, :password_confirmation)
end
end
@@ -38,36 +33,12 @@ class Auth::RegistrationsController < Devise::RegistrationsController
new_user_session_path
end
def after_update_path_for(_resource)
edit_user_registration_path
end
def check_enabled_registrations
redirect_to root_path if single_user_mode? || !allowed_registrations?
end
def allowed_registrations?
Setting.open_registrations || (invite_code.present? && Invite.find_by(code: invite_code)&.valid_for_use?)
end
def invite_code
if params[:user]
params[:user][:invite_code]
else
params[:invite_code]
end
redirect_to root_path if single_user_mode? || !Setting.open_registrations
end
private
def set_pack
use_pack %w(edit update).include?(action_name) ? 'admin' : 'auth'
end
def set_instance_presenter
@instance_presenter = InstancePresenter.new
end
def determine_layout
%w(edit update).include?(action_name) ? 'admin' : 'auth'
end

View File

@@ -8,8 +8,6 @@ class Auth::SessionsController < Devise::SessionsController
skip_before_action :require_no_authentication, only: [:create]
skip_before_action :check_suspension, only: [:destroy]
prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create]
prepend_before_action :set_pack
before_action :set_instance_presenter, only: [:new]
def create
super do |resource|
@@ -63,7 +61,7 @@ class Auth::SessionsController < Devise::SessionsController
if user_params[:otp_attempt].present? && session[:otp_user_id]
authenticate_with_two_factor_via_otp(user)
elsif user&.valid_password?(user_params[:password])
elsif user && user.valid_password?(user_params[:password])
prompt_for_two_factor(user)
end
end
@@ -86,14 +84,6 @@ class Auth::SessionsController < Devise::SessionsController
private
def set_pack
use_pack 'auth'
end
def set_instance_presenter
@instance_presenter = InstancePresenter.new
end
def home_paths(resource)
paths = [about_path]
if single_user_mode? && resource.is_a?(User)

View File

@@ -4,8 +4,6 @@ class AuthorizeFollowsController < ApplicationController
layout 'modal'
before_action :authenticate_user!
before_action :set_pack
before_action :set_body_classes
def show
@account = located_account || render(:error)
@@ -25,10 +23,6 @@ class AuthorizeFollowsController < ApplicationController
private
def set_pack
use_pack 'modal'
end
def follow_attempt
FollowService.new.call(current_account, acct_without_prefix)
end
@@ -64,8 +58,4 @@ class AuthorizeFollowsController < ApplicationController
def acct_params
params.fetch(:acct, '')
end
def set_body_classes
@body_classes = 'modal-layout'
end
end

View File

@@ -1,9 +0,0 @@
# frozen_string_literal: true
module AccountableConcern
extend ActiveSupport::Concern
def log_action(action, target)
Admin::ActionLog.create(account: current_account, action: action, target: target)
end
end

View File

@@ -2,7 +2,6 @@
module Authorization
extend ActiveSupport::Concern
include Pundit
def pundit_user

View File

@@ -44,8 +44,7 @@ module RateLimitHeaders
end
def api_throttle_data
most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_, v| v[:limit] }
request.env['rack.attack.throttle_data'][most_limited_type]
request.env['rack.attack.throttle_data']['api']
end
def request_time

View File

@@ -9,15 +9,10 @@ module SignatureVerification
request.headers['Signature'].present?
end
def signature_verification_failure_reason
return @signature_verification_failure_reason if defined?(@signature_verification_failure_reason)
end
def signed_request_account
return @signed_request_account if defined?(@signed_request_account)
unless signed_request?
@signature_verification_failure_reason = 'Request not signed'
@signed_request_account = nil
return
end
@@ -32,7 +27,6 @@ module SignatureVerification
end
if incompatible_signature?(signature_params)
@signature_verification_failure_reason = 'Incompatible request signature'
@signed_request_account = nil
return
end
@@ -40,7 +34,6 @@ module SignatureVerification
account = account_from_key_id(signature_params['keyId'])
if account.nil?
@signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}"
@signed_request_account = nil
return
end
@@ -48,21 +41,10 @@ module SignatureVerification
signature = Base64.decode64(signature_params['signature'])
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!
if account.keypair.public_key.verify(OpenSSL::Digest::SHA256.new, signature, compare_signed_string)
@signed_request_account = account
@signed_request_account
else
@signed_verification_failure_reason = "Verification failed for #{account.username}@#{account.domain} #{account.uri}"
@signed_request_account = nil
end
else
@signed_verification_failure_reason = "Verification failed for #{account.username}@#{account.domain} #{account.uri}"
@signed_request_account = nil
end
end
@@ -117,7 +99,7 @@ module SignatureVerification
ResolveRemoteAccountService.new.call(key_id.gsub(/\Aacct:/, ''))
elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
account = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account)
account ||= ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false)
account ||= ActivityPub::FetchRemoteKeyService.new.call(key_id)
account
end
end

View File

@@ -7,24 +7,21 @@ module UserTrackingConcern
UPDATE_SIGN_IN_HOURS = 24
included do
before_action :set_user_activity
before_action :set_user_activity, if: %i(user_signed_in? user_needs_sign_in_update?)
end
private
def set_user_activity
return unless user_needs_sign_in_update?
# Mark as signed-in today
current_user.update_tracked_fields!(request)
ActivityTracker.record('activity:logins', current_user.id)
# Regenerate feed if needed
regenerate_feed! if user_needs_feed_update?
end
def user_needs_sign_in_update?
user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_HOURS.hours.ago)
current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_HOURS.hours.ago
end
def user_needs_feed_update?

View File

@@ -1,22 +0,0 @@
# frozen_string_literal: true
class EmojisController < ApplicationController
before_action :set_emoji
def show
respond_to do |format|
format.json do
render json: @emoji,
serializer: ActivityPub::EmojiSerializer,
adapter: ActivityPub::Adapter,
content_type: 'application/activity+json'
end
end
end
private
def set_emoji
@emoji = CustomEmoji.local.find(params[:id])
end
end

View File

@@ -7,44 +7,22 @@ class FollowerAccountsController < ApplicationController
@follows = Follow.where(target_account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account)
respond_to do |format|
format.html do
use_pack 'public'
end
format.html
format.json do
render json: collection_presenter,
serializer: ActivityPub::CollectionSerializer,
adapter: ActivityPub::Adapter,
content_type: 'application/activity+json'
render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
end
end
private
def page_url(page)
account_followers_url(@account, page: page) unless page.nil?
end
def collection_presenter
page = ActivityPub::CollectionPresenter.new(
id: account_followers_url(@account, page: params.fetch(:page, 1)),
type: :ordered,
size: @account.followers_count,
items: @follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) },
part_of: account_followers_url(@account),
next: page_url(@follows.next_page),
prev: page_url(@follows.prev_page)
)
if params[:page].present?
page
else
ActivityPub::CollectionPresenter.new(
id: account_followers_url(@account),
type: :ordered,
size: @account.followers_count,
first: page
items: @follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) }
)
end
end
end

View File

@@ -7,44 +7,22 @@ class FollowingAccountsController < ApplicationController
@follows = Follow.where(account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account)
respond_to do |format|
format.html do
use_pack 'public'
end
format.html
format.json do
render json: collection_presenter,
serializer: ActivityPub::CollectionSerializer,
adapter: ActivityPub::Adapter,
content_type: 'application/activity+json'
render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
end
end
private
def page_url(page)
account_following_index_url(@account, page: page) unless page.nil?
end
def collection_presenter
page = ActivityPub::CollectionPresenter.new(
id: account_following_index_url(@account, page: params.fetch(:page, 1)),
type: :ordered,
size: @account.following_count,
items: @follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) },
part_of: account_following_index_url(@account),
next: page_url(@follows.next_page),
prev: page_url(@follows.prev_page)
)
if params[:page].present?
page
else
ActivityPub::CollectionPresenter.new(
id: account_following_index_url(@account),
type: :ordered,
size: @account.following_count,
first: page
items: @follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) }
)
end
end
end

View File

@@ -2,7 +2,6 @@
class HomeController < ApplicationController
before_action :authenticate_user!
before_action :set_pack
before_action :set_initial_state_json
def index
@@ -12,34 +11,7 @@ class HomeController < ApplicationController
private
def authenticate_user!
return if user_signed_in?
matches = request.path.match(/\A\/web\/(statuses|accounts)\/([\d]+)\z/)
if matches
case matches[1]
when 'statuses'
status = Status.find_by(id: matches[2])
if status && (status.public_visibility? || status.unlisted_visibility?)
redirect_to(ActivityPub::TagManager.instance.url_for(status))
return
end
when 'accounts'
account = Account.find_by(id: matches[2])
if account
redirect_to(ActivityPub::TagManager.instance.url_for(account))
return
end
end
end
redirect_to(default_redirect_path)
end
def set_pack
use_pack 'home'
redirect_to(single_user_mode? ? account_path(Account.first) : about_path) unless user_signed_in?
end
def set_initial_state_json
@@ -56,14 +28,4 @@ class HomeController < ApplicationController
admin: Account.find_local(Setting.site_contact_username),
}
end
def default_redirect_path
if request.path.start_with?('/web')
new_user_session_path
elsif single_user_mode?
short_account_path(Account.first)
else
about_path
end
end
end

View File

@@ -1,48 +0,0 @@
# frozen_string_literal: true
class InvitesController < ApplicationController
include Authorization
layout 'admin'
before_action :authenticate_user!
before_action :set_pack
def index
authorize :invite, :create?
@invites = Invite.where(user: current_user)
@invite = Invite.new(expires_in: 1.day.to_i)
end
def create
authorize :invite, :create?
@invite = Invite.new(resource_params)
@invite.user = current_user
if @invite.save
redirect_to invites_path
else
@invites = Invite.where(user: current_user)
render :index
end
end
def destroy
@invite = Invite.where(user: current_user).find(params[:id])
authorize @invite, :destroy?
@invite.expire!
redirect_to invites_path
end
private
def set_pack
use_pack 'settings'
end
def resource_params
params.require(:invite).permit(:max_uses, :expires_in)
end
end

View File

@@ -1,7 +1,11 @@
# frozen_string_literal: true
class ManifestsController < ApplicationController
def show
render json: InstancePresenter.new, serializer: ManifestSerializer
before_action :set_instance_presenter
def show; end
def set_instance_presenter
@instance_presenter = InstancePresenter.new
end
end

View File

@@ -1,40 +0,0 @@
# frozen_string_literal: true
class MediaProxyController < ApplicationController
include RoutingHelper
def show
RedisLock.acquire(lock_options) do |lock|
if lock.acquired?
@media_attachment = MediaAttachment.remote.find(params[:id])
redownload! if @media_attachment.needs_redownload? && !reject_media?
end
end
redirect_to full_asset_url(@media_attachment.file.url(version))
end
private
def redownload!
@media_attachment.file_remote_url = @media_attachment.remote_url
@media_attachment.created_at = Time.now.utc
@media_attachment.save!
end
def version
if request.path.ends_with?('/small')
:small
else
:original
end
end
def lock_options
{ redis: Redis.current, key: "media_download:#{params[:id]}" }
end
def reject_media?
DomainBlock.find_by(domain: @media_attachment.account.domain)&.reject_media?
end
end

View File

@@ -5,7 +5,6 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
before_action :store_current_location
before_action :authenticate_resource_owner!
before_action :set_pack
include Localized
@@ -14,8 +13,4 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
def store_current_location
store_location_for(:user, request.url)
end
def set_pack
use_pack 'auth'
end
end

View File

@@ -5,7 +5,6 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
before_action :store_current_location
before_action :authenticate_resource_owner!
before_action :set_pack
include Localized
@@ -14,8 +13,4 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
def store_current_location
store_location_for(:user, request.url)
end
def set_pack
use_pack 'settings'
end
end

View File

@@ -4,7 +4,6 @@ class RemoteFollowController < ApplicationController
layout 'modal'
before_action :set_account
before_action :set_pack
before_action :gone, if: :suspended_account?
def new
@@ -32,10 +31,6 @@ class RemoteFollowController < ApplicationController
{ acct: session[:remote_follow] }
end
def set_pack
use_pack 'modal'
end
def set_account
@account = Account.find_local!(params[:account_username])
end
@@ -43,8 +38,4 @@ class RemoteFollowController < ApplicationController
def suspended_account?
@account.suspended?
end
def set_body_classes
@body_classes = 'modal-layout'
end
end

View File

@@ -1,7 +1,9 @@
# frozen_string_literal: true
class Settings::ApplicationsController < Settings::BaseController
class Settings::ApplicationsController < ApplicationController
layout 'admin'
before_action :authenticate_user!
before_action :set_application, only: [:show, :update, :destroy, :regenerate]
before_action :prepare_scopes, only: [:create, :update]

View File

@@ -1,12 +0,0 @@
# frozen_string_literal: true
class Settings::BaseController < ApplicationController
layout 'admin'
before_action :authenticate_user!
before_action :set_pack
def set_pack
use_pack 'settings'
end
end

View File

@@ -1,8 +1,10 @@
# frozen_string_literal: true
class Settings::DeletesController < Settings::BaseController
class Settings::DeletesController < ApplicationController
layout 'admin'
prepend_before_action :check_enabled_deletion
before_action :check_enabled_deletion
before_action :authenticate_user!
def show
@confirmation = Form::DeleteConfirmation.new

View File

@@ -1,6 +1,10 @@
# frozen_string_literal: true
class Settings::ExportsController < Settings::BaseController
class Settings::ExportsController < ApplicationController
layout 'admin'
before_action :authenticate_user!
def show
@export = Export.new(current_account)
end

View File

@@ -1,35 +0,0 @@
# frozen_string_literal: true
class Settings::FlavoursController < Settings::BaseController
def index
redirect_to action: 'show', flavour: current_flavour
end
def show
unless Themes.instance.flavours.include?(params[:flavour]) or params[:flavour] == current_flavour
redirect_to action: 'show', flavour: current_flavour
end
@listing = Themes.instance.flavours
@selected = params[:flavour]
end
def update
user_settings.update(user_settings_params(params[:flavour]).to_h)
redirect_to action: 'show', flavour: params[:flavour]
end
private
def user_settings
UserSettingsDecorator.new(current_user)
end
def user_settings_params(flavour)
params.require(:user).merge({ setting_flavour: flavour }).permit(
:setting_flavour,
:setting_skin
)
end
end

View File

@@ -2,10 +2,14 @@
require 'sidekiq-bulk'
class Settings::FollowerDomainsController < Settings::BaseController
class Settings::FollowerDomainsController < ApplicationController
layout 'admin'
before_action :authenticate_user!
def show
@account = current_account
@domains = current_account.followers.reorder('MIN(follows.id) DESC').group('accounts.domain').select('accounts.domain, count(accounts.id) as accounts_from_domain').page(params[:page]).per(10)
@domains = current_account.followers.reorder(nil).group('accounts.domain').select('accounts.domain, count(accounts.id) as accounts_from_domain').page(params[:page]).per(10)
end
def update

View File

@@ -1,6 +1,9 @@
# frozen_string_literal: true
class Settings::ImportsController < Settings::BaseController
class Settings::ImportsController < ApplicationController
layout 'admin'
before_action :authenticate_user!
before_action :set_account
def show

View File

@@ -1,61 +0,0 @@
# frozen_string_literal: true
class Settings::KeywordMutesController < Settings::BaseController
before_action :load_keyword_mute, only: [:edit, :update, :destroy]
def index
@keyword_mutes = paginated_keyword_mutes_for_account
end
def new
@keyword_mute = keyword_mutes_for_account.build
end
def create
@keyword_mute = keyword_mutes_for_account.create(keyword_mute_params)
if @keyword_mute.persisted?
redirect_to settings_keyword_mutes_path, notice: I18n.t('generic.changes_saved_msg')
else
render :new
end
end
def update
if @keyword_mute.update(keyword_mute_params)
redirect_to settings_keyword_mutes_path, notice: I18n.t('generic.changes_saved_msg')
else
render :edit
end
end
def destroy
@keyword_mute.destroy!
redirect_to settings_keyword_mutes_path, notice: I18n.t('generic.changes_saved_msg')
end
def destroy_all
keyword_mutes_for_account.delete_all
redirect_to settings_keyword_mutes_path, notice: I18n.t('generic.changes_saved_msg')
end
private
def keyword_mutes_for_account
Glitch::KeywordMute.where(account: current_account)
end
def load_keyword_mute
@keyword_mute = keyword_mutes_for_account.find(params[:id])
end
def keyword_mute_params
params.require(:keyword_mute).permit(:keyword, :whole_word)
end
def paginated_keyword_mutes_for_account
keyword_mutes_for_account.order(:keyword).page params[:page]
end
end

View File

@@ -1,34 +0,0 @@
# frozen_string_literal: true
class Settings::MigrationsController < ApplicationController
layout 'admin'
before_action :authenticate_user!
def show
@migration = Form::Migration.new(account: current_account.moved_to_account)
end
def update
@migration = Form::Migration.new(resource_params)
if @migration.valid? && migration_account_changed?
current_account.update!(moved_to_account: @migration.account)
ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)
redirect_to settings_migration_path, notice: I18n.t('migrations.updated_msg')
else
render :show
end
end
private
def resource_params
params.require(:migration).permit(:acct)
end
def migration_account_changed?
current_account.moved_to_account_id != @migration.account&.id &&
current_account.id != @migration.account&.id
end
end

View File

@@ -1,28 +0,0 @@
# frozen_string_literal: true
class Settings::NotificationsController < Settings::BaseController
def show; end
def update
user_settings.update(user_settings_params.to_h)
if current_user.save
redirect_to settings_notifications_path, notice: I18n.t('generic.changes_saved_msg')
else
render :show
end
end
private
def user_settings
UserSettingsDecorator.new(current_user)
end
def user_settings_params
params.require(:user).permit(
notification_emails: %i(follow follow_request reblog favourite mention digest),
interactions: %i(must_be_follower must_be_following must_be_following_dm)
)
end
end

View File

@@ -1,6 +1,10 @@
# frozen_string_literal: true
class Settings::PreferencesController < Settings::BaseController
class Settings::PreferencesController < ApplicationController
layout 'admin'
before_action :authenticate_user!
def show; end
def update
@@ -33,10 +37,8 @@ class Settings::PreferencesController < Settings::BaseController
:setting_default_sensitive,
:setting_unfollow_modal,
:setting_boost_modal,
:setting_favourite_modal,
:setting_delete_modal,
:setting_auto_play_gif,
:setting_reduce_motion,
:setting_system_font_ui,
:setting_noindex,
notification_emails: %i(follow follow_request reblog favourite mention digest),

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