Compare commits

..

19 Commits

Author SHA1 Message Date
kibigo!
da2b6dda6a This is a better way of detecting frontends 2017-06-22 21:10:02 -07:00
kibigo!
ed82421870 Forgot to delete a debugging thing sry 😰 2017-06-22 20:38:08 -07:00
kibigo!
b3904c2553 MORE FRONTENDS (EASY MODE) WIN!!! 2017-06-22 20:15:11 -07:00
beatrix
101a4c6913 glitch the getting started image 2017-06-22 13:04:56 -04:00
kibigo!
11da74dbb7 Very minor styling improvements to toot-collapsing 2017-06-22 00:54:33 -07:00
kibigo!
51a86b32c3 Updates height upon collapsing 2017-06-21 20:17:12 -07:00
kibigo!
51b783cdbc Minor collapsing button improvements~ 2017-06-21 19:54:41 -07:00
kibigo!
3915f06b02 Collapsable toots [1/??] 2017-06-21 19:40:53 -07:00
kibigo!
07b1171c73 Profile Metadata HACK 😈 2017-06-20 19:44:43 -07:00
Go Shoemake
571576d6f7 Fixes drawer so stuff doesn't overflow 2017-06-20 23:46:17 +00:00
Charlotte Fields
7151ec7680 cybre cleanup 2017-06-20 23:46:17 +00:00
Chronister
a4b3009c1c cybrespace to 1.4.2 2017-06-20 23:46:17 +00:00
Chronister
ef30a92c71 All cybrespace changes through 5/28 2017-06-20 23:46:17 +00:00
Charlotte Fields
613aa55e03 adding cybre changes 2017-06-20 23:46:17 +00:00
beatrix-bitrot
88a08d54b6 update local modifications for cors and cp 2017-06-20 23:46:17 +00:00
beatrix-bitrot
3a69d70eae silly readme update to test automated deploys 2017-06-20 23:46:17 +00:00
beatrix-bitrot
9c778f4abf update README.md 2017-06-20 23:46:17 +00:00
beatrix
ac61ce5826 Update README.md 2017-06-20 23:46:17 +00:00
Beatrix Bitrot
73d6da32be CORS tweaks 2017-06-20 23:46:17 +00:00
924 changed files with 8841 additions and 22466 deletions

View File

@@ -15,15 +15,13 @@
"plugins": [ "plugins": [
"syntax-dynamic-import", "syntax-dynamic-import",
["transform-object-rest-spread", { "useBuiltIns": true }], ["transform-object-rest-spread", { "useBuiltIns": true }],
"transform-decorators-legacy",
"transform-class-properties", "transform-class-properties",
[ [
"react-intl", "react-intl",
{ {
"messagesDir": "./build/messages" "messagesDir": "./build/messages"
} }
], ]
"preval"
], ],
"env": { "env": {
"development": { "development": {
@@ -45,7 +43,6 @@
] ]
} }
], ],
"transform-react-inline-elements",
[ [
"transform-runtime", "transform-runtime",
{ {

View File

@@ -4,6 +4,7 @@ public/system
public/assets public/assets
public/packs public/packs
node_modules node_modules
storybook
neo4j neo4j
vendor/bundle vendor/bundle
.DS_Store .DS_Store

View File

@@ -69,7 +69,7 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
# PAPERCLIP_ROOT_URL=/system # PAPERCLIP_ROOT_URL=/system
# Optional asset host for multi-server setups # Optional asset host for multi-server setups
# CDN_HOST=https://assets.example.com # CDN_HOST=assets.example.com
# S3 (optional) # S3 (optional)
# S3_ENABLED=true # S3_ENABLED=true

View File

@@ -31,17 +31,6 @@ 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 (`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=
VAPID_PUBLIC_KEY=
# Registrations # Registrations
# Single user mode will disable registrations and redirect frontpage to the first profile # Single user mode will disable registrations and redirect frontpage to the first profile
# SINGLE_USER_MODE=true # SINGLE_USER_MODE=true
@@ -69,7 +58,7 @@ SMTP_FROM_ADDRESS=notifications@example.com
#SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt #SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt
#SMTP_OPENSSL_VERIFY_MODE=peer #SMTP_OPENSSL_VERIFY_MODE=peer
#SMTP_ENABLE_STARTTLS_AUTO=true #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. # 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 # PAPERCLIP_ROOT_PATH=/var/lib/mastodon/public-system

View File

@@ -1,9 +1,7 @@
--- ---
root: true
env: env:
browser: true browser: true
node: true node: false
es6: true es6: true
parser: babel-eslint parser: babel-eslint
@@ -49,20 +47,13 @@ rules:
- warn - warn
- allow: - allow:
- error - error
- warn
no-fallthrough: error no-fallthrough: error
no-irregular-whitespace: error no-irregular-whitespace: error
no-mixed-spaces-and-tabs: warn no-mixed-spaces-and-tabs: warn
no-nested-ternary: warn no-nested-ternary: warn
no-trailing-spaces: warn no-trailing-spaces: warn
no-undef: error
no-unreachable: error no-unreachable: error
no-unused-expressions: error no-unused-expressions: error
no-unused-vars:
- error
- vars: all
args: after-used
ignoreRestSiblings: true
object-curly-spacing: object-curly-spacing:
- error - error
- always - always
@@ -90,10 +81,7 @@ rules:
- 2 - 2
react/jsx-no-bind: error react/jsx-no-bind: error
react/jsx-no-duplicate-props: error react/jsx-no-duplicate-props: error
react/jsx-no-undef: error
react/jsx-tag-spacing: error react/jsx-tag-spacing: error
react/jsx-uses-react: error
react/jsx-uses-vars: error
react/jsx-wrap-multilines: error react/jsx-wrap-multilines: error
react/no-multi-comp: off react/no-multi-comp: off
react/no-string-refs: error react/no-string-refs: error
@@ -113,7 +101,7 @@ rules:
jsx-a11y/iframe-has-title: warn jsx-a11y/iframe-has-title: warn
jsx-a11y/img-has-alt: warn jsx-a11y/img-has-alt: warn
jsx-a11y/img-redundant-alt: warn jsx-a11y/img-redundant-alt: warn
jsx-a11y/label-has-for: off jsx-a11y/label-has-for: warn
jsx-a11y/mouse-events-have-key-events: warn jsx-a11y/mouse-events-have-key-events: warn
jsx-a11y/no-access-key: warn jsx-a11y/no-access-key: warn
jsx-a11y/no-distracting-elements: warn jsx-a11y/no-distracting-elements: warn
@@ -122,6 +110,6 @@ rules:
jsx-a11y/onclick-has-focus: warn jsx-a11y/onclick-has-focus: warn
jsx-a11y/onclick-has-role: warn jsx-a11y/onclick-has-role: warn
jsx-a11y/role-has-required-aria-props: warn jsx-a11y/role-has-required-aria-props: warn
jsx-a11y/role-supports-aria-props: off jsx-a11y/role-supports-aria-props: warn
jsx-a11y/scope: warn jsx-a11y/scope: warn
jsx-a11y/tabindex-no-positive: warn jsx-a11y/tabindex-no-positive: warn

14
.gitattributes vendored
View File

@@ -1,14 +0,0 @@
* text=auto eol=lf
*.eot -text
*.gif -text
*.gz -text
*.ico -text
*.jpg -text
*.mp3 -text
*.ogg -text
*.png -text
*.ttf -text
*.webm -text
*.woff -text
*.woff2 -text
spec/fixtures/requests/** -text !eol

View File

@@ -14,6 +14,7 @@ node_modules/
public/assets/ public/assets/
public/system/ public/system/
spec/ spec/
storybook/
tmp/ tmp/
.vagrant/ .vagrant/
vendor/bundle/ vendor/bundle/

View File

@@ -6,4 +6,3 @@ plugins:
- last 2 versions - last 2 versions
- IE >= 11 - IE >= 11
- iOS >= 9 - iOS >= 9
postcss-object-fit-images: {}

View File

@@ -10,7 +10,6 @@ AllCops:
- 'node_modules/**/*' - 'node_modules/**/*'
- 'Vagrantfile' - 'Vagrantfile'
- 'vendor/**/*' - 'vendor/**/*'
- 'lib/json_ld/*'
Bundler/OrderedGems: Bundler/OrderedGems:
Enabled: false Enabled: false
@@ -28,7 +27,6 @@ Metrics/AbcSize:
Max: 100 Max: 100
Metrics/BlockLength: Metrics/BlockLength:
Max: 35
Exclude: Exclude:
- 'lib/tasks/**/*' - 'lib/tasks/**/*'
@@ -37,10 +35,10 @@ Metrics/BlockNesting:
Metrics/ClassLength: Metrics/ClassLength:
CountComments: false CountComments: false
Max: 300 Max: 200
Metrics/CyclomaticComplexity: Metrics/CyclomaticComplexity:
Max: 25 Max: 15
Metrics/LineLength: Metrics/LineLength:
AllowURI: true AllowURI: true
@@ -55,11 +53,11 @@ Metrics/ModuleLength:
Max: 200 Max: 200
Metrics/ParameterLists: Metrics/ParameterLists:
Max: 5 Max: 4
CountKeywordArgs: true CountKeywordArgs: true
Metrics/PerceivedComplexity: Metrics/PerceivedComplexity:
Max: 20 Max: 10
Rails: Rails:
Enabled: true Enabled: true

View File

@@ -2,3 +2,4 @@ node_modules/
.cache/ .cache/
docs/ docs/
spec/ spec/
storybook/

View File

@@ -6,9 +6,8 @@ cache:
- node_modules - node_modules
- public/assets - public/assets
- public/packs-test - public/packs-test
- tmp/cache/babel-loader
dist: trusty dist: trusty
sudo: required sudo: false
notifications: notifications:
email: false email: false
@@ -33,7 +32,6 @@ addons:
- g++-6 - g++-6
- libprotobuf-dev - libprotobuf-dev
- protobuf-compiler - protobuf-compiler
- libicu-dev
rvm: rvm:
- 2.3.4 - 2.3.4

View File

@@ -1,9 +1,5 @@
ffmpeg protobuf-compiler
libicu-dev
libidn11
libidn11-dev
libpq-dev
libprotobuf-dev libprotobuf-dev
ffmpeg
libxdamage1 libxdamage1
libxfixes3 libxfixes3
protobuf-compiler

View File

@@ -1,15 +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ą
/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,4 +1,4 @@
FROM ruby:2.4.1-alpine3.6 FROM ruby:2.4.1-alpine
LABEL maintainer="https://github.com/tootsuite/mastodon" \ LABEL maintainer="https://github.com/tootsuite/mastodon" \
description="A GNU Social-compatible microblogging server" description="A GNU Social-compatible microblogging server"
@@ -7,19 +7,16 @@ ENV UID=991 GID=991 \
RAILS_SERVE_STATIC_FILES=true \ RAILS_SERVE_STATIC_FILES=true \
RAILS_ENV=production NODE_ENV=production RAILS_ENV=production NODE_ENV=production
ARG LIBICONV_VERSION=1.15
ARG LIBICONV_DOWNLOAD_SHA256=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178
EXPOSE 3000 4000 EXPOSE 3000 4000
WORKDIR /mastodon WORKDIR /mastodon
RUN apk -U upgrade \ RUN echo "@edge https://nl.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories \
&& apk -U upgrade \
&& apk add -t build-dependencies \ && apk add -t build-dependencies \
build-base \ build-base \
icu-dev \ libxml2-dev \
libidn-dev \ libxslt-dev \
libtool \
postgresql-dev \ postgresql-dev \
protobuf-dev \ protobuf-dev \
python \ python \
@@ -28,34 +25,22 @@ RUN apk -U upgrade \
ffmpeg \ ffmpeg \
file \ file \
git \ git \
icu-libs \ imagemagick@edge \
imagemagick \
libidn \
libpq \ libpq \
nodejs-npm \ libxml2 \
nodejs \ libxslt \
nodejs-npm@edge \
nodejs@edge \
protobuf \ protobuf \
su-exec \ su-exec \
tini \ tini \
yarn \ && npm install -g npm@3 && npm install -g yarn \
&& update-ca-certificates \ && update-ca-certificates \
&& 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 \
&& ./configure --prefix=/usr/local \
&& make -j$(getconf _NPROCESSORS_ONLN)\
&& make install \
&& libtool --finish /usr/local/lib \
&& cd /mastodon \
&& rm -rf /tmp/* /var/cache/apk/* && rm -rf /tmp/* /var/cache/apk/*
COPY Gemfile Gemfile.lock package.json yarn.lock /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 \ RUN bundle install --deployment --without test development \
&& bundle install -j$(getconf _NPROCESSORS_ONLN) --deployment --without test development \
&& yarn --ignore-optional --pure-lockfile && yarn --ignore-optional --pure-lockfile
COPY . /mastodon COPY . /mastodon

14
Gemfile
View File

@@ -18,27 +18,22 @@ gem 'aws-sdk', '~> 2.9'
gem 'paperclip', '~> 5.1' gem 'paperclip', '~> 5.1'
gem 'paperclip-av-transcoder', '~> 0.6' gem 'paperclip-av-transcoder', '~> 0.6'
gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.5' gem 'addressable', '~> 2.5'
gem 'bootsnap' gem 'bootsnap'
gem 'browser'
gem 'charlock_holmes', '~> 0.7.5'
gem 'cld3', '~> 3.1' gem 'cld3', '~> 3.1'
gem 'devise', '~> 4.2' gem 'devise', '~> 4.2'
gem 'devise-two-factor', '~> 3.0' gem 'devise-two-factor', '~> 3.0'
gem 'doorkeeper', '~> 4.2' gem 'doorkeeper', '~> 4.2'
gem 'fast_blank', '~> 1.0' gem 'fast_blank', '~> 1.0'
gem 'goldfinger', '~> 2.0' gem 'goldfinger', '~> 1.2'
gem 'hiredis', '~> 0.6' gem 'hiredis', '~> 0.6'
gem 'redis-namespace', '~> 1.5' gem 'redis-namespace', '~> 1.5'
gem 'htmlentities', '~> 4.3' gem 'htmlentities', '~> 4.3'
gem 'http', '~> 2.2' gem 'http', '~> 2.2'
gem 'http_accept_language', '~> 2.1' gem 'http_accept_language', '~> 2.1'
gem 'httplog', '~> 0.99' gem 'httplog', '~> 0.99'
gem 'idn-ruby', require: 'idn'
gem 'kaminari', '~> 1.0' gem 'kaminari', '~> 1.0'
gem 'link_header', '~> 0.0' gem 'link_header', '~> 0.0'
gem 'mime-types', '~> 3.1'
gem 'nokogiri', '~> 1.7' gem 'nokogiri', '~> 1.7'
gem 'oj', '~> 3.0' gem 'oj', '~> 3.0'
gem 'ostatus2', '~> 2.0' gem 'ostatus2', '~> 2.0'
@@ -51,7 +46,6 @@ gem 'rack-timeout', '~> 0.4'
gem 'rails-i18n', '~> 5.0' gem 'rails-i18n', '~> 5.0'
gem 'rails-settings-cached', '~> 0.6' gem 'rails-settings-cached', '~> 0.6'
gem 'redis', '~> 3.3', require: ['redis', 'redis/connection/hiredis'] gem 'redis', '~> 3.3', require: ['redis', 'redis/connection/hiredis']
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'rqrcode', '~> 0.10' gem 'rqrcode', '~> 0.10'
gem 'ruby-oembed', '~> 0.12', require: 'oembed' gem 'ruby-oembed', '~> 0.12', require: 'oembed'
gem 'sanitize', '~> 4.4' gem 'sanitize', '~> 4.4'
@@ -66,10 +60,6 @@ gem 'statsd-instrument', '~> 2.1'
gem 'twitter-text', '~> 1.14' gem 'twitter-text', '~> 1.14'
gem 'tzinfo-data', '~> 1.2017' gem 'tzinfo-data', '~> 1.2017'
gem 'webpacker', '~> 2.0' gem 'webpacker', '~> 2.0'
gem 'webpush'
gem 'json-ld-preloaded', '~> 2.2.1'
gem 'rdf-normalize', '~> 0.3.1'
group :development, :test do group :development, :test do
gem 'fabrication', '~> 2.16' gem 'fabrication', '~> 2.16'
@@ -83,7 +73,7 @@ group :test do
gem 'capybara', '~> 2.14' gem 'capybara', '~> 2.14'
gem 'climate_control', '~> 0.2' gem 'climate_control', '~> 0.2'
gem 'faker', '~> 1.7' gem 'faker', '~> 1.7'
gem 'microformats', '~> 4.0' gem 'microformats2', '~> 3.0'
gem 'rails-controller-testing', '~> 1.0' gem 'rails-controller-testing', '~> 1.0'
gem 'rspec-sidekiq', '~> 3.0' gem 'rspec-sidekiq', '~> 3.0'
gem 'simplecov', '~> 0.14', require: false gem 'simplecov', '~> 0.14', require: false

View File

@@ -1,52 +1,47 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (5.1.3) actioncable (5.1.1)
actionpack (= 5.1.3) actionpack (= 5.1.1)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (~> 0.6.1) websocket-driver (~> 0.6.1)
actionmailer (5.1.3) actionmailer (5.1.1)
actionpack (= 5.1.3) actionpack (= 5.1.1)
actionview (= 5.1.3) actionview (= 5.1.1)
activejob (= 5.1.3) activejob (= 5.1.1)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
actionpack (5.1.3) actionpack (5.1.1)
actionview (= 5.1.3) actionview (= 5.1.1)
activesupport (= 5.1.3) activesupport (= 5.1.1)
rack (~> 2.0) rack (~> 2.0)
rack-test (~> 0.6.3) rack-test (~> 0.6.3)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.1.3) actionview (5.1.1)
activesupport (= 5.1.3) activesupport (= 5.1.1)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.4) erubi (~> 1.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3) rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_model_serializers (0.10.6)
actionpack (>= 4.1, < 6)
activemodel (>= 4.1, < 6)
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.2)
active_record_query_trace (1.5.4) active_record_query_trace (1.5.4)
activejob (5.1.3) activejob (5.1.1)
activesupport (= 5.1.3) activesupport (= 5.1.1)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (5.1.3) activemodel (5.1.1)
activesupport (= 5.1.3) activesupport (= 5.1.1)
activerecord (5.1.3) activerecord (5.1.1)
activemodel (= 5.1.3) activemodel (= 5.1.1)
activesupport (= 5.1.3) activesupport (= 5.1.1)
arel (~> 8.0) arel (~> 8.0)
activesupport (5.1.3) activesupport (5.1.1)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7) i18n (~> 0.7)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
addressable (2.5.2) addressable (2.5.1)
public_suffix (>= 2.0.2, < 4.0) public_suffix (~> 2.0, >= 2.0.2)
airbrussh (1.3.0) airbrussh (1.2.0)
sshkit (>= 1.6.1, != 1.7.0) sshkit (>= 1.6.1, != 1.7.0)
annotate (2.7.2) annotate (2.7.2)
activerecord (>= 3.2, < 6.0) activerecord (>= 3.2, < 6.0)
@@ -57,14 +52,14 @@ GEM
encryptor (~> 3.0.0) encryptor (~> 3.0.0)
av (0.9.0) av (0.9.0)
cocaine (~> 0.5.3) cocaine (~> 0.5.3)
aws-sdk (2.10.21) aws-sdk (2.9.37)
aws-sdk-resources (= 2.10.21) aws-sdk-resources (= 2.9.37)
aws-sdk-core (2.10.21) aws-sdk-core (2.9.37)
aws-sigv4 (~> 1.0) aws-sigv4 (~> 1.0)
jmespath (~> 1.0) jmespath (~> 1.0)
aws-sdk-resources (2.10.21) aws-sdk-resources (2.9.37)
aws-sdk-core (= 2.10.21) aws-sdk-core (= 2.9.37)
aws-sigv4 (1.0.1) aws-sigv4 (1.0.0)
bcrypt (3.1.11) bcrypt (3.1.11)
better_errors (2.1.1) better_errors (2.1.1)
coderay (>= 1.0.0) coderay (>= 1.0.0)
@@ -72,18 +67,17 @@ GEM
rack (>= 0.9.0) rack (>= 0.9.0)
binding_of_caller (0.7.2) binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
bootsnap (1.1.2) bootsnap (1.0.0)
msgpack (~> 1.0) msgpack (~> 1.0)
brakeman (3.7.2) brakeman (3.6.2)
browser (2.4.0)
builder (3.2.3) builder (3.2.3)
bullet (5.5.1) bullet (5.5.1)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
uniform_notifier (~> 1.10.0) uniform_notifier (~> 1.10.0)
bundler-audit (0.6.0) bundler-audit (0.5.0)
bundler (~> 1.2) bundler (~> 1.2)
thor (~> 0.18) thor (~> 0.18)
capistrano (3.8.2) capistrano (3.8.1)
airbrussh (>= 1.0.0) airbrussh (>= 1.0.0)
i18n i18n
rake (>= 10.0.0) rake (>= 10.0.0)
@@ -99,18 +93,15 @@ GEM
sshkit (~> 1.3) sshkit (~> 1.3)
capistrano-yarn (2.0.2) capistrano-yarn (2.0.2)
capistrano (~> 3.0) capistrano (~> 3.0)
capybara (2.14.4) capybara (2.14.2)
addressable addressable
mime-types (>= 1.16) mime-types (>= 1.16)
nokogiri (>= 1.3.3) nokogiri (>= 1.3.3)
rack (>= 1.0.0) rack (>= 1.0.0)
rack-test (>= 0.5.4) rack-test (>= 0.5.4)
xpath (~> 2.0) xpath (~> 2.0)
case_transform (0.2)
activesupport
charlock_holmes (0.7.5)
chunky_png (1.3.8) chunky_png (1.3.8)
cld3 (3.1.3) cld3 (3.1.2)
ffi (>= 1.1.0, < 1.10.0) ffi (>= 1.1.0, < 1.10.0)
climate_control (0.2.0) climate_control (0.2.0)
cocaine (0.5.8) cocaine (0.5.8)
@@ -150,12 +141,12 @@ GEM
thread thread
thread_safe thread_safe
encryptor (3.0.0) encryptor (3.0.0)
erubi (1.6.1) erubi (1.6.0)
erubis (2.7.0) erubis (2.7.0)
et-orbi (1.0.5) et-orbi (1.0.4)
tzinfo tzinfo
execjs (2.7.0) execjs (2.7.0)
fabrication (2.16.2) fabrication (2.16.1)
faker (1.7.3) faker (1.7.3)
i18n (~> 0.5) i18n (~> 0.5)
fast_blank (1.0.0) fast_blank (1.0.0)
@@ -165,12 +156,11 @@ GEM
ruby-progressbar (~> 1.4) ruby-progressbar (~> 1.4)
globalid (0.4.0) globalid (0.4.0)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
goldfinger (2.0.1) goldfinger (1.2.0)
addressable (~> 2.5) addressable (~> 2.4)
http (~> 2.2) http (~> 2.0)
nokogiri (~> 1.8) nokogiri (~> 1.6)
oj (~> 3.0) hamlit (2.8.1)
hamlit (2.8.4)
temple (>= 0.8.0) temple (>= 0.8.0)
thor thor
tilt tilt
@@ -179,12 +169,9 @@ GEM
activesupport (>= 4.0.1) activesupport (>= 4.0.1)
hamlit (>= 1.2.0) hamlit (>= 1.2.0)
railties (>= 4.0.1) railties (>= 4.0.1)
hamster (3.0.0) hashdiff (0.3.4)
concurrent-ruby (~> 1.0)
hashdiff (0.3.5)
highline (1.7.8) highline (1.7.8)
hiredis (0.6.1) hiredis (0.6.1)
hkdf (0.3.0)
htmlentities (4.3.4) htmlentities (4.3.4)
http (2.2.2) http (2.2.2)
addressable (~> 2.3) addressable (~> 2.3)
@@ -194,13 +181,13 @@ GEM
http-cookie (1.0.3) http-cookie (1.0.3)
domain_name (~> 0.5) domain_name (~> 0.5)
http-form_data (1.0.3) http-form_data (1.0.3)
http_accept_language (2.1.1) http_accept_language (2.1.0)
http_parser.rb (0.6.0) http_parser.rb (0.6.0)
httplog (0.99.7) httplog (0.99.3)
colorize colorize
rack rack
i18n (0.8.6) i18n (0.8.4)
i18n-tasks (0.9.16) i18n-tasks (0.9.15)
activesupport (>= 4.0.2) activesupport (>= 4.0.2)
ast (>= 2.1.0) ast (>= 2.1.0)
easy_translate (>= 0.5.0) easy_translate (>= 0.5.0)
@@ -210,18 +197,8 @@ GEM
parser (>= 2.2.3.0) parser (>= 2.2.3.0)
rainbow (~> 2.2) rainbow (~> 2.2)
terminal-table (>= 1.5.1) terminal-table (>= 1.5.1)
idn-ruby (0.1.0)
jmespath (1.3.1) jmespath (1.3.1)
json (2.1.0) json (2.1.0)
json-ld (2.1.5)
multi_json (~> 1.12)
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.1.3)
jwt (1.5.6)
kaminari (1.0.1) kaminari (1.0.1)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
kaminari-actionview (= 1.0.1) kaminari-actionview (= 1.0.1)
@@ -251,10 +228,8 @@ GEM
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.6.6) mail (2.6.6)
mime-types (>= 1.16, < 4) mime-types (>= 1.16, < 4)
mario-redis-lock (1.2.0)
redis (~> 3, >= 3.0.5)
method_source (0.8.2) method_source (0.8.2)
microformats (4.0.7) microformats2 (3.1.0)
json json
nokogiri nokogiri
mime-types (3.1) mime-types (3.1)
@@ -262,7 +237,7 @@ GEM
mime-types-data (3.2016.0521) mime-types-data (3.2016.0521)
mimemagic (0.3.2) mimemagic (0.3.2)
mini_portile2 (2.2.0) mini_portile2 (2.2.0)
minitest (5.10.3) minitest (5.10.2)
msgpack (1.1.0) msgpack (1.1.0)
multi_json (1.12.1) multi_json (1.12.1)
net-scp (1.2.1) net-scp (1.2.1)
@@ -273,8 +248,8 @@ GEM
mini_portile2 (~> 2.2.0) mini_portile2 (~> 2.2.0)
nokogumbo (1.4.13) nokogumbo (1.4.13)
nokogiri nokogiri
oj (3.3.4) oj (3.1.0)
openssl (2.0.4) openssl (2.0.3)
orm_adapter (0.5.0) orm_adapter (0.5.0)
ostatus2 (2.0.1) ostatus2 (2.0.1)
addressable (~> 2.4) addressable (~> 2.4)
@@ -292,14 +267,14 @@ GEM
av (~> 0.9.0) av (~> 0.9.0)
paperclip (>= 2.5.2) paperclip (>= 2.5.2)
parallel (1.11.2) parallel (1.11.2)
parallel_tests (2.14.2) parallel_tests (2.14.1)
parallel parallel
parser (2.4.0.0) parser (2.4.0.0)
ast (~> 2.2) ast (~> 2.2)
pg (0.21.0) pg (0.20.0)
pghero (1.7.0) pghero (1.7.0)
activerecord activerecord
pkg-config (1.2.4) pkg-config (1.2.3)
powerpack (0.1.1) powerpack (0.1.1)
pry (0.10.4) pry (0.10.4)
coderay (~> 1.1.0) coderay (~> 1.1.0)
@@ -307,7 +282,7 @@ GEM
slop (~> 3.4) slop (~> 3.4)
pry-rails (0.3.6) pry-rails (0.3.6)
pry (>= 0.10.4) pry (>= 0.10.4)
public_suffix (3.0.0) public_suffix (2.0.5)
puma (3.9.1) puma (3.9.1)
pundit (1.1.0) pundit (1.1.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
@@ -322,17 +297,17 @@ GEM
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rack-timeout (0.4.2) rack-timeout (0.4.2)
rails (5.1.3) rails (5.1.1)
actioncable (= 5.1.3) actioncable (= 5.1.1)
actionmailer (= 5.1.3) actionmailer (= 5.1.1)
actionpack (= 5.1.3) actionpack (= 5.1.1)
actionview (= 5.1.3) actionview (= 5.1.1)
activejob (= 5.1.3) activejob (= 5.1.1)
activemodel (= 5.1.3) activemodel (= 5.1.1)
activerecord (= 5.1.3) activerecord (= 5.1.1)
activesupport (= 5.1.3) activesupport (= 5.1.1)
bundler (>= 1.3.0) bundler (>= 1.3.0, < 2.0)
railties (= 5.1.3) railties (= 5.1.1)
sprockets-rails (>= 2.0.0) sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.2) rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1) actionpack (~> 5.x, >= 5.0.1)
@@ -346,28 +321,23 @@ GEM
rails-i18n (5.0.4) rails-i18n (5.0.4)
i18n (~> 0.7) i18n (~> 0.7)
railties (~> 5.0) railties (~> 5.0)
rails-settings-cached (0.6.6) rails-settings-cached (0.6.5)
rails (>= 4.2.0) rails (>= 4.2.0)
railties (5.1.3) railties (5.1.1)
actionpack (= 5.1.3) actionpack (= 5.1.1)
activesupport (= 5.1.3) activesupport (= 5.1.1)
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (2.2.2) rainbow (2.2.2)
rake rake
rake (12.0.0) 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.3) redis (3.3.3)
redis-actionpack (5.0.1) redis-actionpack (5.0.1)
actionpack (>= 4.0, < 6) actionpack (>= 4.0, < 6)
redis-rack (>= 1, < 3) redis-rack (>= 1, < 3)
redis-store (>= 1.1.0, < 1.4.0) redis-store (>= 1.1.0, < 1.4.0)
redis-activesupport (5.0.3) redis-activesupport (5.0.2)
activesupport (>= 3, < 6) activesupport (>= 3, < 6)
redis-store (~> 1.3.0) redis-store (~> 1.3.0)
redis-namespace (1.5.3) redis-namespace (1.5.3)
@@ -403,7 +373,7 @@ GEM
rspec-expectations (~> 3.6.0) rspec-expectations (~> 3.6.0)
rspec-mocks (~> 3.6.0) rspec-mocks (~> 3.6.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.6.0)
rspec-sidekiq (3.0.3) rspec-sidekiq (3.0.1)
rspec-core (~> 3.0, >= 3.0.0) rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0) sidekiq (>= 2.4.0)
rspec-support (3.6.0) rspec-support (3.6.0)
@@ -424,10 +394,10 @@ GEM
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
nokogumbo (~> 1.4.1) nokogumbo (~> 1.4.1)
sass (3.4.24) sass (3.4.24)
scss_lint (0.54.0) scss_lint (0.53.0)
rake (>= 0.9, < 13) rake (>= 0.9, < 13)
sass (~> 3.4.20) sass (~> 3.4.20)
sidekiq (5.0.4) sidekiq (5.0.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0) connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0) rack-protection (>= 1.5.0)
@@ -435,12 +405,12 @@ GEM
sidekiq-bulk (0.1.1) sidekiq-bulk (0.1.1)
activesupport activesupport
sidekiq sidekiq
sidekiq-scheduler (2.1.8) sidekiq-scheduler (2.1.5)
redis (~> 3) redis (~> 3)
rufus-scheduler (~> 3.2) rufus-scheduler (~> 3.2)
sidekiq (>= 3) sidekiq (>= 3)
tilt (>= 1.4.0) tilt (>= 1.4.0)
sidekiq-unique-jobs (5.0.9) sidekiq-unique-jobs (5.0.8)
sidekiq (>= 4.0, <= 6.0) sidekiq (>= 4.0, <= 6.0)
thor (~> 0) thor (~> 0)
simple-navigation (4.0.5) simple-navigation (4.0.5)
@@ -464,15 +434,15 @@ GEM
sshkit (1.13.1) sshkit (1.13.1)
net-scp (>= 1.1.2) net-scp (>= 1.1.2)
net-ssh (>= 2.8.0) net-ssh (>= 2.8.0)
statsd-instrument (2.1.4) statsd-instrument (2.1.2)
temple (0.8.0) temple (0.8.0)
terminal-table (1.8.0) terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1) unicode-display_width (~> 1.1, >= 1.1.1)
thor (0.20.0) thor (0.19.4)
thread (0.2.2) thread (0.2.2)
thread_safe (0.3.6) thread_safe (0.3.6)
tilt (2.0.8) tilt (2.0.7)
twitter-text (1.14.7) twitter-text (1.14.5)
unf (~> 0.1.0) unf (~> 0.1.0)
tzinfo (1.2.3) tzinfo (1.2.3)
thread_safe (~> 0.1) thread_safe (~> 0.1)
@@ -483,7 +453,7 @@ GEM
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.4) unf_ext (0.0.7.4)
unicode-display_width (1.3.0) unicode-display_width (1.2.1)
uniform_notifier (1.10.0) uniform_notifier (1.10.0)
warden (1.2.7) warden (1.2.7)
rack (>= 1.0) rack (>= 1.0)
@@ -495,9 +465,6 @@ GEM
activesupport (>= 4.2) activesupport (>= 4.2)
multi_json (~> 1.2) multi_json (~> 1.2)
railties (>= 4.2) railties (>= 4.2)
webpush (0.3.2)
hkdf (~> 0.2)
jwt
websocket-driver (0.6.5) websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2) websocket-extensions (0.1.2)
@@ -508,7 +475,6 @@ PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
active_model_serializers (~> 0.10)
active_record_query_trace (~> 1.5) active_record_query_trace (~> 1.5)
addressable (~> 2.5) addressable (~> 2.5)
annotate (~> 2.7) annotate (~> 2.7)
@@ -517,7 +483,6 @@ DEPENDENCIES
binding_of_caller (~> 0.7) binding_of_caller (~> 0.7)
bootsnap bootsnap
brakeman (~> 3.6) brakeman (~> 3.6)
browser
bullet (~> 5.5) bullet (~> 5.5)
bundler-audit (~> 0.5) bundler-audit (~> 0.5)
capistrano (~> 3.8) capistrano (~> 3.8)
@@ -525,7 +490,6 @@ DEPENDENCIES
capistrano-rbenv (~> 2.1) capistrano-rbenv (~> 2.1)
capistrano-yarn (~> 2.0) capistrano-yarn (~> 2.0)
capybara (~> 2.14) capybara (~> 2.14)
charlock_holmes (~> 0.7.5)
cld3 (~> 3.1) cld3 (~> 3.1)
climate_control (~> 0.2) climate_control (~> 0.2)
devise (~> 4.2) devise (~> 4.2)
@@ -536,7 +500,7 @@ DEPENDENCIES
faker (~> 1.7) faker (~> 1.7)
fast_blank (~> 1.0) fast_blank (~> 1.0)
fuubar (~> 2.2) fuubar (~> 2.2)
goldfinger (~> 2.0) goldfinger (~> 1.2)
hamlit-rails (~> 0.2) hamlit-rails (~> 0.2)
hiredis (~> 0.6) hiredis (~> 0.6)
htmlentities (~> 4.3) htmlentities (~> 4.3)
@@ -544,16 +508,12 @@ DEPENDENCIES
http_accept_language (~> 2.1) http_accept_language (~> 2.1)
httplog (~> 0.99) httplog (~> 0.99)
i18n-tasks (~> 0.9) i18n-tasks (~> 0.9)
idn-ruby
json-ld-preloaded (~> 2.2.1)
kaminari (~> 1.0) kaminari (~> 1.0)
letter_opener (~> 1.4) letter_opener (~> 1.4)
letter_opener_web (~> 1.3) letter_opener_web (~> 1.3)
link_header (~> 0.0) link_header (~> 0.0)
lograge (~> 0.5) lograge (~> 0.5)
mario-redis-lock (~> 1.2) microformats2 (~> 3.0)
microformats (~> 4.0)
mime-types (~> 3.1)
nokogiri (~> 1.7) nokogiri (~> 1.7)
oj (~> 3.0) oj (~> 3.0)
ostatus2 (~> 2.0) ostatus2 (~> 2.0)
@@ -575,7 +535,6 @@ DEPENDENCIES
rails-controller-testing (~> 1.0) rails-controller-testing (~> 1.0)
rails-i18n (~> 5.0) rails-i18n (~> 5.0)
rails-settings-cached (~> 0.6) rails-settings-cached (~> 0.6)
rdf-normalize (~> 0.3.1)
redis (~> 3.3) redis (~> 3.3)
redis-namespace (~> 1.5) redis-namespace (~> 1.5)
redis-rails (~> 5.0) redis-rails (~> 5.0)
@@ -600,10 +559,9 @@ DEPENDENCIES
uglifier (~> 3.2) uglifier (~> 3.2)
webmock (~> 3.0) webmock (~> 3.0)
webpacker (~> 2.0) webpacker (~> 2.0)
webpush
RUBY VERSION RUBY VERSION
ruby 2.4.1p111 ruby 2.4.1p111
BUNDLED WITH BUNDLED WITH
1.15.4 1.15.1

View File

@@ -1,70 +1,5 @@
![Mastodon](https://i.imgur.com/NhZc40l.png) Mastodon Glitch Edition
======== ========
Now with automated deploys!
[![Build Status](http://img.shields.io/travis/tootsuite/mastodon.svg)][travis] 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?
[![Code Climate](https://img.shields.io/codeclimate/github/tootsuite/mastodon.svg)][code_climate]
[travis]: https://travis-ci.org/tootsuite/mastodon
[code_climate]: https://codeclimate.com/github/tootsuite/mastodon
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.
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)

7
Vagrantfile vendored
View File

@@ -35,8 +35,6 @@ sudo apt-get install \
postgresql-contrib \ postgresql-contrib \
protobuf-compiler \ protobuf-compiler \
yarn \ yarn \
libicu-dev \
libidn11-dev \
libprotobuf-dev \ libprotobuf-dev \
libreadline-dev \ libreadline-dev \
-y -y
@@ -44,12 +42,9 @@ sudo apt-get install \
# Install rvm # Install rvm
read RUBY_VERSION < .ruby-version read RUBY_VERSION < .ruby-version
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
curl -sSL https://raw.githubusercontent.com/rvm/rvm/stable/binscripts/rvm-installer | bash -s stable --ruby=$RUBY_VERSION curl -sSL https://get.rvm.io | bash -s stable --ruby=$RUBY_VERSION
source /home/vagrant/.rvm/scripts/rvm source /home/vagrant/.rvm/scripts/rvm
# Install Ruby
rvm install ruby-$RUBY_VERSION
# Configure database # Configure database
sudo -u postgres createuser -U postgres vagrant -s sudo -u postgres createuser -U postgres vagrant -s
sudo -u postgres createdb -U postgres mastodon_development sudo -u postgres createdb -U postgres mastodon_development

View File

@@ -2,7 +2,7 @@
"name": "Mastodon", "name": "Mastodon",
"description": "A GNU Social-compatible microblogging server", "description": "A GNU Social-compatible microblogging server",
"repository": "https://github.com/tootsuite/mastodon", "repository": "https://github.com/tootsuite/mastodon",
"logo": "https://github.com/tootsuite.png", "logo": "https://github.com/tootsuite/mastodon/raw/master/app/assets/images/logo.png",
"env": { "env": {
"HEROKU": { "HEROKU": {
"description": "Leave this as true", "description": "Leave this as true",

View File

@@ -2,12 +2,9 @@
class AboutController < ApplicationController class AboutController < ApplicationController
before_action :set_body_classes before_action :set_body_classes
before_action :set_instance_presenter, only: [:show, :more, :terms] before_action :set_instance_presenter, only: [:show, :more]
def show def show; end
serializable_resource = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(initial_state_params), serializer: InitialStateSerializer)
@initial_state_json = serializable_resource.to_json
end
def more; end def more; end
@@ -18,7 +15,6 @@ class AboutController < ApplicationController
def new_user def new_user
User.new.tap(&:build_account) User.new.tap(&:build_account)
end end
helper_method :new_user helper_method :new_user
def set_instance_presenter def set_instance_presenter
@@ -28,11 +24,4 @@ class AboutController < ApplicationController
def set_body_classes def set_body_classes
@body_classes = 'about-body' @body_classes = 'about-body'
end end
def initial_state_params
{
settings: {},
token: current_session&.token,
}
end
end end

View File

@@ -2,79 +2,26 @@
class AccountsController < ApplicationController class AccountsController < ApplicationController
include AccountControllerConcern include AccountControllerConcern
include SignatureVerification
def show def show
respond_to do |format| respond_to do |format|
format.html do format.html do
@pinned_statuses = [] @statuses = @account.statuses.permitted_for(@account, current_account).paginate_by_max_id(20, params[:max_id], params[:since_id])
@statuses = cache_collection(@statuses, Status)
if current_account && @account.blocking?(current_account)
@statuses = []
return
end
@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?
end end
format.atom do format.atom do
@entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id]) @entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id])
render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.to_a)) render xml: AtomSerializer.render(AtomSerializer.new.feed(@account, @entries.to_a))
end end
format.json do format.activitystreams2
render json: @account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
end end
end end
private private
def filtered_statuses
default_statuses.tap do |statuses|
statuses.merge!(only_media_scope) if media_requested?
statuses.merge!(no_replies_scope) unless replies_requested?
end
end
def default_statuses
@account.statuses.where(visibility: [:public, :unlisted])
end
def only_media_scope
Status.where(id: account_media_status_ids)
end
def account_media_status_ids
@account.media_attachments.attached.reorder(nil).select(:status_id).distinct
end
def no_replies_scope
Status.without_replies
end
def set_account def set_account
@account = Account.find_local!(params[:username]) @account = Account.find_local!(params[:username])
end end
def next_url
if media_requested?
short_account_media_url(@account, max_id: @statuses.last.id)
elsif replies_requested?
short_account_with_replies_url(@account, max_id: @statuses.last.id)
else
short_account_url(@account, max_id: @statuses.last.id)
end
end
def media_requested?
request.path.ends_with?('/media')
end
def replies_requested?
request.path.ends_with?('/with_replies')
end
end end

View File

@@ -1,36 +0,0 @@
# frozen_string_literal: true
class ActivityPub::InboxesController < Api::BaseController
include SignatureVerification
before_action :set_account
def create
if signed_request_account
upgrade_account
process_payload
head 201
else
head 202
end
end
private
def set_account
@account = Account.find_local!(params[:account_username]) if params[:account_username]
end
def body
@body ||= request.body.read
end
def upgrade_account
return unless signed_request_account.subscribed?
Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id)
end
def process_payload
ActivityPub::ProcessingWorker.perform_async(signed_request_account.id, body.force_encoding('UTF-8'))
end
end

View File

@@ -1,27 +0,0 @@
# frozen_string_literal: true
class ActivityPub::OutboxesController < Api::BaseController
before_action :set_account
def show
@statuses = @account.statuses.permitted_for(@account, current_account).paginate_by_max_id(20, params[:max_id], params[:since_id])
@statuses = cache_collection(@statuses, Status)
render json: outbox_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
private
def set_account
@account = Account.find_local!(params[:account_username])
end
def outbox_presenter
ActivityPub::CollectionPresenter.new(
id: account_outbox_url(@account),
type: :ordered,
size: @account.statuses_count,
items: @statuses
)
end
end

View File

@@ -17,13 +17,13 @@ module Admin
end end
def unsubscribe def unsubscribe
Pubsubhubbub::UnsubscribeWorker.perform_async(@account.id) UnsubscribeService.new.call(@account)
redirect_to admin_account_path(@account.id) redirect_to admin_account_path(@account.id)
end end
def redownload def redownload
@account.reset_avatar! @account.avatar = @account.avatar_remote_url
@account.reset_header! @account.header = @account.header_remote_url
@account.save! @account.save!
redirect_to admin_account_path(@account.id) redirect_to admin_account_path(@account.id)

View File

@@ -6,26 +6,15 @@ module Admin
@instances = ordered_instances @instances = ordered_instances
end end
def resubscribe
params.require(:by_domain)
Pubsubhubbub::SubscribeWorker.push_bulk(subscribeable_accounts.pluck(:id))
redirect_to admin_instances_path
end
private private
def paginated_instances def paginated_instances
Account.remote.by_domain_accounts.page(params[:page]) Account.remote.by_domain_accounts.page(params[:page])
end end
helper_method :paginated_instances helper_method :paginated_instances
def ordered_instances def ordered_instances
paginated_instances.map { |account| Instance.new(account) } paginated_instances.map { |account| Instance.new(account) }
end end
def subscribeable_accounts
Account.with_followers.remote.where(domain: params[:by_domain])
end
end end
end end

View File

@@ -5,14 +5,7 @@ module Admin
include Authorization include Authorization
before_action :set_report before_action :set_report
before_action :set_status, only: [:update, :destroy] before_action :set_status
def create
@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 def update
@status.update(status_params) @status.update(status_params)
@@ -22,7 +15,7 @@ module Admin
def destroy def destroy
authorize @status, :destroy? authorize @status, :destroy?
RemovalWorker.perform_async(@status.id) RemovalWorker.perform_async(@status.id)
render json: @status redirect_to admin_report_path(@report)
end end
private private
@@ -31,10 +24,6 @@ module Admin
params.require(:status).permit(:sensitive) params.require(:status).permit(:sensitive)
end end
def form_status_batch_params
params.require(:form_status_batch).permit(:action, status_ids: [])
end
def set_report def set_report
@report = Report.find(params[:report_id]) @report = Report.find(params[:report_id])
end end

View File

@@ -8,9 +8,7 @@ module Admin
@reports = filtered_reports.page(params[:page]) @reports = filtered_reports.page(params[:page])
end end
def show def show; end
@form = Form::StatusBatch.new
end
def update def update
process_report process_report

View File

@@ -8,21 +8,13 @@ module Admin
site_title site_title
site_description site_description
site_extended_description site_extended_description
site_terms
open_registrations open_registrations
closed_registrations_message closed_registrations_message
open_deletion
timeline_preview
).freeze
BOOLEAN_SETTINGS = %w(
open_registrations
open_deletion
timeline_preview
).freeze ).freeze
BOOLEAN_SETTINGS = %w(open_registrations).freeze
def edit def edit
@admin_settings = Form::AdminSettings.new @settings = Setting.all_as_records
end end
def update def update
@@ -31,19 +23,19 @@ module Admin
setting.update(value: value_for_update(key, value)) setting.update(value: value_for_update(key, value))
end end
flash[:notice] = I18n.t('generic.changes_saved_msg') flash[:notice] = 'Success!'
redirect_to edit_admin_settings_path redirect_to edit_admin_settings_path
end end
private private
def settings_params def settings_params
params.require(:form_admin_settings).permit(ADMIN_SETTINGS) params.permit(ADMIN_SETTINGS)
end end
def value_for_update(key, value) def value_for_update(key, value)
if BOOLEAN_SETTINGS.include?(key) if BOOLEAN_SETTINGS.include?(key)
value == '1' value == 'true'
else else
value value
end end

View File

@@ -1,69 +0,0 @@
# frozen_string_literal: true
module Admin
class StatusesController < BaseController
include Authorization
helper_method :current_params
before_action :set_account
before_action :set_status, only: [:update, :destroy]
PER_PAGE = 20
def 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
@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
@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)
render json: @status
end
private
def status_params
params.require(:status).permit(:sensitive)
end
def form_status_batch_params
params.require(:form_status_batch).permit(:action, status_ids: [])
end
def set_status
@status = @account.statuses.find(params[:id])
end
def set_account
@account = Account.find(params[:account_id])
end
def current_params
page = (params[:page] || 1).to_i
{
media: params[:media],
page: page > 1 && page,
}.select { |_, value| value.present? }
end
end
end

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
class Api::ActivityPub::ActivitiesController < Api::BaseController
include Authorization
# before_action :set_follow, only: [:show_follow]
before_action :set_status, only: [:show_status]
respond_to :activitystreams2
# Show a status in AS2 format, as either an Announce (reblog) or a Create (post) activity.
def show_status
authorize @status, :show?
if @status.reblog?
render :show_status_announce
else
render :show_status_create
end
end
private
def set_status
@status = Status.find(params[:id])
end
end

View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
class Api::ActivityPub::NotesController < Api::BaseController
include Authorization
before_action :set_status
respond_to :activitystreams2
def show
authorize @status, :show?
end
private
def set_status
@status = Status.find(params[:id])
end
end

View File

@@ -0,0 +1,69 @@
# frozen_string_literal: true
class Api::ActivityPub::OutboxController < Api::BaseController
before_action :set_account
respond_to :activitystreams2
def show
if params[:max_id] || params[:since_id]
show_outbox_page
else
show_base_outbox
end
end
private
def show_base_outbox
@statuses = Status.as_outbox_timeline(@account)
@statuses = cache_collection(@statuses)
set_maps(@statuses)
set_first_last_page(@statuses)
render :show
end
def show_outbox_page
all_statuses = Status.as_outbox_timeline(@account)
@statuses = all_statuses.paginate_by_max_id(limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], params[:since_id])
all_statuses = cache_collection(all_statuses)
@statuses = cache_collection(@statuses)
set_maps(@statuses)
set_first_last_page(all_statuses)
@next_page_url = api_activitypub_outbox_url(pagination_params(max_id: @statuses.last.id)) unless @statuses.empty?
@prev_page_url = api_activitypub_outbox_url(pagination_params(since_id: @statuses.first.id)) unless @statuses.empty?
@paginated = @next_page_url || @prev_page_url
@part_of_url = api_activitypub_outbox_url
set_pagination_headers(@next_page_url, @prev_page_url)
render :show_page
end
def cache_collection(raw)
super(raw, Status)
end
def set_account
@account = Account.find(params[:id])
end
def set_first_last_page(statuses) # rubocop:disable Style/AccessorMethodName
return if statuses.empty?
@first_page_url = api_activitypub_outbox_url(max_id: statuses.first.id + 1)
@last_page_url = api_activitypub_outbox_url(since_id: statuses.last.id - 1)
end
def pagination_params(core_params)
params.permit(:local, :limit).merge(core_params)
end
end

View File

@@ -17,7 +17,11 @@ class Api::BaseController < ApplicationController
render json: { error: 'Record not found' }, status: 404 render json: { error: 'Record not found' }, status: 404
end end
rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do rescue_from Goldfinger::Error do
render json: { error: 'Remote account could not be resolved' }, status: 422
end
rescue_from HTTP::Error do
render json: { error: 'Remote data could not be fetched' }, status: 503 render json: { error: 'Remote data could not be fetched' }, status: 503
end end
@@ -43,7 +47,7 @@ class Api::BaseController < ApplicationController
links = [] links = []
links << [next_path, [%w(rel next)]] if next_path links << [next_path, [%w(rel next)]] if next_path
links << [prev_path, [%w(rel prev)]] if prev_path links << [prev_path, [%w(rel prev)]] if prev_path
response.headers['Link'] = LinkHeader.new(links) unless links.empty? response.headers['Link'] = LinkHeader.new(links)
end end
def limit_param(default_limit) def limit_param(default_limit)
@@ -62,11 +66,10 @@ class Api::BaseController < ApplicationController
end end
def require_user! def require_user!
if current_user current_resource_owner
set_user_activity set_user_activity
else rescue ActiveRecord::RecordNotFound
render json: { error: 'This method requires an authenticated user' }, status: 422 render json: { error: 'This method requires an authenticated user' }, status: 422
end
end end
def render_empty def render_empty

View File

@@ -4,14 +4,15 @@ class Api::OEmbedController < Api::BaseController
respond_to :json respond_to :json
def show def show
@status = status_finder.status @stream_entry = find_stream_entry.stream_entry
render json: @status, serializer: OEmbedSerializer, width: maxwidth_or_default, height: maxheight_or_default @width = maxwidth_or_default
@height = maxheight_or_default
end end
private private
def status_finder def find_stream_entry
StatusFinder.new(params[:url]) StreamEntryFinder.new(params[:url])
end end
def maxwidth_or_default def maxwidth_or_default

View File

@@ -1,8 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::PushController < Api::BaseController class Api::PushController < Api::BaseController
include SignatureVerification
def update def update
response, status = process_push_request response, status = process_push_request
render plain: response, status: status render plain: response, status: status
@@ -13,7 +11,7 @@ class Api::PushController < Api::BaseController
def process_push_request def process_push_request
case hub_mode case hub_mode
when 'subscribe' when 'subscribe'
Pubsubhubbub::SubscribeService.new.call(account_from_topic, hub_callback, hub_secret, hub_lease_seconds, verified_domain) Pubsubhubbub::SubscribeService.new.call(account_from_topic, hub_callback, hub_secret, hub_lease_seconds)
when 'unsubscribe' when 'unsubscribe'
Pubsubhubbub::UnsubscribeService.new.call(account_from_topic, hub_callback) Pubsubhubbub::UnsubscribeService.new.call(account_from_topic, hub_callback)
else else
@@ -59,10 +57,6 @@ class Api::PushController < Api::BaseController
TagManager.instance.web_domain?(hub_topic_domain) TagManager.instance.web_domain?(hub_topic_domain)
end end
def verified_domain
return signed_request_account.domain if signed_request_account
end
def hub_topic_domain def hub_topic_domain
hub_topic_uri.host + (hub_topic_uri.port ? ":#{hub_topic_uri.port}" : '') hub_topic_uri.host + (hub_topic_uri.port ? ":#{hub_topic_uri.port}" : '')
end end

View File

@@ -42,7 +42,7 @@ class Api::SubscriptionsController < Api::BaseController
end end
def lease_seconds_or_default def lease_seconds_or_default
(params['hub.lease_seconds'] || 1.day).to_i.seconds (params['hub.lease_seconds'] || 86_400).to_i.seconds
end end
def set_account def set_account

View File

@@ -1,20 +1,18 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::Accounts::CredentialsController < Api::BaseController class Api::V1::Accounts::CredentialsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }, except: [:update]
before_action -> { doorkeeper_authorize! :write }, only: [:update] before_action -> { doorkeeper_authorize! :write }, only: [:update]
before_action :require_user! before_action :require_user!
def show def show
@account = current_account @account = current_account
render json: @account, serializer: REST::CredentialAccountSerializer render 'api/v1/accounts/show'
end end
def update def update
current_account.update!(account_params)
@account = current_account @account = current_account
UpdateAccountService.new.call(@account, account_params, raise_error: true) render 'api/v1/accounts/show'
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
render json: @account, serializer: REST::CredentialAccountSerializer
end end
private private

View File

@@ -9,7 +9,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
def index def index
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer render 'api/v1/accounts/index'
end end
private private

View File

@@ -9,7 +9,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
def index def index
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer render 'api/v1/accounts/index'
end end
private private

View File

@@ -8,15 +8,16 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController
def index def index
@accounts = Account.where(id: account_ids).select('id') @accounts = Account.where(id: account_ids).select('id')
render json: @accounts, each_serializer: REST::RelationshipSerializer, relationships: relationships @following = Account.following_map(account_ids, current_user.account_id)
@followed_by = Account.followed_by_map(account_ids, current_user.account_id)
@blocking = Account.blocking_map(account_ids, current_user.account_id)
@muting = Account.muting_map(account_ids, current_user.account_id)
@requested = Account.requested_map(account_ids, current_user.account_id)
@domain_blocking = Account.domain_blocking_map(account_ids, current_user.account_id)
end end
private private
def relationships
AccountRelationshipsPresenter.new(@accounts, current_user.account_id)
end
def account_ids def account_ids
@_account_ids ||= Array(params[:id]).map(&:to_i) @_account_ids ||= Array(params[:id]).map(&:to_i)
end end

View File

@@ -8,7 +8,8 @@ class Api::V1::Accounts::SearchController < Api::BaseController
def show def show
@accounts = account_search @accounts = account_search
render json: @accounts, each_serializer: REST::AccountSerializer
render 'api/v1/accounts/index'
end end
private private

View File

@@ -9,7 +9,6 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
def index def index
@statuses = load_statuses @statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
end end
private private
@@ -19,7 +18,9 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
end end
def load_statuses def load_statuses
cached_account_statuses cached_account_statuses.tap do |statuses|
set_maps(statuses)
end
end end
def cached_account_statuses def cached_account_statuses
@@ -29,7 +30,6 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
def account_statuses def account_statuses
default_statuses.tap do |statuses| default_statuses.tap do |statuses|
statuses.merge!(only_media_scope) if params[:only_media] statuses.merge!(only_media_scope) if params[:only_media]
statuses.merge!(pinned_scope) if params[:pinned]
statuses.merge!(no_replies_scope) if params[:exclude_replies] statuses.merge!(no_replies_scope) if params[:exclude_replies]
end end
end end
@@ -54,10 +54,6 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
@account.media_attachments.attached.reorder(nil).select(:status_id).distinct @account.media_attachments.attached.reorder(nil).select(:status_id).distinct
end end
def pinned_scope
@account.pinned_statuses
end
def no_replies_scope def no_replies_scope
Status.without_replies Status.without_replies
end end

View File

@@ -8,38 +8,49 @@ class Api::V1::AccountsController < Api::BaseController
respond_to :json respond_to :json
def show def show; end
render json: @account, serializer: REST::AccountSerializer
end
def follow def follow
FollowService.new.call(current_user.account, @account.acct) FollowService.new.call(current_user.account, @account.acct)
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships set_relationship
render :relationship
end end
def block def block
BlockService.new.call(current_user.account, @account) BlockService.new.call(current_user.account, @account)
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
@following = { @account.id => false }
@followed_by = { @account.id => false }
@blocking = { @account.id => true }
@requested = { @account.id => false }
@muting = { @account.id => current_account.muting?(@account.id) }
@domain_blocking = { @account.id => current_account.domain_blocking?(@account.domain) }
render :relationship
end end
def mute def mute
MuteService.new.call(current_user.account, @account) MuteService.new.call(current_user.account, @account)
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships set_relationship
render :relationship
end end
def unfollow def unfollow
UnfollowService.new.call(current_user.account, @account) UnfollowService.new.call(current_user.account, @account)
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships set_relationship
render :relationship
end end
def unblock def unblock
UnblockService.new.call(current_user.account, @account) UnblockService.new.call(current_user.account, @account)
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships set_relationship
render :relationship
end end
def unmute def unmute
UnmuteService.new.call(current_user.account, @account) UnmuteService.new.call(current_user.account, @account)
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships set_relationship
render :relationship
end end
private private
@@ -48,7 +59,12 @@ class Api::V1::AccountsController < Api::BaseController
@account = Account.find(params[:id]) @account = Account.find(params[:id])
end end
def relationships def set_relationship
AccountRelationshipsPresenter.new([@account.id], current_user.account_id) @following = Account.following_map([@account.id], current_user.account_id)
@followed_by = Account.followed_by_map([@account.id], current_user.account_id)
@blocking = Account.blocking_map([@account.id], current_user.account_id)
@muting = Account.muting_map([@account.id], current_user.account_id)
@requested = Account.requested_map([@account.id], current_user.account_id)
@domain_blocking = Account.domain_blocking_map([@account.id], current_user.account_id)
end end
end end

View File

@@ -5,7 +5,6 @@ class Api::V1::AppsController < Api::BaseController
def create def create
@app = Doorkeeper::Application.create!(application_options) @app = Doorkeeper::Application.create!(application_options)
render json: @app, serializer: REST::ApplicationSerializer
end end
private private

View File

@@ -9,7 +9,6 @@ class Api::V1::BlocksController < Api::BaseController
def index def index
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer
end end
private private

View File

@@ -9,18 +9,21 @@ class Api::V1::FavouritesController < Api::BaseController
def index def index
@statuses = load_statuses @statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
end end
private private
def load_statuses def load_statuses
cached_favourites cached_favourites.tap do |statuses|
set_maps(statuses)
end
end end
def cached_favourites def cached_favourites
cache_collection( cache_collection(
Status.reorder(nil).joins(:favourites).merge(results), Status.where(
id: results.map(&:status_id)
),
Status Status
) )
end end

View File

@@ -7,7 +7,6 @@ class Api::V1::FollowRequestsController < Api::BaseController
def index def index
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer
end end
def authorize def authorize

View File

@@ -10,7 +10,7 @@ class Api::V1::FollowsController < Api::BaseController
raise ActiveRecord::RecordNotFound if follow_params[:uri].blank? raise ActiveRecord::RecordNotFound if follow_params[:uri].blank?
@account = FollowService.new.call(current_user.account, target_uri).try(:target_account) @account = FollowService.new.call(current_user.account, target_uri).try(:target_account)
render json: @account, serializer: REST::AccountSerializer render :show
end end
private private

View File

@@ -3,7 +3,5 @@
class Api::V1::InstancesController < Api::BaseController class Api::V1::InstancesController < Api::BaseController
respond_to :json respond_to :json
def show def show; end
render json: {}, serializer: REST::InstanceSerializer
end
end end

View File

@@ -11,7 +11,6 @@ class Api::V1::MediaController < Api::BaseController
def create def create
@media = current_account.media_attachments.create!(file: media_params[:file]) @media = current_account.media_attachments.create!(file: media_params[:file])
render json: @media, serializer: REST::MediaAttachmentSerializer
rescue Paperclip::Errors::NotIdentifiedByImageMagickError rescue Paperclip::Errors::NotIdentifiedByImageMagickError
render json: file_type_error, status: 422 render json: file_type_error, status: 422
rescue Paperclip::Error rescue Paperclip::Error

View File

@@ -9,7 +9,6 @@ class Api::V1::MutesController < Api::BaseController
def index def index
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer
end end
private private

View File

@@ -11,12 +11,11 @@ class Api::V1::NotificationsController < Api::BaseController
def index def index
@notifications = load_notifications @notifications = load_notifications
render json: @notifications, each_serializer: REST::NotificationSerializer, relationships: StatusRelationshipsPresenter.new(target_statuses_from_notifications, current_user&.account_id) set_maps_for_notification_target_statuses
end end
def show def show
@notification = current_account.notifications.find(params[:id]) @notification = current_account.notifications.find(params[:id])
render json: @notification, serializer: REST::NotificationSerializer
end end
def clear def clear
@@ -47,6 +46,10 @@ class Api::V1::NotificationsController < Api::BaseController
current_account.notifications.browserable(exclude_types) current_account.notifications.browserable(exclude_types)
end end
def set_maps_for_notification_target_statuses
set_maps target_statuses_from_notifications
end
def target_statuses_from_notifications def target_statuses_from_notifications
@notifications.reject { |notification| notification.target_status.nil? }.map(&:target_status) @notifications.reject { |notification| notification.target_status.nil? }.map(&:target_status)
end end

View File

@@ -9,7 +9,6 @@ class Api::V1::ReportsController < Api::BaseController
def index def index
@reports = current_account.reports @reports = current_account.reports
render json: @reports, each_serializer: REST::ReportSerializer
end end
def create def create
@@ -18,10 +17,7 @@ class Api::V1::ReportsController < Api::BaseController
status_ids: reported_status_ids, status_ids: reported_status_ids,
comment: report_params[:comment] comment: report_params[:comment]
) )
render :show
User.admins.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later }
render json: @report, serializer: REST::ReportSerializer
end end
private private

View File

@@ -3,14 +3,10 @@
class Api::V1::SearchController < Api::BaseController class Api::V1::SearchController < Api::BaseController
RESULTS_LIMIT = 5 RESULTS_LIMIT = 5
before_action -> { doorkeeper_authorize! :read }
before_action :require_user!
respond_to :json respond_to :json
def index def index
@search = Search.new(search_results) @search = OpenStruct.new(search_results)
render json: @search, serializer: REST::SearchSerializer
end end
private private

View File

@@ -11,7 +11,7 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
def index def index
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer render 'api/v1/statuses/accounts'
end end
private private

View File

@@ -10,7 +10,7 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController
def create def create
@status = favourited_status @status = favourited_status
render json: @status, serializer: REST::StatusSerializer render 'api/v1/statuses/show'
end end
def destroy def destroy
@@ -19,7 +19,7 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController
UnfavouriteWorker.perform_async(current_user.account_id, @status.id) UnfavouriteWorker.perform_async(current_user.account_id, @status.id)
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_user&.account_id, favourites_map: @favourites_map) render 'api/v1/statuses/show'
end end
private private

View File

@@ -14,14 +14,14 @@ class Api::V1::Statuses::MutesController < Api::BaseController
current_account.mute_conversation!(@conversation) current_account.mute_conversation!(@conversation)
@mutes_map = { @conversation.id => true } @mutes_map = { @conversation.id => true }
render json: @status, serializer: REST::StatusSerializer render 'api/v1/statuses/show'
end end
def destroy def destroy
current_account.unmute_conversation!(@conversation) current_account.unmute_conversation!(@conversation)
@mutes_map = { @conversation.id => false } @mutes_map = { @conversation.id => false }
render json: @status, serializer: REST::StatusSerializer render 'api/v1/statuses/show'
end end
private private

View File

@@ -1,28 +0,0 @@
# frozen_string_literal: true
class Api::V1::Statuses::PinsController < Api::BaseController
include Authorization
before_action -> { doorkeeper_authorize! :write }
before_action :require_user!
before_action :set_status
respond_to :json
def create
StatusPin.create!(account: current_account, status: @status)
render json: @status, serializer: REST::StatusSerializer
end
def destroy
pin = StatusPin.find_by(account: current_account, status: @status)
pin&.destroy!
render json: @status, serializer: REST::StatusSerializer
end
private
def set_status
@status = Status.find(params[:status_id])
end
end

View File

@@ -11,7 +11,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
def index def index
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer render 'api/v1/statuses/accounts'
end end
private private

View File

@@ -10,7 +10,7 @@ class Api::V1::Statuses::ReblogsController < Api::BaseController
def create def create
@status = ReblogService.new.call(current_user.account, status_for_reblog) @status = ReblogService.new.call(current_user.account, status_for_reblog)
render json: @status, serializer: REST::StatusSerializer render 'api/v1/statuses/show'
end end
def destroy def destroy
@@ -20,7 +20,7 @@ class Api::V1::Statuses::ReblogsController < Api::BaseController
authorize status_for_destroy, :unreblog? authorize status_for_destroy, :unreblog?
RemovalWorker.perform_async(status_for_destroy.id) RemovalWorker.perform_async(status_for_destroy.id)
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_user&.account_id, reblogs_map: @reblogs_map) render 'api/v1/statuses/show'
end end
private private

View File

@@ -13,7 +13,6 @@ class Api::V1::StatusesController < Api::BaseController
def show def show
cached = Rails.cache.read(@status.cache_key) cached = Rails.cache.read(@status.cache_key)
@status = cached unless cached.nil? @status = cached unless cached.nil?
render json: @status, serializer: REST::StatusSerializer
end end
def context def context
@@ -22,20 +21,15 @@ class Api::V1::StatusesController < Api::BaseController
loaded_ancestors = cache_collection(ancestors_results, Status) loaded_ancestors = cache_collection(ancestors_results, Status)
loaded_descendants = cache_collection(descendants_results, Status) loaded_descendants = cache_collection(descendants_results, Status)
@context = Context.new(ancestors: loaded_ancestors, descendants: loaded_descendants) @context = OpenStruct.new(ancestors: loaded_ancestors, descendants: loaded_descendants)
statuses = [@status] + @context.ancestors + @context.descendants statuses = [@status] + @context[:ancestors] + @context[:descendants]
render json: @context, serializer: REST::ContextSerializer, relationships: StatusRelationshipsPresenter.new(statuses, current_user&.account_id) set_maps(statuses)
end end
def card def card
@card = @status.preview_cards.first @card = PreviewCard.find_by(status: @status)
render_empty if @card.nil?
if @card.nil?
render_empty
else
render json: @card, serializer: REST::PreviewCardSerializer
end
end end
def create def create
@@ -49,7 +43,7 @@ class Api::V1::StatusesController < Api::BaseController
application: doorkeeper_token.application, application: doorkeeper_token.application,
idempotency: request.headers['Idempotency-Key']) idempotency: request.headers['Idempotency-Key'])
render json: @status, serializer: REST::StatusSerializer render :show
end end
def destroy def destroy

View File

@@ -9,13 +9,15 @@ class Api::V1::Timelines::HomeController < Api::BaseController
def show def show
@statuses = load_statuses @statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) render 'api/v1/timelines/show'
end end
private private
def load_statuses def load_statuses
cached_home_statuses cached_home_statuses.tap do |statuses|
set_maps(statuses)
end
end end
def cached_home_statuses def cached_home_statuses

View File

@@ -7,13 +7,15 @@ class Api::V1::Timelines::PublicController < Api::BaseController
def show def show
@statuses = load_statuses @statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) render 'api/v1/timelines/show'
end end
private private
def load_statuses def load_statuses
cached_public_statuses cached_public_statuses.tap do |statuses|
set_maps(statuses)
end
end end
def cached_public_statuses def cached_public_statuses

View File

@@ -8,7 +8,7 @@ class Api::V1::Timelines::TagController < Api::BaseController
def show def show
@statuses = load_statuses @statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) render 'api/v1/timelines/show'
end end
private private
@@ -18,7 +18,9 @@ class Api::V1::Timelines::TagController < Api::BaseController
end end
def load_statuses def load_statuses
cached_tagged_statuses cached_tagged_statuses.tap do |statuses|
set_maps(statuses)
end
end end
def cached_tagged_statuses def cached_tagged_statuses

View File

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

View File

@@ -1,52 +0,0 @@
# frozen_string_literal: true
class Api::Web::PushSubscriptionsController < Api::BaseController
respond_to :json
before_action :require_user!
def create
params.require(:subscription).require(:endpoint)
params.require(:subscription).require(:keys).require([:auth, :p256dh])
active_session = current_session
unless active_session.web_push_subscription.nil?
active_session.web_push_subscription.destroy!
active_session.update!(web_push_subscription: nil)
end
# Mobile devices do not support regular notifications, so we enable push notifications by default
alerts_enabled = active_session.detection.device.mobile? || active_session.detection.device.tablet?
data = {
alerts: {
follow: alerts_enabled,
favourite: alerts_enabled,
reblog: alerts_enabled,
mention: alerts_enabled,
},
}
web_subscription = ::Web::PushSubscription.create!(
endpoint: params[:subscription][:endpoint],
key_p256dh: params[:subscription][:keys][:p256dh],
key_auth: params[:subscription][:keys][:auth],
data: data
)
active_session.update!(web_push_subscription: web_subscription)
render json: web_subscription.as_payload
end
def update
params.require([:id, :data])
web_subscription = ::Web::PushSubscription.find(params[:id])
web_subscription.update!(data: params[:data])
render json: web_subscription.as_payload
end
end

View File

@@ -11,7 +11,6 @@ class ApplicationController < ActionController::Base
include UserTrackingConcern include UserTrackingConcern
helper_method :current_account helper_method :current_account
helper_method :current_session
helper_method :single_user_mode? helper_method :single_user_mode?
rescue_from ActionController::RoutingError, with: :not_found rescue_from ActionController::RoutingError, with: :not_found
@@ -43,10 +42,6 @@ class ApplicationController < ActionController::Base
forbidden if current_user.account.suspended? forbidden if current_user.account.suspended?
end end
def after_sign_out_path_for(_resource_or_scope)
new_user_session_path
end
protected protected
def forbidden def forbidden
@@ -73,10 +68,6 @@ class ApplicationController < ActionController::Base
@current_account ||= current_user.try(:account) @current_account ||= current_user.try(:account)
end end
def current_session
@current_session ||= SessionActivation.find_by(session_id: cookies.signed['_session_id'])
end
def cache_collection(raw, klass) def cache_collection(raw, klass)
return raw unless klass.respond_to?(:with_includes) return raw unless klass.respond_to?(:with_includes)

View File

@@ -1,20 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
class Auth::PasswordsController < Devise::PasswordsController class Auth::PasswordsController < Devise::PasswordsController
before_action :check_validity_of_reset_password_token, only: :edit
layout 'auth' layout 'auth'
private
def check_validity_of_reset_password_token
unless reset_password_token_is_valid?
flash[:error] = I18n.t('auth.invalid_reset_password_token')
redirect_to new_password_path(resource_name)
end
end
def reset_password_token_is_valid?
resource_class.with_reset_password_token(params[:reset_password_token]).present?
end
end end

View File

@@ -5,7 +5,6 @@ class Auth::RegistrationsController < Devise::RegistrationsController
before_action :check_enabled_registrations, only: [:new, :create] before_action :check_enabled_registrations, only: [:new, :create]
before_action :configure_sign_up_params, only: [:create] before_action :configure_sign_up_params, only: [:create]
before_action :set_sessions, only: [:edit, :update]
def destroy def destroy
not_found not_found
@@ -42,8 +41,4 @@ class Auth::RegistrationsController < Devise::RegistrationsController
def determine_layout def determine_layout
%w(edit update).include?(action_name) ? 'admin' : 'auth' %w(edit update).include?(action_name) ? 'admin' : 'auth'
end end
def set_sessions
@sessions = current_user.session_activations
end
end end

View File

@@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class AuthorizeFollowsController < ApplicationController class AuthorizeFollowsController < ApplicationController
layout 'modal' layout 'public'
before_action :authenticate_user! before_action :authenticate_user!
@@ -15,7 +15,7 @@ class AuthorizeFollowsController < ApplicationController
if @account.nil? if @account.nil?
render :error render :error
else else
render :success redirect_to web_url("accounts/#{@account.id}")
end end
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
render :error render :error

View File

@@ -23,7 +23,6 @@ module AccountControllerConcern
[ [
webfinger_account_link, webfinger_account_link,
atom_account_url_link, atom_account_url_link,
actor_url_link,
] ]
) )
end end
@@ -42,13 +41,6 @@ module AccountControllerConcern
] ]
end end
def actor_url_link
[
ActivityPub::TagManager.instance.uri_for(@account),
[%w(rel alternate), %w(type application/activity+json)],
]
end
def webfinger_account_url def webfinger_account_url
webfinger_url(resource: @account.to_webfinger_s) webfinger_url(resource: @account.to_webfinger_s)
end end

View File

@@ -1,106 +0,0 @@
# frozen_string_literal: true
# Implemented according to HTTP signatures (Draft 6)
# <https://tools.ietf.org/html/draft-cavage-http-signatures-06>
module SignatureVerification
extend ActiveSupport::Concern
def signed_request?
request.headers['Signature'].present?
end
def signed_request_account
return @signed_request_account if defined?(@signed_request_account)
unless signed_request?
@signed_request_account = nil
return
end
raw_signature = request.headers['Signature']
signature_params = {}
raw_signature.split(',').each do |part|
parsed_parts = part.match(/([a-z]+)="([^"]+)"/i)
next if parsed_parts.nil? || parsed_parts.size != 3
signature_params[parsed_parts[1]] = parsed_parts[2]
end
if incompatible_signature?(signature_params)
@signed_request_account = nil
return
end
account = account_from_key_id(signature_params['keyId'])
if account.nil?
@signed_request_account = nil
return
end
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
else
@signed_request_account = nil
end
end
def request_body
@request_body ||= request.raw_post
end
private
def build_signed_string(signed_headers)
signed_headers = 'date' if signed_headers.blank?
signed_headers.split(' ').map do |signed_header|
if signed_header == Request::REQUEST_TARGET
"#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}"
elsif signed_header == 'digest'
"digest: #{body_digest}"
else
"#{signed_header}: #{request.headers[to_header_name(signed_header)]}"
end
end.join("\n")
end
def matches_time_window?
begin
time_sent = DateTime.httpdate(request.headers['Date'])
rescue ArgumentError
return false
end
(Time.now.utc - time_sent).abs <= 30
end
def body_digest
"SHA-256=#{Digest::SHA256.base64digest(request_body)}"
end
def to_header_name(name)
name.split(/-/).map(&:capitalize).join('-')
end
def incompatible_signature?(signature_params)
signature_params['keyId'].blank? ||
signature_params['signature'].blank? ||
signature_params['algorithm'].blank? ||
signature_params['algorithm'] != 'rsa-sha256'
end
def account_from_key_id(key_id)
if key_id.start_with?('acct:')
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)
account
end
end
end

View File

@@ -5,24 +5,5 @@ class FollowerAccountsController < ApplicationController
def index def index
@follows = Follow.where(target_account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account) @follows = Follow.where(target_account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account)
respond_to do |format|
format.html
format.json do
render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
end
end
private
def collection_presenter
ActivityPub::CollectionPresenter.new(
id: account_followers_url(@account),
type: :ordered,
size: @account.followers_count,
items: @follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) }
)
end end
end end

View File

@@ -5,24 +5,5 @@ class FollowingAccountsController < ApplicationController
def index def index
@follows = Follow.where(account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account) @follows = Follow.where(account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account)
respond_to do |format|
format.html
format.json do
render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
end
end
private
def collection_presenter
ActivityPub::CollectionPresenter.new(
id: account_following_index_url(@account),
type: :ordered,
size: @account.following_count,
items: @follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) }
)
end end
end end

View File

@@ -2,10 +2,14 @@
class HomeController < ApplicationController class HomeController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action :set_initial_state_json
def index def index
@body_classes = 'app-body' @body_classes = 'app-body'
@token = find_or_create_access_token.token
@web_settings = Web::Setting.find_by(user: current_user)&.data || {}
@admin = Account.find_local(Setting.site_contact_username)
@streaming_api_base_url = Rails.configuration.x.streaming_api_base_url
@frontend = (params[:frontend] and Rails.configuration.x.available_frontends.include? params[:frontend] + '.js') ? params[:frontend] : 'mastodon'
end end
private private
@@ -14,18 +18,13 @@ class HomeController < ApplicationController
redirect_to(single_user_mode? ? account_path(Account.first) : about_path) unless user_signed_in? redirect_to(single_user_mode? ? account_path(Account.first) : about_path) unless user_signed_in?
end end
def set_initial_state_json def find_or_create_access_token
serializable_resource = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(initial_state_params), serializer: InitialStateSerializer) Doorkeeper::AccessToken.find_or_create_for(
@initial_state_json = serializable_resource.to_json Doorkeeper::Application.where(superapp: true).first,
end current_user.id,
Doorkeeper::OAuth::Scopes.from_string('read write follow'),
def initial_state_params Doorkeeper.configuration.access_token_expires_in,
{ Doorkeeper.configuration.refresh_token_enabled?
settings: Web::Setting.find_by(user: current_user)&.data || {}, )
push_subscription: current_account.user.web_push_subscription(current_session),
current_account: current_account,
token: current_session.token,
admin: Account.find_local(Setting.site_contact_username),
}
end end
end end

View File

@@ -1,18 +0,0 @@
# frozen_string_literal: true
class IntentsController < ApplicationController
def show
uri = Addressable::URI.parse(params[:uri])
if uri.scheme == 'web+mastodon'
case uri.host
when 'follow'
return redirect_to authorize_follow_path(acct: uri.query_values['uri'].gsub(/\Aacct:/, ''))
when 'share'
return redirect_to share_path(text: uri.query_values['text'])
end
end
not_found
end
end

View File

@@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class RemoteFollowController < ApplicationController class RemoteFollowController < ApplicationController
layout 'modal' layout 'public'
before_action :set_account before_action :set_account
before_action :gone, if: :suspended_account? before_action :gone, if: :suspended_account?

View File

@@ -1,72 +0,0 @@
# frozen_string_literal: true
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]
def index
@applications = current_user.applications.page(params[:page])
end
def new
@application = Doorkeeper::Application.new(
redirect_uri: Doorkeeper.configuration.native_redirect_uri,
scopes: 'read write follow'
)
end
def show; end
def create
@application = current_user.applications.build(application_params)
if @application.save
redirect_to settings_applications_path, notice: I18n.t('applications.created')
else
render :new
end
end
def update
if @application.update(application_params)
redirect_to settings_applications_path, notice: I18n.t('generic.changes_saved_msg')
else
render :show
end
end
def destroy
@application.destroy
redirect_to settings_applications_path, notice: I18n.t('applications.destroyed')
end
def regenerate
@access_token = current_user.token_for_app(@application)
@access_token.destroy
redirect_to settings_application_path(@application), notice: I18n.t('applications.token_regenerated')
end
private
def set_application
@application = current_user.applications.find(params[:id])
end
def application_params
params.require(:doorkeeper_application).permit(
:name,
:redirect_uri,
:scopes,
:website
)
end
def prepare_scopes
scopes = params.fetch(:doorkeeper_application, {}).fetch(:scopes, nil)
params[:doorkeeper_application][:scopes] = scopes.join(' ') if scopes.is_a? Array
end
end

View File

@@ -34,13 +34,9 @@ class Settings::PreferencesController < ApplicationController
def user_settings_params def user_settings_params
params.require(:user).permit( params.require(:user).permit(
:setting_default_privacy, :setting_default_privacy,
:setting_default_sensitive,
:setting_unfollow_modal,
:setting_boost_modal, :setting_boost_modal,
:setting_delete_modal, :setting_delete_modal,
:setting_auto_play_gif, :setting_auto_play_gif,
:setting_system_font_ui,
:setting_noindex,
notification_emails: %i(follow follow_request reblog favourite mention digest), notification_emails: %i(follow follow_request reblog favourite mention digest),
interactions: %i(must_be_follower must_be_following) interactions: %i(must_be_follower must_be_following)
) )

View File

@@ -14,8 +14,7 @@ class Settings::ProfilesController < ApplicationController
def show; end def show; end
def update def update
if UpdateAccountService.new.call(@account, account_params) if @account.update(account_params)
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
redirect_to settings_profile_path, notice: I18n.t('generic.changes_saved_msg') redirect_to settings_profile_path, notice: I18n.t('generic.changes_saved_msg')
else else
render :show render :show

View File

@@ -1,17 +0,0 @@
# frozen_string_literal: true
class Settings::SessionsController < ApplicationController
before_action :set_session, only: :destroy
def destroy
@session.destroy!
flash[:notice] = I18n.t('sessions.revoke_success')
redirect_to edit_user_registration_path
end
private
def set_session
@session = current_user.session_activations.find(params[:id])
end
end

View File

@@ -7,9 +7,7 @@ module Settings
before_action :authenticate_user! before_action :authenticate_user!
before_action :verify_otp_required, only: [:create] before_action :verify_otp_required, only: [:create]
def show def show; end
@confirmation = Form::TwoFactorConfirmation.new
end
def create def create
current_user.otp_secret = User.generate_otp_secret(32) current_user.otp_secret = User.generate_otp_secret(32)
@@ -18,30 +16,15 @@ module Settings
end end
def destroy def destroy
if acceptable_code? current_user.otp_required_for_login = false
current_user.otp_required_for_login = false current_user.save!
current_user.save! redirect_to settings_two_factor_authentication_path
redirect_to settings_two_factor_authentication_path
else
flash.now[:alert] = I18n.t('two_factor_authentication.wrong_code')
@confirmation = Form::TwoFactorConfirmation.new
render :show
end
end end
private private
def confirmation_params
params.require(:form_two_factor_confirmation).permit(:code)
end
def verify_otp_required def verify_otp_required
redirect_to settings_two_factor_authentication_path if current_user.otp_required_for_login? redirect_to settings_two_factor_authentication_path if current_user.otp_required_for_login?
end end
def acceptable_code?
current_user.validate_and_consume_otp!(confirmation_params[:code]) ||
current_user.invalidate_otp_backup_code!(confirmation_params[:code])
end
end end
end end

View File

@@ -1,30 +0,0 @@
# frozen_string_literal: true
class SharesController < ApplicationController
layout 'modal'
before_action :authenticate_user!
before_action :set_body_classes
def show
serializable_resource = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(initial_state_params), serializer: InitialStateSerializer)
@initial_state_json = serializable_resource.to_json
end
private
def initial_state_params
{
settings: Web::Setting.find_by(user: current_user)&.data || {},
push_subscription: current_account.user.web_push_subscription(current_session),
current_account: current_account,
token: current_session.token,
admin: Account.find_local(Setting.site_contact_username),
text: params[:text],
}
end
def set_body_classes
@body_classes = 'compose-standalone'
end
end

View File

@@ -9,30 +9,12 @@ class StatusesController < ApplicationController
before_action :set_status before_action :set_status
before_action :set_link_headers before_action :set_link_headers
before_action :check_account_suspension before_action :check_account_suspension
before_action :redirect_to_original, only: [:show]
def show def show
respond_to do |format| @ancestors = @status.reply? ? cache_collection(@status.ancestors(current_account), Status) : []
format.html do @descendants = cache_collection(@status.descendants(current_account), Status)
@ancestors = @status.reply? ? cache_collection(@status.ancestors(current_account), Status) : []
@descendants = cache_collection(@status.descendants(current_account), Status)
render 'stream_entries/show' render 'stream_entries/show'
end
format.json do
render json: @status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
end
end
def activity
render json: @status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
def embed
response.headers['X-Frame-Options'] = 'ALLOWALL'
render 'stream_entries/embed', layout: 'embedded'
end end
private private
@@ -42,12 +24,7 @@ class StatusesController < ApplicationController
end end
def set_link_headers def set_link_headers
response.headers['Link'] = LinkHeader.new( response.headers['Link'] = LinkHeader.new([[account_stream_entry_url(@account, @status.stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]]])
[
[account_stream_entry_url(@account, @status.stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]],
[ActivityPub::TagManager.instance.uri_for(@status), [%w(rel alternate), %w(type application/activity+json)]],
]
)
end end
def set_status def set_status
@@ -64,8 +41,4 @@ class StatusesController < ApplicationController
def check_account_suspension def check_account_suspension
gone if @account.suspended? gone if @account.suspended?
end end
def redirect_to_original
redirect_to ::TagManager.instance.url_for(@status.reblog) if @status.reblog?
end
end end

View File

@@ -2,7 +2,6 @@
class StreamEntriesController < ApplicationController class StreamEntriesController < ApplicationController
include Authorization include Authorization
include SignatureVerification
layout 'public' layout 'public'
@@ -19,13 +18,16 @@ class StreamEntriesController < ApplicationController
end end
format.atom do format.atom do
render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(@stream_entry, true)) render xml: AtomSerializer.render(AtomSerializer.new.entry(@stream_entry, true))
end end
end end
end end
def embed def embed
redirect_to embed_short_account_status_url(@account, @stream_entry.activity), status: 301 response.headers['X-Frame-Options'] = 'ALLOWALL'
return gone if @stream_entry.activity.nil?
render layout: 'embedded'
end end
private private
@@ -35,12 +37,7 @@ class StreamEntriesController < ApplicationController
end end
def set_link_headers def set_link_headers
response.headers['Link'] = LinkHeader.new( response.headers['Link'] = LinkHeader.new([[account_stream_entry_url(@account, @stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]]])
[
[account_stream_entry_url(@account, @stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]],
[ActivityPub::TagManager.instance.uri_for(@stream_entry.activity), [%w(rel alternate), %w(type application/activity+json)]],
]
)
end end
def set_stream_entry def set_stream_entry

View File

@@ -5,26 +5,7 @@ class TagsController < ApplicationController
def show def show
@tag = Tag.find_by!(name: params[:id].downcase) @tag = Tag.find_by!(name: params[:id].downcase)
@statuses = Status.as_tag_timeline(@tag, current_account, params[:local]).paginate_by_max_id(20, params[:max_id]) @statuses = @tag.nil? ? [] : Status.as_tag_timeline(@tag, current_account, params[:local]).paginate_by_max_id(20, params[:max_id])
@statuses = cache_collection(@statuses, Status) @statuses = cache_collection(@statuses, Status)
respond_to do |format|
format.html
format.json do
render json: collection_presenter, serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
end
end
private
def collection_presenter
ActivityPub::CollectionPresenter.new(
id: tag_url(@tag),
type: :ordered,
size: @tag.statuses.count,
items: @statuses.map { |s| ActivityPub::TagManager.instance.uri_for(s) }
)
end end
end end

View File

@@ -0,0 +1,8 @@
# frozen_string_literal: true
module Activitystreams2BuilderHelper
# Gets a usable name for an account, using display name or username.
def account_name(account)
account.display_name.presence || account.username
end
end

View File

@@ -6,21 +6,15 @@ module Admin::FilterHelper
FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS
def filter_link_to(text, link_to_params, link_class_params = link_to_params) def filter_link_to(text, more_params)
new_url = filtered_url_for(link_to_params) new_url = filtered_url_for(more_params)
new_class = filtered_url_for(link_class_params) link_to text, new_url, class: filter_link_class(new_url)
link_to text, new_url, class: filter_link_class(new_class)
end end
def table_link_to(icon, text, path, options = {}) def table_link_to(icon, text, path, options = {})
link_to safe_join([fa_icon(icon), text]), path, options.merge(class: 'table-action-link') link_to safe_join([fa_icon(icon), text]), path, options.merge(class: 'table-action-link')
end end
def selected?(more_params)
new_url = filtered_url_for(more_params)
filter_link_class(new_url) == 'selected' ? true : false
end
private private
def filter_params(more_params) def filter_params(more_params)

View File

@@ -5,10 +5,6 @@ module ApplicationHelper
current_page?(path) ? 'active' : '' current_page?(path) ? 'active' : ''
end end
def active_link_to(label, path, options = {})
link_to label, path, options.merge(class: active_nav_class(path))
end
def show_landing_strip? def show_landing_strip?
!user_signed_in? && !single_user_mode? !user_signed_in? && !single_user_mode?
end end
@@ -35,11 +31,7 @@ module ApplicationHelper
Rails.env.production? ? site_title : "#{site_title} (Dev)" Rails.env.production? ? site_title : "#{site_title} (Dev)"
end end
def fa_icon(icon, attributes = {}) def fa_icon(icon)
class_names = attributes[:class]&.split(' ') || [] content_tag(:i, nil, class: 'fa ' + icon.split(' ').map { |cl| "fa-#{cl}" }.join(' '))
class_names << 'fa'
class_names += icon.split(' ').map { |cl| "fa-#{cl}" }
content_tag(:i, nil, attributes.merge(class: class_names.join(' ')))
end end
end end

View File

@@ -1,24 +0,0 @@
# frozen_string_literal: true
module EmojiHelper
def emojify(text)
return text if text.blank?
text.gsub(emoji_pattern) do |match|
emoji = Emoji.instance.unicode($1) # rubocop:disable Style/PerlBackrefs
if emoji
emoji
else
match
end
end
end
def emoji_pattern
@emoji_pattern ||=
/(?<=[^[:alnum:]:]|\n|^)
(#{Emoji.instance.names.map { |name| Regexp.escape(name) }.join('|')})
(?=[^[:alnum:]:]|$)/x
end
end

View File

@@ -0,0 +1,17 @@
# frozen_string_literal: true
module HttpHelper
def http_client(options = {})
timeout = { write: 10, connect: 10, read: 10 }.merge(options)
HTTP.headers(user_agent: user_agent)
.timeout(:per_operation, timeout)
.follow
end
private
def user_agent
@user_agent ||= "#{HTTP::Request::USER_AGENT} (Mastodon/#{Mastodon::Version}; +http://#{Rails.configuration.x.local_domain}/)"
end
end

View File

@@ -2,7 +2,7 @@
module InstanceHelper module InstanceHelper
def site_title def site_title
Setting.site_title.presence || site_hostname Setting.site_title.to_s
end end
def site_hostname def site_hostname

View File

@@ -1,52 +0,0 @@
# frozen_string_literal: true
module JsonLdHelper
def equals_or_includes?(haystack, needle)
haystack.is_a?(Array) ? haystack.include?(needle) : haystack == needle
end
def first_of_value(value)
value.is_a?(Array) ? value.first : value
end
def value_or_id(value)
value.is_a?(String) || value.nil? ? value : value['id']
end
def supported_context?(json)
!json.nil? && equals_or_includes?(json['@context'], ActivityPub::TagManager::CONTEXT)
end
def canonicalize(json)
graph = RDF::Graph.new << JSON::LD::API.toRdf(json)
graph.dump(:normalize)
end
def fetch_resource(uri)
response = build_request(uri).perform
return if response.code != 200
body_to_json(response.to_s)
end
def body_to_json(body)
body.is_a?(String) ? Oj.load(body, mode: :strict) : body
rescue Oj::ParseError
nil
end
def merge_context(context, new_context)
if context.is_a?(Array)
context << new_context
else
[context, new_context]
end
end
private
def build_request(uri)
request = Request.new(:get, uri)
request.add_headers('Accept' => 'application/activity+json, application/ld+json')
request
end
end

View File

@@ -11,9 +11,7 @@ module RoutingHelper
end end
end end
def full_asset_url(source, options = {}) def full_asset_url(source)
source = ActionController::Base.helpers.asset_url(source, options) unless Rails.configuration.x.use_s3 Rails.configuration.x.use_s3 ? source : URI.join(root_url, ActionController::Base.helpers.asset_url(source)).to_s
URI.join(root_url, source).to_s
end end
end end

View File

@@ -19,7 +19,6 @@ module SettingsHelper
io: 'Ido', io: 'Ido',
it: 'Italiano', it: 'Italiano',
ja: '日本語', ja: '日本語',
ko: '한국어',
nl: 'Nederlands', nl: 'Nederlands',
no: 'Norsk', no: 'Norsk',
oc: 'Occitan', oc: 'Occitan',
@@ -42,16 +41,4 @@ module SettingsHelper
def hash_to_object(hash) def hash_to_object(hash)
HashObject.new(hash) HashObject.new(hash)
end end
def session_device_icon(session)
device = session.detection.device
if device.mobile?
'mobile'
elsif device.tablet?
'tablet'
else
'desktop'
end
end
end end

View File

@@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
module StreamEntriesHelper module StreamEntriesHelper
EMBEDDED_CONTROLLER = 'statuses' EMBEDDED_CONTROLLER = 'stream_entries'
EMBEDDED_ACTION = 'embed' EMBEDDED_ACTION = 'embed'
def display_name(account) def display_name(account)

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

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