Merge remote-tracking branch 'tootsuite/main' into custom/quote
This commit is contained in:
commit
0c206d8711
@ -1,8 +1,8 @@
|
|||||||
version: 2.1
|
version: 2.1
|
||||||
|
|
||||||
orbs:
|
orbs:
|
||||||
ruby: circleci/ruby@1.2.0
|
ruby: circleci/ruby@1.4.1
|
||||||
node: circleci/node@4.7.0
|
node: circleci/node@5.0.1
|
||||||
|
|
||||||
executors:
|
executors:
|
||||||
default:
|
default:
|
||||||
@ -23,7 +23,7 @@ executors:
|
|||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: root
|
POSTGRES_USER: root
|
||||||
POSTGRES_HOST_AUTH_METHOD: trust
|
POSTGRES_HOST_AUTH_METHOD: trust
|
||||||
- image: circleci/redis:6-alpine
|
- image: cimg/redis:6.2
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
install-system-dependencies:
|
install-system-dependencies:
|
||||||
@ -45,7 +45,7 @@ commands:
|
|||||||
bundle config without 'development production'
|
bundle config without 'development production'
|
||||||
name: Set bundler settings
|
name: Set bundler settings
|
||||||
- ruby/install-deps:
|
- ruby/install-deps:
|
||||||
bundler-version: '2.2.31'
|
bundler-version: '2.3.8'
|
||||||
key: ruby<< parameters.ruby-version >>-gems-v1
|
key: ruby<< parameters.ruby-version >>-gems-v1
|
||||||
wait-db:
|
wait-db:
|
||||||
steps:
|
steps:
|
||||||
@ -127,9 +127,18 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
command: ./bin/rails tests:migrations:populate_v2
|
command: ./bin/rails tests:migrations:populate_v2
|
||||||
name: Populate database with test data
|
name: Populate database with test data
|
||||||
|
- run:
|
||||||
|
command: ./bin/rails db:migrate VERSION=20180514140000
|
||||||
|
name: Run migrations up to v2.4.0
|
||||||
|
- run:
|
||||||
|
command: ./bin/rails tests:migrations:populate_v2_4
|
||||||
|
name: Populate database with test data
|
||||||
- run:
|
- run:
|
||||||
command: ./bin/rails db:migrate
|
command: ./bin/rails db:migrate
|
||||||
name: Run all remaining migrations
|
name: Run all remaining migrations
|
||||||
|
- run:
|
||||||
|
command: ./bin/rails tests:migrations:check_database
|
||||||
|
name: Check migration result
|
||||||
|
|
||||||
test-two-step-migrations:
|
test-two-step-migrations:
|
||||||
executor:
|
executor:
|
||||||
@ -150,14 +159,25 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
command: ./bin/rails tests:migrations:populate_v2
|
command: ./bin/rails tests:migrations:populate_v2
|
||||||
name: Populate database with test data
|
name: Populate database with test data
|
||||||
|
- run:
|
||||||
|
command: ./bin/rails db:migrate VERSION=20180514140000
|
||||||
|
name: Run pre-deployment migrations up to v2.4.0
|
||||||
|
environment:
|
||||||
|
SKIP_POST_DEPLOYMENT_MIGRATIONS: true
|
||||||
|
- run:
|
||||||
|
command: ./bin/rails tests:migrations:populate_v2_4
|
||||||
|
name: Populate database with test data
|
||||||
- run:
|
- run:
|
||||||
command: ./bin/rails db:migrate
|
command: ./bin/rails db:migrate
|
||||||
name: Run all pre-deployment migrations
|
name: Run all pre-deployment migrations
|
||||||
evironment:
|
environment:
|
||||||
SKIP_POST_DEPLOYMENT_MIGRATIONS: true
|
SKIP_POST_DEPLOYMENT_MIGRATIONS: true
|
||||||
- run:
|
- run:
|
||||||
command: ./bin/rails db:migrate
|
command: ./bin/rails db:migrate
|
||||||
name: Run all post-deployment remaining migrations
|
name: Run all post-deployment remaining migrations
|
||||||
|
- run:
|
||||||
|
command: ./bin/rails tests:migrations:check_database
|
||||||
|
name: Check migration result
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
version: 2
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
version: "2"
|
version: '2'
|
||||||
checks:
|
checks:
|
||||||
argument-count:
|
argument-count:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
24
.devcontainer/Dockerfile
Normal file
24
.devcontainer/Dockerfile
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# [Choice] Ruby version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.1, 3.0, 2, 2.7, 2.6, 3-bullseye, 3.1-bullseye, 3.0-bullseye, 2-bullseye, 2.7-bullseye, 2.6-bullseye, 3-buster, 3.1-buster, 3.0-buster, 2-buster, 2.7-buster, 2.6-buster
|
||||||
|
ARG VARIANT=3.1-bullseye
|
||||||
|
FROM mcr.microsoft.com/vscode/devcontainers/ruby:${VARIANT}
|
||||||
|
|
||||||
|
# Install Rails
|
||||||
|
# RUN gem install rails webdrivers
|
||||||
|
|
||||||
|
# Default value to allow debug server to serve content over GitHub Codespace's port forwarding service
|
||||||
|
# The value is a comma-separated list of allowed domains
|
||||||
|
ENV RAILS_DEVELOPMENT_HOSTS=".githubpreview.dev"
|
||||||
|
|
||||||
|
# [Choice] Node.js version: lts/*, 16, 14, 12, 10
|
||||||
|
ARG NODE_VERSION="lts/*"
|
||||||
|
RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"
|
||||||
|
|
||||||
|
# [Optional] Uncomment this section to install additional OS packages.
|
||||||
|
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
|
&& apt-get -y install --no-install-recommends libicu-dev libidn11-dev ffmpeg imagemagick libpam-dev
|
||||||
|
|
||||||
|
# [Optional] Uncomment this line to install additional gems.
|
||||||
|
RUN gem install foreman
|
||||||
|
|
||||||
|
# [Optional] Uncomment this line to install global node packages.
|
||||||
|
RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g yarn" 2>&1
|
26
.devcontainer/devcontainer.json
Normal file
26
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "Mastodon",
|
||||||
|
"dockerComposeFile": "docker-compose.yml",
|
||||||
|
"service": "app",
|
||||||
|
"workspaceFolder": "/workspaces/mastodon",
|
||||||
|
|
||||||
|
// Set *default* container specific settings.json values on container create.
|
||||||
|
"settings": {},
|
||||||
|
|
||||||
|
// Add the IDs of extensions you want installed when the container is created.
|
||||||
|
"extensions": [
|
||||||
|
"EditorConfig.EditorConfig",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"rebornix.Ruby"
|
||||||
|
],
|
||||||
|
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
// This can be used to network with other containers or the host.
|
||||||
|
"forwardPorts": [3000, 4000],
|
||||||
|
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
"postCreateCommand": "bundle install --path vendor/bundle && yarn install && ./bin/rails db:setup",
|
||||||
|
|
||||||
|
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||||
|
"remoteUser": "vscode"
|
||||||
|
}
|
83
.devcontainer/docker-compose.yml
Normal file
83
.devcontainer/docker-compose.yml
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
# Update 'VARIANT' to pick a version of Ruby: 3, 3.1, 3.0, 2, 2.7, 2.6
|
||||||
|
# Append -bullseye or -buster to pin to an OS version.
|
||||||
|
# Use -bullseye variants on local arm64/Apple Silicon.
|
||||||
|
VARIANT: '3.0-bullseye'
|
||||||
|
# Optional Node.js version to install
|
||||||
|
NODE_VERSION: '14'
|
||||||
|
volumes:
|
||||||
|
- ..:/workspaces/mastodon:cached
|
||||||
|
environment:
|
||||||
|
RAILS_ENV: development
|
||||||
|
NODE_ENV: development
|
||||||
|
|
||||||
|
REDIS_HOST: redis
|
||||||
|
REDIS_PORT: '6379'
|
||||||
|
DB_HOST: db
|
||||||
|
DB_USER: postgres
|
||||||
|
DB_PASS: postgres
|
||||||
|
DB_PORT: '5432'
|
||||||
|
ES_ENABLED: 'true'
|
||||||
|
ES_HOST: es
|
||||||
|
ES_PORT: '9200'
|
||||||
|
# Overrides default command so things don't shut down after the process ends.
|
||||||
|
command: sleep infinity
|
||||||
|
networks:
|
||||||
|
- external_network
|
||||||
|
- internal_network
|
||||||
|
user: vscode
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_DB: postgres
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
POSTGRES_HOST_AUTH_METHOD: trust
|
||||||
|
networks:
|
||||||
|
- internal_network
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:6-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
networks:
|
||||||
|
- internal_network
|
||||||
|
|
||||||
|
es:
|
||||||
|
image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
ES_JAVA_OPTS: -Xms512m -Xmx512m
|
||||||
|
cluster.name: es-mastodon
|
||||||
|
discovery.type: single-node
|
||||||
|
bootstrap.memory_lock: 'true'
|
||||||
|
volumes:
|
||||||
|
- es-data:/usr/share/elasticsearch/data
|
||||||
|
networks:
|
||||||
|
- internal_network
|
||||||
|
ulimits:
|
||||||
|
memlock:
|
||||||
|
soft: -1
|
||||||
|
hard: -1
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres-data:
|
||||||
|
redis-data:
|
||||||
|
es-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
external_network:
|
||||||
|
internal_network:
|
||||||
|
internal: true
|
@ -58,7 +58,7 @@ SMTP_SERVER=smtp.mailgun.org
|
|||||||
SMTP_PORT=587
|
SMTP_PORT=587
|
||||||
SMTP_LOGIN=
|
SMTP_LOGIN=
|
||||||
SMTP_PASSWORD=
|
SMTP_PASSWORD=
|
||||||
SMTP_FROM_ADDRESS=notificatons@example.com
|
SMTP_FROM_ADDRESS=notifications@example.com
|
||||||
|
|
||||||
# File storage (optional)
|
# File storage (optional)
|
||||||
# -----------------------
|
# -----------------------
|
||||||
|
@ -79,6 +79,11 @@ module.exports = {
|
|||||||
'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-restricted-properties': [
|
||||||
|
'error',
|
||||||
|
{ property: 'substring', message: 'Use .slice instead of .substring.' },
|
||||||
|
{ property: 'substr', message: 'Use .slice instead of .substr.' },
|
||||||
|
],
|
||||||
'no-trailing-spaces': 'warn',
|
'no-trailing-spaces': 'warn',
|
||||||
'no-undef': 'error',
|
'no-undef': 'error',
|
||||||
'no-unreachable': 'error',
|
'no-unreachable': 'error',
|
||||||
|
32
.github/CODEOWNERS
vendored
32
.github/CODEOWNERS
vendored
@ -1,32 +0,0 @@
|
|||||||
# CODEOWNERS for mastodon/mastodon
|
|
||||||
|
|
||||||
# Translators
|
|
||||||
# To add translator, copy these lines, replace `fr` with appropriate language code and replace `@żelipapą` with user's GitHub nickname preceded by `@` sign or e-mail address.
|
|
||||||
# /app/javascript/mastodon/locales/fr.json @żelipapą
|
|
||||||
# /app/views/user_mailer/*.fr.html.erb @żelipapą
|
|
||||||
# /app/views/user_mailer/*.fr.text.erb @żelipapą
|
|
||||||
# /config/locales/*.fr.yml @żelipapą
|
|
||||||
# /config/locales/fr.yml @żelipapą
|
|
||||||
|
|
||||||
# Polish
|
|
||||||
/app/javascript/mastodon/locales/pl.json @m4sk1n
|
|
||||||
/app/views/user_mailer/*.pl.html.erb @m4sk1n
|
|
||||||
/app/views/user_mailer/*.pl.text.erb @m4sk1n
|
|
||||||
/config/locales/*.pl.yml @m4sk1n
|
|
||||||
/config/locales/pl.yml @m4sk1n
|
|
||||||
|
|
||||||
# French
|
|
||||||
/app/javascript/mastodon/locales/fr.json @aldarone
|
|
||||||
/app/javascript/mastodon/locales/whitelist_fr.json @aldarone
|
|
||||||
/app/views/user_mailer/*.fr.html.erb @aldarone
|
|
||||||
/app/views/user_mailer/*.fr.text.erb @aldarone
|
|
||||||
/config/locales/*.fr.yml @aldarone
|
|
||||||
/config/locales/fr.yml @aldarone
|
|
||||||
|
|
||||||
# Dutch
|
|
||||||
/app/javascript/mastodon/locales/nl.json @jeroenpraat
|
|
||||||
/app/javascript/mastodon/locales/whitelist_nl.json @jeroenpraat
|
|
||||||
/app/views/user_mailer/*.nl.html.erb @jeroenpraat
|
|
||||||
/app/views/user_mailer/*.nl.text.erb @jeroenpraat
|
|
||||||
/config/locales/*.nl.yml @jeroenpraat
|
|
||||||
/config/locales/nl.yml @jeroenpraat
|
|
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -1,3 +1,3 @@
|
|||||||
patreon: mastodon
|
patreon: mastodon
|
||||||
open_collective: mastodon
|
open_collective: mastodon
|
||||||
github: [Gargron]
|
custom: https://sponsor.joinmastodon.org
|
||||||
|
1
.github/ISSUE_TEMPLATE/2.feature_request.yml
vendored
1
.github/ISSUE_TEMPLATE/2.feature_request.yml
vendored
@ -1,5 +1,6 @@
|
|||||||
name: Feature Request
|
name: Feature Request
|
||||||
description: I have a suggestion
|
description: I have a suggestion
|
||||||
|
labels: suggestion
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
10
.github/ISSUE_TEMPLATE/3.support.md
vendored
10
.github/ISSUE_TEMPLATE/3.support.md
vendored
@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
name: Support
|
|
||||||
about: Ask for help with your deployment
|
|
||||||
title: DO NOT CREATE THIS ISSUE
|
|
||||||
---
|
|
||||||
|
|
||||||
We primarily use GitHub as a bug and feature tracker. For usage questions, troubleshooting of deployments and other individual technical assistance, please use one of the resources below:
|
|
||||||
|
|
||||||
- https://discourse.joinmastodon.org
|
|
||||||
- #mastodon on irc.freenode.net
|
|
7
.github/ISSUE_TEMPLATE/config.yml
vendored
7
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +1,8 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Mastodon Meta Discussion Board
|
- name: GitHub Discussions
|
||||||
url: https://discourse.joinmastodon.org/
|
url: https://github.com/mastodon/mastodon/discussions
|
||||||
about: Please ask and answer questions here.
|
about: Please ask and answer questions here.
|
||||||
|
- name: Bug Bounty Program
|
||||||
|
url: https://app.intigriti.com/programs/mastodon/mastodonio/detail
|
||||||
|
about: Please report security vulnerabilities here.
|
||||||
|
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@ -6,7 +6,7 @@
|
|||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
- package-ecosystem: npm
|
- package-ecosystem: npm
|
||||||
directory: "/"
|
directory: '/'
|
||||||
schedule:
|
schedule:
|
||||||
interval: weekly
|
interval: weekly
|
||||||
open-pull-requests-limit: 99
|
open-pull-requests-limit: 99
|
||||||
@ -14,7 +14,7 @@ updates:
|
|||||||
- dependency-type: direct
|
- dependency-type: direct
|
||||||
|
|
||||||
- package-ecosystem: bundler
|
- package-ecosystem: bundler
|
||||||
directory: "/"
|
directory: '/'
|
||||||
schedule:
|
schedule:
|
||||||
interval: weekly
|
interval: weekly
|
||||||
open-pull-requests-limit: 99
|
open-pull-requests-limit: 99
|
||||||
|
6
.github/workflows/build-image.yml
vendored
6
.github/workflows/build-image.yml
vendored
@ -3,9 +3,9 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- "main"
|
- 'main'
|
||||||
tags:
|
tags:
|
||||||
- "*"
|
- '*'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- .github/workflows/build-image.yml
|
- .github/workflows/build-image.yml
|
||||||
@ -30,7 +30,7 @@ jobs:
|
|||||||
latest=auto
|
latest=auto
|
||||||
tags: |
|
tags: |
|
||||||
type=edge,branch=main
|
type=edge,branch=main
|
||||||
type=semver,pattern={{ raw }}
|
type=match,pattern=v(.*),group=0
|
||||||
type=ref,event=pr
|
type=ref,event=pr
|
||||||
- uses: docker/build-push-action@v2
|
- uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
|
78
.prettierignore
Normal file
78
.prettierignore
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
|
||||||
|
#
|
||||||
|
# If you find yourself ignoring temporary files generated by your text editor
|
||||||
|
# or operating system, you probably want to add a global ignore instead:
|
||||||
|
# git config --global core.excludesfile '~/.gitignore_global'
|
||||||
|
|
||||||
|
# Ignore bundler config and downloaded libraries.
|
||||||
|
/.bundle
|
||||||
|
/vendor/bundle
|
||||||
|
|
||||||
|
# Ignore the default SQLite database.
|
||||||
|
/db/*.sqlite3
|
||||||
|
/db/*.sqlite3-journal
|
||||||
|
|
||||||
|
# Ignore all logfiles and tempfiles.
|
||||||
|
.eslintcache
|
||||||
|
/log/*
|
||||||
|
!/log/.keep
|
||||||
|
/tmp
|
||||||
|
/coverage
|
||||||
|
/public/system
|
||||||
|
/public/assets
|
||||||
|
/public/packs
|
||||||
|
/public/packs-test
|
||||||
|
.env
|
||||||
|
.env.production
|
||||||
|
.env.development
|
||||||
|
/node_modules/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# Ignore Vagrant files
|
||||||
|
.vagrant/
|
||||||
|
|
||||||
|
# Ignore Capistrano customizations
|
||||||
|
/config/deploy/*
|
||||||
|
|
||||||
|
# Ignore IDE files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Ignore postgres + redis + elasticsearch volume optionally created by docker-compose
|
||||||
|
/postgres
|
||||||
|
/postgres14
|
||||||
|
/redis
|
||||||
|
/elasticsearch
|
||||||
|
|
||||||
|
# ignore Helm dependency charts
|
||||||
|
/chart/charts/*.tgz
|
||||||
|
|
||||||
|
# Ignore Apple files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Ignore vim files
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Ignore npm debug log
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
# Ignore yarn log files
|
||||||
|
yarn-error.log
|
||||||
|
yarn-debug.log
|
||||||
|
|
||||||
|
# Ignore vagrant log files
|
||||||
|
*-cloudimg-console.log
|
||||||
|
|
||||||
|
# Ignore Docker option files
|
||||||
|
docker-compose.override.yml
|
||||||
|
|
||||||
|
# Ignore Helm files
|
||||||
|
/chart
|
||||||
|
|
||||||
|
# Ignore emoji map file
|
||||||
|
/app/javascript/mastodon/features/emoji/emoji_map.json
|
||||||
|
|
||||||
|
# Ignore locale files
|
||||||
|
/app/javascript/mastodon/locales
|
||||||
|
/config/locales
|
3
.prettierrc.js
Normal file
3
.prettierrc.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
singleQuote: true
|
||||||
|
}
|
@ -29,6 +29,9 @@ Layout/EmptyLineAfterMagicComment:
|
|||||||
Layout/EmptyLineAfterGuardClause:
|
Layout/EmptyLineAfterGuardClause:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/EmptyLineBetweenDefs:
|
||||||
|
AllowAdjacentOneLineDefs: true
|
||||||
|
|
||||||
Layout/EmptyLinesAroundAttributeAccessor:
|
Layout/EmptyLinesAroundAttributeAccessor:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
||||||
|
675
AUTHORS.md
675
AUTHORS.md
File diff suppressed because it is too large
Load Diff
272
CHANGELOG.md
272
CHANGELOG.md
@ -3,6 +3,248 @@ Changelog
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [3.5.1] - 2022-04-08
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add pagination for trending statuses in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17976))
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Change e-mail notifications to only be sent when recipient is offline ([Gargron](https://github.com/mastodon/mastodon/pull/17984))
|
||||||
|
- Send e-mails for mentions and follows by default again
|
||||||
|
- But only when recipient does not have push notifications through an app
|
||||||
|
- Change `website` attribute to be nullable on `Application` entity in REST API ([rinsuki](https://github.com/mastodon/mastodon/pull/17962))
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Remove sign-in token authentication, instead send e-mail about new sign-in ([Gargron](https://github.com/mastodon/mastodon/pull/17970))
|
||||||
|
- You no longer need to enter a security code sent through e-mail
|
||||||
|
- Instead you get an e-mail about a new sign-in from an unfamiliar IP address
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix error resposes for `from` search prefix ([single-right-quote](https://github.com/mastodon/mastodon/pull/17963))
|
||||||
|
- Fix dangling language-specific trends ([Gargron](https://github.com/mastodon/mastodon/pull/17997))
|
||||||
|
- Fix extremely rare race condition when deleting a status or account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17994))
|
||||||
|
- Fix trends returning less results per page when filtered in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17996))
|
||||||
|
- Fix pagination header on empty trends responses in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17986))
|
||||||
|
- Fix cookies secure flag being set when served over Tor ([Gargron](https://github.com/mastodon/mastodon/pull/17992))
|
||||||
|
- Fix migration error handling ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17991))
|
||||||
|
- Fix error when re-running some migrations if they get interrupted at the wrong moment ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17989))
|
||||||
|
- Fix potentially missing statuses when reconnecting to streaming API in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17981), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17987), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17980))
|
||||||
|
- Fix error when sending warning emails with custom text ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17983))
|
||||||
|
- Fix unset `SMTP_RETURN_PATH` environment variable causing e-mail not to send ([Gargron](https://github.com/mastodon/mastodon/pull/17982))
|
||||||
|
- Fix possible duplicate statuses in timelines in some edge cases in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17971))
|
||||||
|
- Fix spurious edits and require incoming edits to be explicitly marked as such ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17918))
|
||||||
|
- Fix error when encountering invalid pinned statuses ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17964))
|
||||||
|
- Fix inconsistency in error handling when removing a status ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17974))
|
||||||
|
- Fix admin API unconditionally requiring CSRF token ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17975))
|
||||||
|
- Fix trending tags endpoint missing `offset` param in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17973))
|
||||||
|
- Fix unusual number formatting in some locales ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17929))
|
||||||
|
- Fix `S3_FORCE_SINGLE_REQUEST` environment variable not working ([HolgerHuo](https://github.com/mastodon/mastodon/pull/17922))
|
||||||
|
- Fix failure to build assets with OpenSSL 3 ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17930))
|
||||||
|
- Fix PWA manifest using outdated routes ([HolgerHuo](https://github.com/mastodon/mastodon/pull/17921))
|
||||||
|
- Fix error when indexing statuses into Elasticsearch ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17912))
|
||||||
|
|
||||||
|
## [3.5.0] - 2022-03-30
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Add support for incoming edited posts** ([Gargron](https://github.com/mastodon/mastodon/pull/16697), [Gargron](https://github.com/mastodon/mastodon/pull/17727), [Gargron](https://github.com/mastodon/mastodon/pull/17728), [Gargron](https://github.com/mastodon/mastodon/pull/17320), [Gargron](https://github.com/mastodon/mastodon/pull/17404), [Gargron](https://github.com/mastodon/mastodon/pull/17390), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17335), [Gargron](https://github.com/mastodon/mastodon/pull/17696), [Gargron](https://github.com/mastodon/mastodon/pull/17745), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17740), [Gargron](https://github.com/mastodon/mastodon/pull/17697), [Gargron](https://github.com/mastodon/mastodon/pull/17648), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17531), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17499), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17498), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17380), [Gargron](https://github.com/mastodon/mastodon/pull/17373), [Gargron](https://github.com/mastodon/mastodon/pull/17334), [Gargron](https://github.com/mastodon/mastodon/pull/17333), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17699), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17748))
|
||||||
|
- Previous versions remain available for perusal and comparison
|
||||||
|
- People who reblogged a post are notified when it's edited
|
||||||
|
- New REST APIs:
|
||||||
|
- `PUT /api/v1/statuses/:id`
|
||||||
|
- `GET /api/v1/statuses/:id/history`
|
||||||
|
- `GET /api/v1/statuses/:id/source`
|
||||||
|
- New streaming API event:
|
||||||
|
- `status.update`
|
||||||
|
- **Add appeals for moderator decisions** ([Gargron](https://github.com/mastodon/mastodon/pull/17364), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17725), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17566), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17652), [Gargron](https://github.com/mastodon/mastodon/pull/17616), [Gargron](https://github.com/mastodon/mastodon/pull/17615), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17554), [Gargron](https://github.com/mastodon/mastodon/pull/17523))
|
||||||
|
- All default moderator decisions now notify the affected user by e-mail
|
||||||
|
- They now link to an appeal page instead of suggesting replying to the e-mail
|
||||||
|
- They can now be found in account settings and not just e-mail
|
||||||
|
- Users can submit one appeal within 20 days of the decision
|
||||||
|
- Moderators can approve or reject the appeal
|
||||||
|
- **Add notifications for posts deleted by moderators** ([Gargron](https://github.com/mastodon/mastodon/pull/17204), [Gargron](https://github.com/mastodon/mastodon/pull/17668), [Gargron](https://github.com/mastodon/mastodon/pull/17746), [Gargron](https://github.com/mastodon/mastodon/pull/17679), [Gargron](https://github.com/mastodon/mastodon/pull/17487))
|
||||||
|
- New, redesigned report view in admin UI
|
||||||
|
- Common report actions now only take one click to complete
|
||||||
|
- Deleting posts or marking as sensitive from report now notifies user
|
||||||
|
- Reports can be categorized by reason and specific rules violated
|
||||||
|
- The reasons are automatically cited in the notifications, except for spam
|
||||||
|
- Marking posts as sensitive now federates using post editing
|
||||||
|
- **Add explore page with trending posts and links** ([Gargron](https://github.com/mastodon/mastodon/pull/17123), [Gargron](https://github.com/mastodon/mastodon/pull/17431), [Gargron](https://github.com/mastodon/mastodon/pull/16917), [Gargron](https://github.com/mastodon/mastodon/pull/17677), [Gargron](https://github.com/mastodon/mastodon/pull/16938), [Gargron](https://github.com/mastodon/mastodon/pull/17044), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16978), [Gargron](https://github.com/mastodon/mastodon/pull/16979), [tribela](https://github.com/mastodon/mastodon/pull/17066), [Gargron](https://github.com/mastodon/mastodon/pull/17072), [Gargron](https://github.com/mastodon/mastodon/pull/17403), [noiob](https://github.com/mastodon/mastodon/pull/17624), [mayaeh](https://github.com/mastodon/mastodon/pull/17755), [mayaeh](https://github.com/mastodon/mastodon/pull/17757), [Gargron](https://github.com/mastodon/mastodon/pull/17760), [mayaeh](https://github.com/mastodon/mastodon/pull/17762))
|
||||||
|
- Hashtag trends algorithm is extended to work for posts and links
|
||||||
|
- Links are only considered if they have an adequate preview card
|
||||||
|
- Preview card generation has been improved to support structured data
|
||||||
|
- Links can only trend if the publisher (domain) has been approved
|
||||||
|
- Posts can only trend if the author has been approved
|
||||||
|
- Individual approval and rejection for posts and links is also available
|
||||||
|
- Moderators are notified about pending trends at most once every 2 hours
|
||||||
|
- Posts and link trends are language-specific
|
||||||
|
- Search page is redesigned into explore page in web UI
|
||||||
|
- Discovery tab is coming soon in official iOS and Android apps
|
||||||
|
- New REST APIs:
|
||||||
|
- `GET /api/v1/trends/links`
|
||||||
|
- `GET /api/v1/trends/statuses`
|
||||||
|
- `GET /api/v1/trends/tags` (alias of `GET /api/v1/trends`)
|
||||||
|
- `GET /api/v1/admin/trends/links`
|
||||||
|
- `GET /api/v1/admin/trends/statuses`
|
||||||
|
- `GET /api/v1/admin/trends/tags`
|
||||||
|
- **Add graphs and retention metrics to admin dashboard** ([Gargron](https://github.com/mastodon/mastodon/pull/16829), [Gargron](https://github.com/mastodon/mastodon/pull/17617), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17570), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16910), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16909), [mashirozx](https://github.com/mastodon/mastodon/pull/16884), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16854))
|
||||||
|
- Dashboard shows more numbers with development over time
|
||||||
|
- Other data such as most used interface languages and sign-up sources
|
||||||
|
- User retention graph shows how many new users stick around
|
||||||
|
- New REST APIs:
|
||||||
|
- `POST /api/v1/admin/measures`
|
||||||
|
- `POST /api/v1/admin/dimensions`
|
||||||
|
- `POST /api/v1/admin/retention`
|
||||||
|
- Add `GET /api/v1/accounts/familiar_followers` to REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17700))
|
||||||
|
- Add `POST /api/v1/accounts/:id/remove_from_followers` to REST API ([noellabo](https://github.com/mastodon/mastodon/pull/16864))
|
||||||
|
- Add `category` and `rule_ids` params to `POST /api/v1/reports` IN REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17492), [Gargron](https://github.com/mastodon/mastodon/pull/17682), [Gargron](https://github.com/mastodon/mastodon/pull/17713))
|
||||||
|
- `category` can be one of: `spam`, `violation`, `other` (default)
|
||||||
|
- `rule_ids` must reference `rules` returned in `GET /api/v1/instance`
|
||||||
|
- Add global `lang` param to REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17464), [Gargron](https://github.com/mastodon/mastodon/pull/17592))
|
||||||
|
- Add `types` param to `GET /api/v1/notifications` in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17767))
|
||||||
|
- **Add notifications for moderators about new sign-ups** ([Gargron](https://github.com/mastodon/mastodon/pull/16953), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17629))
|
||||||
|
- When a new user confirms e-mail, moderators receive a notification
|
||||||
|
- New notification type:
|
||||||
|
- `admin.sign_up`
|
||||||
|
- Add authentication history ([Gargron](https://github.com/mastodon/mastodon/pull/16408), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16428), [baby-gnu](https://github.com/mastodon/mastodon/pull/16654))
|
||||||
|
- Add ability to automatically delete old posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16529), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17691), [tribela](https://github.com/mastodon/mastodon/pull/16653))
|
||||||
|
- Add ability to pin private posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16954), [tribela](https://github.com/mastodon/mastodon/pull/17326), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17304), [MitarashiDango](https://github.com/mastodon/mastodon/pull/17647))
|
||||||
|
- Add ability to filter search results by author using `from:` syntax ([tribela](https://github.com/mastodon/mastodon/pull/16526))
|
||||||
|
- Add ability to delete canonical email blocks in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16644))
|
||||||
|
- Add ability to purge undeliverable domains in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16686), [tribela](https://github.com/mastodon/mastodon/pull/17210), [tribela](https://github.com/mastodon/mastodon/pull/17741), [tribela](https://github.com/mastodon/mastodon/pull/17209))
|
||||||
|
- Add ability to disable e-mail token authentication for specific users in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/16427))
|
||||||
|
- **Add ability to suspend accounts in batches in admin UI** ([Gargron](https://github.com/mastodon/mastodon/pull/17009), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17301), [Gargron](https://github.com/mastodon/mastodon/pull/17444))
|
||||||
|
- New, redesigned accounts list in admin UI
|
||||||
|
- Batch suspensions are meant to help clean up spam and bot accounts
|
||||||
|
- They do not generate notifications
|
||||||
|
- Add ability to filter reports by origin of target account in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/16487))
|
||||||
|
- Add support for login through OpenID Connect ([chandrn7](https://github.com/mastodon/mastodon/pull/16221))
|
||||||
|
- Add lazy loading for emoji picker in web UI ([mashirozx](https://github.com/mastodon/mastodon/pull/16907), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17011))
|
||||||
|
- Add single option votes tooltip in polls in web UI ([Brawaru](https://github.com/mastodon/mastodon/pull/16849))
|
||||||
|
- Add confirmation modal when closing media edit modal with unsaved changes in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16518))
|
||||||
|
- Add hint about missing media attachment description in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17845))
|
||||||
|
- Add support for fetching Create and Announce activities by URI in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16383))
|
||||||
|
- Add `S3_FORCE_SINGLE_REQUEST` environment variable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16866))
|
||||||
|
- Add `OMNIAUTH_ONLY` environment variable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17288), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17345))
|
||||||
|
- Add `ES_USER` and `ES_PASS` environment variables for Elasticsearch authentication ([tribela](https://github.com/mastodon/mastodon/pull/16890))
|
||||||
|
- Add `CAS_SECURITY_ASSUME_EMAIL_IS_VERIFIED` environment variable ([baby-gnu](https://github.com/mastodon/mastodon/pull/16655))
|
||||||
|
- Add ability to pass specific domains to `tootctl accounts cull` ([tribela](https://github.com/mastodon/mastodon/pull/16511))
|
||||||
|
- Add `--by-uri` option to `tootctl domains purge` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16434))
|
||||||
|
- Add `--batch-size` option to `tootctl search deploy` ([aquarla](https://github.com/mastodon/mastodon/pull/17049))
|
||||||
|
- Add `--remove-orphans` option to `tootctl statuses remove` ([noellabo](https://github.com/mastodon/mastodon/pull/17067))
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Change design of federation pages in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/17704), [noellabo](https://github.com/mastodon/mastodon/pull/17735), [Gargron](https://github.com/mastodon/mastodon/pull/17765))
|
||||||
|
- Change design of account cards in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17689))
|
||||||
|
- Change `follow` scope to be covered by `read` and `write` scopes in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17678))
|
||||||
|
- Change design of authorized applications page ([Gargron](https://github.com/mastodon/mastodon/pull/17656), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17686))
|
||||||
|
- Change e-mail domain blocks to block IPs dynamically ([Gargron](https://github.com/mastodon/mastodon/pull/17635), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17650), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17649))
|
||||||
|
- Change report modal to include category selection in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17565), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17734), [Gargron](https://github.com/mastodon/mastodon/pull/17654), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17632))
|
||||||
|
- Change reblogs to not count towards hashtag trends anymore ([Gargron](https://github.com/mastodon/mastodon/pull/17501))
|
||||||
|
- Change languages to be listed under standard instead of native name in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/17485))
|
||||||
|
- Change routing paths to use usernames in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/16171), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16772), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16773), [mashirozx](https://github.com/mastodon/mastodon/pull/16793), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17060))
|
||||||
|
- Change list title input design in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17092))
|
||||||
|
- Change "Opt-in to profile directory" preference to be general discoverability preference ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16637))
|
||||||
|
- Change API rate limits to use /64 masking on IPv6 addresses ([tribela](https://github.com/mastodon/mastodon/pull/17588), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17600), [zunda](https://github.com/mastodon/mastodon/pull/17590))
|
||||||
|
- Change allowed formats for locally uploaded custom emojis to include GIF ([rgroothuijsen](https://github.com/mastodon/mastodon/pull/17706), [Gargron](https://github.com/mastodon/mastodon/pull/17759))
|
||||||
|
- Change error message when chosen password is too long ([rgroothuijsen](https://github.com/mastodon/mastodon/pull/17082))
|
||||||
|
- Change minimum required Elasticsearch version from 6 to 7 ([noellabo](https://github.com/mastodon/mastodon/pull/16915))
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Remove profile directory link from main navigation panel in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17688))
|
||||||
|
- **Remove language detection through cld3** ([Gargron](https://github.com/mastodon/mastodon/pull/17478), [ykzts](https://github.com/mastodon/mastodon/pull/17539), [Gargron](https://github.com/mastodon/mastodon/pull/17496), [Gargron](https://github.com/mastodon/mastodon/pull/17722))
|
||||||
|
- cld3 is very inaccurate on short-form content even with unique alphabets
|
||||||
|
- Post language can be overriden individually using `language` param
|
||||||
|
- Otherwise, it defaults to the user's interface language
|
||||||
|
- Remove support for `OAUTH_REDIRECT_AT_SIGN_IN` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17287))
|
||||||
|
- Use `OMNIAUTH_ONLY` instead
|
||||||
|
- Remove Keybase integration ([Gargron](https://github.com/mastodon/mastodon/pull/17045))
|
||||||
|
- Remove old columns and indexes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17245), [Gargron](https://github.com/mastodon/mastodon/pull/16409), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17191))
|
||||||
|
- Remove shortcodes from newly-created media attachments ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16730), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16763))
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- `GET /api/v1/trends` → `GET /api/v1/trends/tags`
|
||||||
|
- OAuth `follow` scope → `read` and/or `write`
|
||||||
|
- `text` attribute on `DELETE /api/v1/statuses/:id` → `GET /api/v1/statuses/:id/source`
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix IDN domains not being rendered correctly in a few left-over places ([Gargron](https://github.com/mastodon/mastodon/pull/17848))
|
||||||
|
- Fix Sanskrit translation not being used in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17820))
|
||||||
|
- Fix Kurdish languages having the wrong language codes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17812))
|
||||||
|
- Fix pghero making database schema suggestions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17807))
|
||||||
|
- Fix encoding glitch in the OpenGraph description of a profile page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17821))
|
||||||
|
- Fix web manifest not permitting PWA usage from alternate domains ([HolgerHuo](https://github.com/mastodon/mastodon/pull/16714))
|
||||||
|
- Fix not being able to edit media attachments for scheduled posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17690))
|
||||||
|
- Fix subscribed relay activities being recorded as boosts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17571))
|
||||||
|
- Fix streaming API server error messages when JSON parsing fails not specifying the source ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17559))
|
||||||
|
- Fix browsers autofilling new password field with old password ([mashirozx](https://github.com/mastodon/mastodon/pull/17702))
|
||||||
|
- Fix text being invisible before fonts load in web UI ([tribela](https://github.com/mastodon/mastodon/pull/16330))
|
||||||
|
- Fix public profile pages of unconfirmed users being accessible ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17385), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17457))
|
||||||
|
- Fix nil error when trying to fetch key for signature verification ([Gargron](https://github.com/mastodon/mastodon/pull/17747))
|
||||||
|
- Fix null values being included in some indexes ([Gargron](https://github.com/mastodon/mastodon/pull/17711))
|
||||||
|
- Fix `POST /api/v1/emails/confirmations` not being available after sign-up ([Gargron](https://github.com/mastodon/mastodon/pull/17743))
|
||||||
|
- Fix rare race condition when reblogged post is deleted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17693), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17730))
|
||||||
|
- Fix being able to add more than 4 hashtags to hashtag column in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17729))
|
||||||
|
- Fix data integrity of featured tags ([Gargron](https://github.com/mastodon/mastodon/pull/17712))
|
||||||
|
- Fix performance of account timelines ([Gargron](https://github.com/mastodon/mastodon/pull/17709))
|
||||||
|
- Fix returning empty `<p>` tag for blank account `note` in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17687))
|
||||||
|
- Fix leak of existence of otherwise inaccessible posts in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17684))
|
||||||
|
- Fix not showing loading indicator when searching in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17655))
|
||||||
|
- Fix media modal footer's “external link” not being a link ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17561))
|
||||||
|
- Fix reply button on media modal not giving focus to compose form ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17626))
|
||||||
|
- Fix some media attachments being converted with too high framerates ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17619))
|
||||||
|
- Fix sign in token and warning emails failing to send when contact e-mail address is malformed ([helloworldstack](https://github.com/mastodon/mastodon/pull/17589))
|
||||||
|
- Fix opening the emoji picker scrolling the single-column view to the top ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17579))
|
||||||
|
- Fix edge case where settings/admin page sidebar would be incorrectly hidden ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17580))
|
||||||
|
- Fix performance of server-side filtering ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17575))
|
||||||
|
- Fix privacy policy link not being visible on small screens ([Gargron](https://github.com/mastodon/mastodon/pull/17533))
|
||||||
|
- Fix duplicate accounts when searching by IP range in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/17524), [tribela](https://github.com/mastodon/mastodon/pull/17150))
|
||||||
|
- Fix error when performing a batch action on posts in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17532))
|
||||||
|
- Fix deletes not being signed in authorized fetch mode ([Gargron](https://github.com/mastodon/mastodon/pull/17484))
|
||||||
|
- Fix Undo Announce sometimes inlining the originally Announced status ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17516))
|
||||||
|
- Fix localization of cold-start follow recommendations ([Gargron](https://github.com/mastodon/mastodon/pull/17479), [Gargron](https://github.com/mastodon/mastodon/pull/17486))
|
||||||
|
- Fix replies collection incorrectly looping ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17462))
|
||||||
|
- Fix errors when multiple Delete are received for a given actor ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17460))
|
||||||
|
- Fixed prototype pollution bug and only allow trusted origin ([r0hanSH](https://github.com/mastodon/mastodon/pull/17420))
|
||||||
|
- Fix text being incorrectly pre-selected in composer textarea on /share ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17339))
|
||||||
|
- Fix SMTP_ENABLE_STARTTLS_AUTO/SMTP_TLS/SMTP_SSL environment variables don't work ([kgtkr](https://github.com/mastodon/mastodon/pull/17216))
|
||||||
|
- Fix media upload specific rate limits only being applied to v1 endpoint in REST API ([tribela](https://github.com/mastodon/mastodon/pull/17272))
|
||||||
|
- Fix media descriptions not being used for client-side filtering ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17206))
|
||||||
|
- Fix cold-start follow recommendation favouring older accounts due to wrong sorting ([noellabo](https://github.com/mastodon/mastodon/pull/17126))
|
||||||
|
- Fix not redirect to the right page after authenticating with WebAuthn ([heguro](https://github.com/mastodon/mastodon/pull/17098))
|
||||||
|
- Fix searching for additional hashtags in hashtag column ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17054))
|
||||||
|
- Fix color of hashtag column settings inputs ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17058))
|
||||||
|
- Fix performance of `tootctl statuses remove` ([noellabo](https://github.com/mastodon/mastodon/pull/17052))
|
||||||
|
- Fix `tootctl accounts cull` not excluding domains on timeouts and certificate issues ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16433))
|
||||||
|
- Fix 404 error when filtering admin action logs by non-existent target account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16643))
|
||||||
|
- Fix error when accessing streaming API without any OAuth scopes ([Brawaru](https://github.com/mastodon/mastodon/pull/16823))
|
||||||
|
- Fix follow request count not updating when new follow requests arrive over streaming API in web UI ([matildepark](https://github.com/mastodon/mastodon/pull/16652))
|
||||||
|
- Fix error when unsuspending a local account ([HolgerHuo](https://github.com/mastodon/mastodon/pull/16605))
|
||||||
|
- Fix crash when a notification contains a not yet processed media attachment in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16573))
|
||||||
|
- Fix wrong color of download button in audio player in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16572))
|
||||||
|
- Fix notes for others accounts not being deleted when an account is deleted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16579))
|
||||||
|
- Fix error when logging occurrence of unsupported video file ([noellabo](https://github.com/mastodon/mastodon/pull/16581))
|
||||||
|
- Fix wrong elements in trends widget being hidden on smaller screens in web UI ([tribela](https://github.com/mastodon/mastodon/pull/16570))
|
||||||
|
- Fix link to about page being displayed in limited federation mode ([weex](https://github.com/mastodon/mastodon/pull/16432))
|
||||||
|
- Fix styling of boost button in media modal not reflecting ability to boost ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16387))
|
||||||
|
- Fix OCR failure when erroneous lang data is in cache ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16386))
|
||||||
|
- Fix downloading media from blocked domains in `tootctl media refresh` ([tribela](https://github.com/mastodon/mastodon/pull/16914))
|
||||||
|
- Fix login form being displayed on landing page when already logged in ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17348))
|
||||||
|
- Fix polling for media processing status too frequently in web UI ([tribela](https://github.com/mastodon/mastodon/pull/17271))
|
||||||
|
- Fix hashtag autocomplete overriding user-typed case ([weex](https://github.com/mastodon/mastodon/pull/16460))
|
||||||
|
- Fix WebAuthn authentication setup to not prompt for PIN ([truongnmt](https://github.com/mastodon/mastodon/pull/16545))
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Fix being able to post URLs longer than 4096 characters ([Gargron](https://github.com/mastodon/mastodon/pull/17908))
|
||||||
|
- Fix being able to bypass e-mail restrictions ([Gargron](https://github.com/mastodon/mastodon/pull/17909))
|
||||||
|
|
||||||
## [3.4.6] - 2022-02-03
|
## [3.4.6] - 2022-02-03
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@ -87,7 +329,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Fix suspended accounts statuses being merged back into timelines ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16628))
|
- Fix suspended accounts statuses being merged back into timelines ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16628))
|
||||||
- Fix crash when encountering invalid account fields ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16598))
|
- Fix crash when encountering invalid account fields ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16598))
|
||||||
- Fix invalid blurhash handling for remote activities ([noellabo](https://github.com/mastodon/mastodon/pull/16583))
|
- Fix invalid blurhash handling for remote activities ([noellabo](https://github.com/mastodon/mastodon/pull/16583))
|
||||||
- Fix newlines being added to accout notes when an account moves ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16415), [noellabo](https://github.com/mastodon/mastodon/pull/16576))
|
- Fix newlines being added to account notes when an account moves ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16415), [noellabo](https://github.com/mastodon/mastodon/pull/16576))
|
||||||
- Fix crash when creating an announcement with links ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16941))
|
- Fix crash when creating an announcement with links ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16941))
|
||||||
- Fix logging out from one browser logging out all other sessions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16943))
|
- Fix logging out from one browser logging out all other sessions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16943))
|
||||||
|
|
||||||
@ -420,7 +662,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Fix inefficiency when fetching bookmarks ([akihikodaki](https://github.com/mastodon/mastodon/pull/14674))
|
- Fix inefficiency when fetching bookmarks ([akihikodaki](https://github.com/mastodon/mastodon/pull/14674))
|
||||||
- Fix inefficiency when fetching favourites ([akihikodaki](https://github.com/mastodon/mastodon/pull/14673))
|
- Fix inefficiency when fetching favourites ([akihikodaki](https://github.com/mastodon/mastodon/pull/14673))
|
||||||
- Fix inefficiency when fetching media-only account timeline ([akihikodaki](https://github.com/mastodon/mastodon/pull/14675))
|
- Fix inefficiency when fetching media-only account timeline ([akihikodaki](https://github.com/mastodon/mastodon/pull/14675))
|
||||||
- Fix inefficieny when deleting accounts ([Gargron](https://github.com/mastodon/mastodon/pull/15387), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15409), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15407), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15408), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15402), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15416), [Gargron](https://github.com/mastodon/mastodon/pull/15421))
|
- Fix inefficiency when deleting accounts ([Gargron](https://github.com/mastodon/mastodon/pull/15387), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15409), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15407), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15408), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15402), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15416), [Gargron](https://github.com/mastodon/mastodon/pull/15421))
|
||||||
- Fix redundant query when processing batch actions on custom emojis ([niwatori24](https://github.com/mastodon/mastodon/pull/14534))
|
- Fix redundant query when processing batch actions on custom emojis ([niwatori24](https://github.com/mastodon/mastodon/pull/14534))
|
||||||
- Fix slow distinct queries where grouped queries are faster ([Gargron](https://github.com/mastodon/mastodon/pull/15287))
|
- Fix slow distinct queries where grouped queries are faster ([Gargron](https://github.com/mastodon/mastodon/pull/15287))
|
||||||
- Fix performance on instances list in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/15282))
|
- Fix performance on instances list in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/15282))
|
||||||
@ -507,7 +749,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Add blurhash to link previews ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13984), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14143), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13985), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/14267), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/14278), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14126), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14261), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14260))
|
- Add blurhash to link previews ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13984), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14143), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13985), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/14267), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/14278), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14126), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14261), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14260))
|
||||||
- In web UI, toots cannot be marked as sensitive unless there is media attached
|
- In web UI, toots cannot be marked as sensitive unless there is media attached
|
||||||
- However, it's possible to do via API or ActivityPub
|
- However, it's possible to do via API or ActivityPub
|
||||||
- Thumnails of link previews of such posts now use blurhash in web UI
|
- Thumbnails of link previews of such posts now use blurhash in web UI
|
||||||
- The Card entity in REST API has a new `blurhash` attribute
|
- The Card entity in REST API has a new `blurhash` attribute
|
||||||
- Add support for `summary` field for media description in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13763))
|
- Add support for `summary` field for media description in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13763))
|
||||||
- Add hints about incomplete remote content to web UI ([Gargron](https://github.com/mastodon/mastodon/pull/14031), [noellabo](https://github.com/mastodon/mastodon/pull/14195))
|
- Add hints about incomplete remote content to web UI ([Gargron](https://github.com/mastodon/mastodon/pull/14031), [noellabo](https://github.com/mastodon/mastodon/pull/14195))
|
||||||
@ -530,7 +772,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- The `meta` attribute on the Media Attachment entity in REST API can now have a `colors` attribute which in turn contains three hex colors: `background`, `foreground`, and `accent`
|
- The `meta` attribute on the Media Attachment entity in REST API can now have a `colors` attribute which in turn contains three hex colors: `background`, `foreground`, and `accent`
|
||||||
- The background color is chosen from the most dominant color around the edges of the thumbnail
|
- The background color is chosen from the most dominant color around the edges of the thumbnail
|
||||||
- The foreground and accent colors are chosen from the colors that are the most different from the background color using the CIEDE2000 algorithm
|
- The foreground and accent colors are chosen from the colors that are the most different from the background color using the CIEDE2000 algorithm
|
||||||
- The most satured color of the two is designated as the accent color
|
- The most saturated color of the two is designated as the accent color
|
||||||
- The one with the highest W3C contrast is designated as the foreground color
|
- The one with the highest W3C contrast is designated as the foreground color
|
||||||
- If there are not enough colors in the thumbnail, new ones are generated using a monochrome pattern
|
- If there are not enough colors in the thumbnail, new ones are generated using a monochrome pattern
|
||||||
- Add a visibility indicator to toots in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/14123), [highemerly](https://github.com/mastodon/mastodon/pull/14292))
|
- Add a visibility indicator to toots in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/14123), [highemerly](https://github.com/mastodon/mastodon/pull/14292))
|
||||||
@ -556,7 +798,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Change boost button to no longer serve as visibility indicator in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/14132), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14373))
|
- Change boost button to no longer serve as visibility indicator in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/14132), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14373))
|
||||||
- Change contrast of flash messages ([cchoi12](https://github.com/mastodon/mastodon/pull/13892))
|
- Change contrast of flash messages ([cchoi12](https://github.com/mastodon/mastodon/pull/13892))
|
||||||
- Change wording from "Hide media" to "Hide image/images" in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13834))
|
- Change wording from "Hide media" to "Hide image/images" in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13834))
|
||||||
- Change appearence of settings pages to be more consistent ([ariasuni](https://github.com/mastodon/mastodon/pull/13938))
|
- Change appearance of settings pages to be more consistent ([ariasuni](https://github.com/mastodon/mastodon/pull/13938))
|
||||||
- Change "Add media" tooltip to not include long list of formats in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13954))
|
- Change "Add media" tooltip to not include long list of formats in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13954))
|
||||||
- Change how badly contrasting emoji are rendered in web UI ([leo60228](https://github.com/mastodon/mastodon/pull/13773), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13772), [mfmfuyu](https://github.com/mastodon/mastodon/pull/14020), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14015))
|
- Change how badly contrasting emoji are rendered in web UI ([leo60228](https://github.com/mastodon/mastodon/pull/13773), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13772), [mfmfuyu](https://github.com/mastodon/mastodon/pull/14020), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14015))
|
||||||
- Change structure of unavailable content section on about page ([ariasuni](https://github.com/mastodon/mastodon/pull/13930))
|
- Change structure of unavailable content section on about page ([ariasuni](https://github.com/mastodon/mastodon/pull/13930))
|
||||||
@ -572,14 +814,14 @@ All notable changes to this project will be documented in this file.
|
|||||||
- `EMAIL_DOMAIN_WHITELIST` → `EMAIL_DOMAIN_ALLOWLIST`
|
- `EMAIL_DOMAIN_WHITELIST` → `EMAIL_DOMAIN_ALLOWLIST`
|
||||||
- CLI option changed:
|
- CLI option changed:
|
||||||
- `tootctl domains purge --whitelist-mode` → `tootctl domains purge --limited-federation-mode`
|
- `tootctl domains purge --whitelist-mode` → `tootctl domains purge --limited-federation-mode`
|
||||||
- Remove some unnecessary database indices ([lfuelling](https://github.com/mastodon/mastodon/pull/13695), [noellabo](https://github.com/mastodon/mastodon/pull/14259))
|
- Remove some unnecessary database indexes ([lfuelling](https://github.com/mastodon/mastodon/pull/13695), [noellabo](https://github.com/mastodon/mastodon/pull/14259))
|
||||||
- Remove unnecessary Node.js version upper bound ([ykzts](https://github.com/mastodon/mastodon/pull/14139))
|
- Remove unnecessary Node.js version upper bound ([ykzts](https://github.com/mastodon/mastodon/pull/14139))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fix `following` param not working when exact match is found in account search ([noellabo](https://github.com/mastodon/mastodon/pull/14394))
|
- Fix `following` param not working when exact match is found in account search ([noellabo](https://github.com/mastodon/mastodon/pull/14394))
|
||||||
- Fix sometimes occuring duplicate mention notifications ([noellabo](https://github.com/mastodon/mastodon/pull/14378))
|
- Fix sometimes occurring duplicate mention notifications ([noellabo](https://github.com/mastodon/mastodon/pull/14378))
|
||||||
- Fix RSS feeds not being cachable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14368))
|
- Fix RSS feeds not being cacheable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14368))
|
||||||
- Fix lack of locking around processing of Announce activities in ActivityPub ([noellabo](https://github.com/mastodon/mastodon/pull/14365))
|
- Fix lack of locking around processing of Announce activities in ActivityPub ([noellabo](https://github.com/mastodon/mastodon/pull/14365))
|
||||||
- Fix boosted toots from blocked account not being retroactively removed from TL ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14339))
|
- Fix boosted toots from blocked account not being retroactively removed from TL ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14339))
|
||||||
- Fix large shortened numbers (like 1.2K) using incorrect pluralization ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/14061))
|
- Fix large shortened numbers (like 1.2K) using incorrect pluralization ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/14061))
|
||||||
@ -591,7 +833,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Fix new posts pushing down origin of opened dropdown in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14271), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14348))
|
- Fix new posts pushing down origin of opened dropdown in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14271), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14348))
|
||||||
- Fix timeline markers not being saved sometimes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13887), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13889), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14155))
|
- Fix timeline markers not being saved sometimes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13887), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13889), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14155))
|
||||||
- Fix CSV uploads being rejected ([noellabo](https://github.com/mastodon/mastodon/pull/13835))
|
- Fix CSV uploads being rejected ([noellabo](https://github.com/mastodon/mastodon/pull/13835))
|
||||||
- Fix incompatibility with ElasticSearch 7.x ([noellabo](https://github.com/mastodon/mastodon/pull/13828))
|
- Fix incompatibility with Elasticsearch 7.x ([noellabo](https://github.com/mastodon/mastodon/pull/13828))
|
||||||
- Fix being able to search posts where you're in the target audience but not actively mentioned ([noellabo](https://github.com/mastodon/mastodon/pull/13829))
|
- Fix being able to search posts where you're in the target audience but not actively mentioned ([noellabo](https://github.com/mastodon/mastodon/pull/13829))
|
||||||
- Fix non-local posts appearing on local-only hashtag timelines in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/13827))
|
- Fix non-local posts appearing on local-only hashtag timelines in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/13827))
|
||||||
- Fix `tootctl media remove-orphans` choking on unknown files in storage ([Gargron](https://github.com/mastodon/mastodon/pull/13765))
|
- Fix `tootctl media remove-orphans` choking on unknown files in storage ([Gargron](https://github.com/mastodon/mastodon/pull/13765))
|
||||||
@ -706,7 +948,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Fix poll refresh button not being debounced in web UI ([rasjonell](https://github.com/mastodon/mastodon/pull/13485), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13490))
|
- Fix poll refresh button not being debounced in web UI ([rasjonell](https://github.com/mastodon/mastodon/pull/13485), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13490))
|
||||||
- Fix confusing error when failing to add an alias to an unknown account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13480))
|
- Fix confusing error when failing to add an alias to an unknown account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13480))
|
||||||
- Fix "Email changed" notification sometimes having wrong e-mail ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13475))
|
- Fix "Email changed" notification sometimes having wrong e-mail ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13475))
|
||||||
- Fix varioues issues on the account aliases page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13452))
|
- Fix various issues on the account aliases page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13452))
|
||||||
- Fix API footer link in web UI ([bubblineyuri](https://github.com/mastodon/mastodon/pull/13441))
|
- Fix API footer link in web UI ([bubblineyuri](https://github.com/mastodon/mastodon/pull/13441))
|
||||||
- Fix pagination of following, followers, follow requests, blocks and mutes lists in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13445))
|
- Fix pagination of following, followers, follow requests, blocks and mutes lists in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13445))
|
||||||
- Fix styling of polls in JS-less fallback on public pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13436))
|
- Fix styling of polls in JS-less fallback on public pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13436))
|
||||||
@ -1195,7 +1437,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Fix URLs appearing twice in errors of ActivityPub::DeliveryWorker ([Gargron](https://github.com/mastodon/mastodon/pull/11231))
|
- Fix URLs appearing twice in errors of ActivityPub::DeliveryWorker ([Gargron](https://github.com/mastodon/mastodon/pull/11231))
|
||||||
- Fix support for HTTP proxies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11245))
|
- Fix support for HTTP proxies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11245))
|
||||||
- Fix HTTP requests to IPv6 hosts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11240))
|
- Fix HTTP requests to IPv6 hosts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11240))
|
||||||
- Fix error in ElasticSearch index import ([mayaeh](https://github.com/mastodon/mastodon/pull/11192))
|
- Fix error in Elasticsearch index import ([mayaeh](https://github.com/mastodon/mastodon/pull/11192))
|
||||||
- Fix duplicate account error when seeding development database ([ysksn](https://github.com/mastodon/mastodon/pull/11366))
|
- Fix duplicate account error when seeding development database ([ysksn](https://github.com/mastodon/mastodon/pull/11366))
|
||||||
- Fix performance of session clean-up scheduler ([abcang](https://github.com/mastodon/mastodon/pull/11871))
|
- Fix performance of session clean-up scheduler ([abcang](https://github.com/mastodon/mastodon/pull/11871))
|
||||||
- Fix older migrations not running ([zunda](https://github.com/mastodon/mastodon/pull/11377))
|
- Fix older migrations not running ([zunda](https://github.com/mastodon/mastodon/pull/11377))
|
||||||
@ -1205,8 +1447,8 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Fix muted text color not applying to all text ([trwnh](https://github.com/mastodon/mastodon/pull/11996))
|
- Fix muted text color not applying to all text ([trwnh](https://github.com/mastodon/mastodon/pull/11996))
|
||||||
- Fix follower/following lists resetting on back-navigation in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11986))
|
- Fix follower/following lists resetting on back-navigation in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11986))
|
||||||
- Fix n+1 query when approving multiple follow requests ([abcang](https://github.com/mastodon/mastodon/pull/12004))
|
- Fix n+1 query when approving multiple follow requests ([abcang](https://github.com/mastodon/mastodon/pull/12004))
|
||||||
- Fix records not being indexed into ElasticSearch sometimes ([Gargron](https://github.com/mastodon/mastodon/pull/12024))
|
- Fix records not being indexed into Elasticsearch sometimes ([Gargron](https://github.com/mastodon/mastodon/pull/12024))
|
||||||
- Fix needlessly indexing unsearchable statuses into ElasticSearch ([Gargron](https://github.com/mastodon/mastodon/pull/12041))
|
- Fix needlessly indexing unsearchable statuses into Elasticsearch ([Gargron](https://github.com/mastodon/mastodon/pull/12041))
|
||||||
- Fix new user bootstrapping crashing when to-be-followed accounts are invalid ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12037))
|
- Fix new user bootstrapping crashing when to-be-followed accounts are invalid ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12037))
|
||||||
- Fix featured hashtag URL being interpreted as media or replies tab ([Gargron](https://github.com/mastodon/mastodon/pull/12048))
|
- Fix featured hashtag URL being interpreted as media or replies tab ([Gargron](https://github.com/mastodon/mastodon/pull/12048))
|
||||||
- Fix account counters being overwritten by parallel writes ([Gargron](https://github.com/mastodon/mastodon/pull/12045))
|
- Fix account counters being overwritten by parallel writes ([Gargron](https://github.com/mastodon/mastodon/pull/12045))
|
||||||
@ -1496,7 +1738,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Change Docker image to use Ubuntu with jemalloc ([Sir-Boops](https://github.com/mastodon/mastodon/pull/10100), [BenLubar](https://github.com/mastodon/mastodon/pull/10212))
|
- Change Docker image to use Ubuntu with jemalloc ([Sir-Boops](https://github.com/mastodon/mastodon/pull/10100), [BenLubar](https://github.com/mastodon/mastodon/pull/10212))
|
||||||
- Change public pages to be cacheable by proxies ([BenLubar](https://github.com/mastodon/mastodon/pull/9059))
|
- Change public pages to be cacheable by proxies ([BenLubar](https://github.com/mastodon/mastodon/pull/9059))
|
||||||
- Change the 410 gone response for suspended accounts to be cacheable by proxies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10339))
|
- Change the 410 gone response for suspended accounts to be cacheable by proxies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10339))
|
||||||
- Change web UI to not not empty timeline of blocked users on block ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10359))
|
- Change web UI to not empty timeline of blocked users on block ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10359))
|
||||||
- Change JSON serializer to remove unused `@context` values ([Gargron](https://github.com/mastodon/mastodon/pull/10378))
|
- Change JSON serializer to remove unused `@context` values ([Gargron](https://github.com/mastodon/mastodon/pull/10378))
|
||||||
- Change GIFV file size limit to be the same as for other videos ([rinsuki](https://github.com/mastodon/mastodon/pull/9924))
|
- Change GIFV file size limit to be the same as for other videos ([rinsuki](https://github.com/mastodon/mastodon/pull/9924))
|
||||||
- Change Webpack to not use @babel/preset-env to compile node_modules ([ykzts](https://github.com/mastodon/mastodon/pull/10289))
|
- Change Webpack to not use @babel/preset-env to compile node_modules ([ykzts](https://github.com/mastodon/mastodon/pull/10289))
|
||||||
@ -1673,7 +1915,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Limit maximum visibility of local silenced users to unlisted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9583))
|
- Limit maximum visibility of local silenced users to unlisted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9583))
|
||||||
- Change API error message for unconfirmed accounts ([noellabo](https://github.com/mastodon/mastodon/pull/9625))
|
- Change API error message for unconfirmed accounts ([noellabo](https://github.com/mastodon/mastodon/pull/9625))
|
||||||
- Change the icon to "reply-all" when it's a reply to other accounts ([mayaeh](https://github.com/mastodon/mastodon/pull/9378))
|
- Change the icon to "reply-all" when it's a reply to other accounts ([mayaeh](https://github.com/mastodon/mastodon/pull/9378))
|
||||||
- Do not ignore federated reports targetting already-reported accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9534))
|
- Do not ignore federated reports targeting already-reported accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9534))
|
||||||
- Upgrade default Ruby version to 2.6.0 ([Gargron](https://github.com/mastodon/mastodon/pull/9688))
|
- Upgrade default Ruby version to 2.6.0 ([Gargron](https://github.com/mastodon/mastodon/pull/9688))
|
||||||
- Change e-mail digest frequency ([Gargron](https://github.com/mastodon/mastodon/pull/9689))
|
- Change e-mail digest frequency ([Gargron](https://github.com/mastodon/mastodon/pull/9689))
|
||||||
- Change Docker images for Tor support in docker-compose.yml ([Sir-Boops](https://github.com/mastodon/mastodon/pull/9438))
|
- Change Docker images for Tor support in docker-compose.yml ([Sir-Boops](https://github.com/mastodon/mastodon/pull/9438))
|
||||||
|
@ -5,7 +5,7 @@ SHELL ["/bin/bash", "-c"]
|
|||||||
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
|
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
|
||||||
|
|
||||||
# Install Node v16 (LTS)
|
# Install Node v16 (LTS)
|
||||||
ENV NODE_VER="16.13.2"
|
ENV NODE_VER="16.14.2"
|
||||||
RUN ARCH= && \
|
RUN ARCH= && \
|
||||||
dpkgArch="$(dpkg --print-architecture)" && \
|
dpkgArch="$(dpkg --print-architecture)" && \
|
||||||
case "${dpkgArch##*-}" in \
|
case "${dpkgArch##*-}" in \
|
||||||
|
27
Gemfile
27
Gemfile
@ -7,7 +7,7 @@ gem 'pkg-config', '~> 1.4'
|
|||||||
gem 'rexml', '~> 3.2'
|
gem 'rexml', '~> 3.2'
|
||||||
|
|
||||||
gem 'puma', '~> 5.6'
|
gem 'puma', '~> 5.6'
|
||||||
gem 'rails', '~> 6.1.4'
|
gem 'rails', '~> 6.1.5'
|
||||||
gem 'sprockets', '~> 3.7.2'
|
gem 'sprockets', '~> 3.7.2'
|
||||||
gem 'thor', '~> 1.2'
|
gem 'thor', '~> 1.2'
|
||||||
gem 'rack', '~> 2.2.3'
|
gem 'rack', '~> 2.2.3'
|
||||||
@ -26,7 +26,7 @@ gem 'blurhash', '~> 0.1'
|
|||||||
|
|
||||||
gem 'active_model_serializers', '~> 0.10'
|
gem 'active_model_serializers', '~> 0.10'
|
||||||
gem 'addressable', '~> 2.8'
|
gem 'addressable', '~> 2.8'
|
||||||
gem 'bootsnap', '~> 1.10.3', require: false
|
gem 'bootsnap', '~> 1.11.1', require: false
|
||||||
gem 'browser'
|
gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.7'
|
gem 'charlock_holmes', '~> 0.7.7'
|
||||||
gem 'chewy', '~> 7.2'
|
gem 'chewy', '~> 7.2'
|
||||||
@ -40,6 +40,7 @@ end
|
|||||||
gem 'net-ldap', '~> 0.17'
|
gem 'net-ldap', '~> 0.17'
|
||||||
gem 'omniauth-cas', '~> 2.0'
|
gem 'omniauth-cas', '~> 2.0'
|
||||||
gem 'omniauth-saml', '~> 1.10'
|
gem 'omniauth-saml', '~> 1.10'
|
||||||
|
gem 'gitlab-omniauth-openid-connect', '~>0.9.1', require: 'omniauth_openid_connect'
|
||||||
gem 'omniauth', '~> 1.9'
|
gem 'omniauth', '~> 1.9'
|
||||||
gem 'omniauth-rails_csrf_protection', '~> 0.1'
|
gem 'omniauth-rails_csrf_protection', '~> 0.1'
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ gem 'parslet'
|
|||||||
gem 'posix-spawn'
|
gem 'posix-spawn'
|
||||||
gem 'pundit', '~> 2.2'
|
gem 'pundit', '~> 2.2'
|
||||||
gem 'premailer-rails'
|
gem 'premailer-rails'
|
||||||
gem 'rack-attack', '~> 6.5'
|
gem 'rack-attack', '~> 6.6'
|
||||||
gem 'rack-cors', '~> 1.1', require: 'rack/cors'
|
gem 'rack-cors', '~> 1.1', require: 'rack/cors'
|
||||||
gem 'rails-i18n', '~> 6.0'
|
gem 'rails-i18n', '~> 6.0'
|
||||||
gem 'rails-settings-cached', '~> 0.6'
|
gem 'rails-settings-cached', '~> 0.6'
|
||||||
@ -78,7 +79,7 @@ gem 'ruby-progressbar', '~> 1.11'
|
|||||||
gem 'sanitize', '~> 6.0'
|
gem 'sanitize', '~> 6.0'
|
||||||
gem 'scenic', '~> 1.6'
|
gem 'scenic', '~> 1.6'
|
||||||
gem 'sidekiq', '~> 6.4'
|
gem 'sidekiq', '~> 6.4'
|
||||||
gem 'sidekiq-scheduler', '~> 3.1'
|
gem 'sidekiq-scheduler', '~> 3.2'
|
||||||
gem 'sidekiq-unique-jobs', '~> 7.1'
|
gem 'sidekiq-unique-jobs', '~> 7.1'
|
||||||
gem 'sidekiq-bulk', '~>0.2.0'
|
gem 'sidekiq-bulk', '~>0.2.0'
|
||||||
gem 'simple-navigation', '~> 4.3'
|
gem 'simple-navigation', '~> 4.3'
|
||||||
@ -88,7 +89,7 @@ gem 'stoplight', '~> 2.2.1'
|
|||||||
gem 'strong_migrations', '~> 0.7'
|
gem 'strong_migrations', '~> 0.7'
|
||||||
gem 'tty-prompt', '~> 0.23', require: false
|
gem 'tty-prompt', '~> 0.23', require: false
|
||||||
gem 'twitter-text', '~> 3.1.0'
|
gem 'twitter-text', '~> 3.1.0'
|
||||||
gem 'tzinfo-data', '~> 1.2021'
|
gem 'tzinfo-data', '~> 1.2022'
|
||||||
gem 'webpacker', '~> 5.4'
|
gem 'webpacker', '~> 5.4'
|
||||||
gem 'webpush', '~> 0.3'
|
gem 'webpush', '~> 0.3'
|
||||||
gem 'webauthn', '~> 3.0.0.alpha1'
|
gem 'webauthn', '~> 3.0.0.alpha1'
|
||||||
@ -98,9 +99,9 @@ gem 'json-ld-preloaded', '~> 3.2'
|
|||||||
gem 'rdf-normalize', '~> 0.5'
|
gem 'rdf-normalize', '~> 0.5'
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'fabrication', '~> 2.27'
|
gem 'fabrication', '~> 2.28'
|
||||||
gem 'fuubar', '~> 2.5'
|
gem 'fuubar', '~> 2.5'
|
||||||
gem 'i18n-tasks', '~> 0.9', require: false
|
gem 'i18n-tasks', '~> 1.0', require: false
|
||||||
gem 'pry-byebug', '~> 3.9'
|
gem 'pry-byebug', '~> 3.9'
|
||||||
gem 'pry-rails', '~> 0.3'
|
gem 'pry-rails', '~> 0.3'
|
||||||
gem 'rspec-rails', '~> 5.1'
|
gem 'rspec-rails', '~> 5.1'
|
||||||
@ -113,7 +114,7 @@ end
|
|||||||
group :test do
|
group :test do
|
||||||
gem 'capybara', '~> 3.36'
|
gem 'capybara', '~> 3.36'
|
||||||
gem 'climate_control', '~> 0.2'
|
gem 'climate_control', '~> 0.2'
|
||||||
gem 'faker', '~> 2.19'
|
gem 'faker', '~> 2.20'
|
||||||
gem 'microformats', '~> 4.2'
|
gem 'microformats', '~> 4.2'
|
||||||
gem 'rails-controller-testing', '~> 1.0'
|
gem 'rails-controller-testing', '~> 1.0'
|
||||||
gem 'rspec-sidekiq', '~> 3.1'
|
gem 'rspec-sidekiq', '~> 3.1'
|
||||||
@ -128,15 +129,15 @@ group :development do
|
|||||||
gem 'better_errors', '~> 2.9'
|
gem 'better_errors', '~> 2.9'
|
||||||
gem 'binding_of_caller', '~> 1.0'
|
gem 'binding_of_caller', '~> 1.0'
|
||||||
gem 'bullet', '~> 7.0'
|
gem 'bullet', '~> 7.0'
|
||||||
gem 'letter_opener', '~> 1.7'
|
gem 'letter_opener', '~> 1.8'
|
||||||
gem 'letter_opener_web', '~> 2.0'
|
gem 'letter_opener_web', '~> 2.0'
|
||||||
gem 'memory_profiler'
|
gem 'memory_profiler'
|
||||||
gem 'rubocop', '~> 1.25', require: false
|
gem 'rubocop', '~> 1.27', require: false
|
||||||
gem 'rubocop-rails', '~> 2.13', require: false
|
gem 'rubocop-rails', '~> 2.14', require: false
|
||||||
gem 'brakeman', '~> 5.2', require: false
|
gem 'brakeman', '~> 5.2', require: false
|
||||||
gem 'bundler-audit', '~> 0.9', require: false
|
gem 'bundler-audit', '~> 0.9', require: false
|
||||||
|
|
||||||
gem 'capistrano', '~> 3.16'
|
gem 'capistrano', '~> 3.17'
|
||||||
gem 'capistrano-rails', '~> 1.6'
|
gem 'capistrano-rails', '~> 1.6'
|
||||||
gem 'capistrano-rbenv', '~> 2.2'
|
gem 'capistrano-rbenv', '~> 2.2'
|
||||||
gem 'capistrano-yarn', '~> 2.0'
|
gem 'capistrano-yarn', '~> 2.0'
|
||||||
@ -145,7 +146,7 @@ group :development do
|
|||||||
end
|
end
|
||||||
|
|
||||||
group :production do
|
group :production do
|
||||||
gem 'lograge', '~> 0.11'
|
gem 'lograge', '~> 0.12'
|
||||||
end
|
end
|
||||||
|
|
||||||
gem 'concurrent-ruby', require: false
|
gem 'concurrent-ruby', require: false
|
||||||
|
288
Gemfile.lock
288
Gemfile.lock
@ -1,40 +1,40 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.1.4.6)
|
actioncable (6.1.5)
|
||||||
actionpack (= 6.1.4.6)
|
actionpack (= 6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.1.4.6)
|
actionmailbox (6.1.5)
|
||||||
actionpack (= 6.1.4.6)
|
actionpack (= 6.1.5)
|
||||||
activejob (= 6.1.4.6)
|
activejob (= 6.1.5)
|
||||||
activerecord (= 6.1.4.6)
|
activerecord (= 6.1.5)
|
||||||
activestorage (= 6.1.4.6)
|
activestorage (= 6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.1.4.6)
|
actionmailer (6.1.5)
|
||||||
actionpack (= 6.1.4.6)
|
actionpack (= 6.1.5)
|
||||||
actionview (= 6.1.4.6)
|
actionview (= 6.1.5)
|
||||||
activejob (= 6.1.4.6)
|
activejob (= 6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (6.1.4.6)
|
actionpack (6.1.5)
|
||||||
actionview (= 6.1.4.6)
|
actionview (= 6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
rack (~> 2.0, >= 2.0.9)
|
rack (~> 2.0, >= 2.0.9)
|
||||||
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.2.0)
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||||
actiontext (6.1.4.6)
|
actiontext (6.1.5)
|
||||||
actionpack (= 6.1.4.6)
|
actionpack (= 6.1.5)
|
||||||
activerecord (= 6.1.4.6)
|
activerecord (= 6.1.5)
|
||||||
activestorage (= 6.1.4.6)
|
activestorage (= 6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.1.4.6)
|
actionview (6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
@ -45,22 +45,22 @@ GEM
|
|||||||
case_transform (>= 0.2)
|
case_transform (>= 0.2)
|
||||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||||
active_record_query_trace (1.8)
|
active_record_query_trace (1.8)
|
||||||
activejob (6.1.4.6)
|
activejob (6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.1.4.6)
|
activemodel (6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
activerecord (6.1.4.6)
|
activerecord (6.1.5)
|
||||||
activemodel (= 6.1.4.6)
|
activemodel (= 6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
activestorage (6.1.4.6)
|
activestorage (6.1.5)
|
||||||
actionpack (= 6.1.4.6)
|
actionpack (= 6.1.5)
|
||||||
activejob (= 6.1.4.6)
|
activejob (= 6.1.5)
|
||||||
activerecord (= 6.1.4.6)
|
activerecord (= 6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
marcel (~> 1.0.0)
|
marcel (~> 1.0)
|
||||||
mini_mime (>= 1.1.0)
|
mini_mime (>= 1.1.0)
|
||||||
activesupport (6.1.4.6)
|
activesupport (6.1.5)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
@ -68,6 +68,7 @@ GEM
|
|||||||
zeitwerk (~> 2.3)
|
zeitwerk (~> 2.3)
|
||||||
addressable (2.8.0)
|
addressable (2.8.0)
|
||||||
public_suffix (>= 2.0.2, < 5.0)
|
public_suffix (>= 2.0.2, < 5.0)
|
||||||
|
aes_key_wrap (1.1.0)
|
||||||
airbrussh (1.4.0)
|
airbrussh (1.4.0)
|
||||||
sshkit (>= 1.6.1, != 1.7.0)
|
sshkit (>= 1.6.1, != 1.7.0)
|
||||||
android_key_attestation (0.3.0)
|
android_key_attestation (0.3.0)
|
||||||
@ -77,36 +78,45 @@ GEM
|
|||||||
ast (2.4.2)
|
ast (2.4.2)
|
||||||
attr_encrypted (3.1.0)
|
attr_encrypted (3.1.0)
|
||||||
encryptor (~> 3.0.0)
|
encryptor (~> 3.0.0)
|
||||||
|
attr_required (1.0.1)
|
||||||
awrence (1.1.1)
|
awrence (1.1.1)
|
||||||
aws-eventstream (1.2.0)
|
aws-eventstream (1.2.0)
|
||||||
aws-partitions (1.558.0)
|
aws-partitions (1.579.0)
|
||||||
aws-sdk-core (3.127.0)
|
aws-sdk-core (3.130.2)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
aws-partitions (~> 1, >= 1.525.0)
|
aws-partitions (~> 1, >= 1.525.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
jmespath (~> 1.0)
|
jmespath (~> 1.0)
|
||||||
aws-sdk-kms (1.55.0)
|
aws-sdk-kms (1.56.0)
|
||||||
aws-sdk-core (~> 3, >= 3.127.0)
|
aws-sdk-core (~> 3, >= 3.127.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sdk-s3 (1.113.0)
|
aws-sdk-s3 (1.113.1)
|
||||||
aws-sdk-core (~> 3, >= 3.127.0)
|
aws-sdk-core (~> 3, >= 3.127.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.4)
|
aws-sigv4 (~> 1.4)
|
||||||
aws-sigv4 (1.4.0)
|
aws-sigv4 (1.5.0)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
bcrypt (3.1.16)
|
bcrypt (3.1.17)
|
||||||
better_errors (2.9.1)
|
better_errors (2.9.1)
|
||||||
coderay (>= 1.0.0)
|
coderay (>= 1.0.0)
|
||||||
erubi (>= 1.0.0)
|
erubi (>= 1.0.0)
|
||||||
rack (>= 0.9.0)
|
rack (>= 0.9.0)
|
||||||
|
better_html (1.0.16)
|
||||||
|
actionview (>= 4.0)
|
||||||
|
activesupport (>= 4.0)
|
||||||
|
ast (~> 2.0)
|
||||||
|
erubi (~> 1.4)
|
||||||
|
html_tokenizer (~> 0.0.6)
|
||||||
|
parser (>= 2.4)
|
||||||
|
smart_properties
|
||||||
bindata (2.4.10)
|
bindata (2.4.10)
|
||||||
binding_of_caller (1.0.0)
|
binding_of_caller (1.0.0)
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
blurhash (0.1.5)
|
blurhash (0.1.6)
|
||||||
ffi (~> 1.14)
|
ffi (~> 1.14)
|
||||||
bootsnap (1.10.3)
|
bootsnap (1.11.1)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (5.2.1)
|
brakeman (5.2.2)
|
||||||
browser (4.2.0)
|
browser (4.2.0)
|
||||||
brpoplpush-redis_script (0.1.2)
|
brpoplpush-redis_script (0.1.2)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.5)
|
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||||
@ -119,14 +129,14 @@ GEM
|
|||||||
bundler (>= 1.2.0, < 3)
|
bundler (>= 1.2.0, < 3)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
byebug (11.1.3)
|
byebug (11.1.3)
|
||||||
capistrano (3.16.0)
|
capistrano (3.17.0)
|
||||||
airbrussh (>= 1.0.0)
|
airbrussh (>= 1.0.0)
|
||||||
i18n
|
i18n
|
||||||
rake (>= 10.0.0)
|
rake (>= 10.0.0)
|
||||||
sshkit (>= 1.9.0)
|
sshkit (>= 1.9.0)
|
||||||
capistrano-bundler (2.0.1)
|
capistrano-bundler (2.0.1)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
capistrano-rails (1.6.1)
|
capistrano-rails (1.6.2)
|
||||||
capistrano (~> 3.1)
|
capistrano (~> 3.1)
|
||||||
capistrano-bundler (>= 1.1, < 3)
|
capistrano-bundler (>= 1.1, < 3)
|
||||||
capistrano-rbenv (2.2.0)
|
capistrano-rbenv (2.2.0)
|
||||||
@ -155,7 +165,7 @@ GEM
|
|||||||
climate_control (0.2.0)
|
climate_control (0.2.0)
|
||||||
coderay (1.1.3)
|
coderay (1.1.3)
|
||||||
color_diff (0.1)
|
color_diff (0.1)
|
||||||
concurrent-ruby (1.1.9)
|
concurrent-ruby (1.1.10)
|
||||||
connection_pool (2.2.5)
|
connection_pool (2.2.5)
|
||||||
cose (1.0.0)
|
cose (1.0.0)
|
||||||
cbor (~> 0.5.9)
|
cbor (~> 0.5.9)
|
||||||
@ -172,11 +182,11 @@ GEM
|
|||||||
railties (>= 4.1.0)
|
railties (>= 4.1.0)
|
||||||
responders
|
responders
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
devise-two-factor (4.0.1)
|
devise-two-factor (4.0.2)
|
||||||
activesupport (< 6.2)
|
activesupport (< 7.1)
|
||||||
attr_encrypted (>= 1.3, < 4, != 2)
|
attr_encrypted (>= 1.3, < 4, != 2)
|
||||||
devise (~> 4.0)
|
devise (~> 4.0)
|
||||||
railties (< 6.2)
|
railties (< 7.1)
|
||||||
rotp (~> 6.0)
|
rotp (~> 6.0)
|
||||||
devise_pam_authenticatable2 (9.2.0)
|
devise_pam_authenticatable2 (9.2.0)
|
||||||
devise (>= 4.0.0)
|
devise (>= 4.0.0)
|
||||||
@ -206,12 +216,12 @@ GEM
|
|||||||
multi_json
|
multi_json
|
||||||
encryptor (3.0.0)
|
encryptor (3.0.0)
|
||||||
erubi (1.10.0)
|
erubi (1.10.0)
|
||||||
et-orbi (1.2.6)
|
et-orbi (1.2.7)
|
||||||
tzinfo
|
tzinfo
|
||||||
excon (0.76.0)
|
excon (0.76.0)
|
||||||
fabrication (2.27.0)
|
fabrication (2.28.0)
|
||||||
faker (2.19.0)
|
faker (2.20.0)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
faraday (1.9.3)
|
faraday (1.9.3)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-em_http (~> 1.0)
|
||||||
faraday-em_synchrony (~> 1.0)
|
faraday-em_synchrony (~> 1.0)
|
||||||
@ -254,12 +264,16 @@ GEM
|
|||||||
fog-json (>= 1.0)
|
fog-json (>= 1.0)
|
||||||
ipaddress (>= 0.8)
|
ipaddress (>= 0.8)
|
||||||
formatador (0.2.5)
|
formatador (0.2.5)
|
||||||
fugit (1.5.2)
|
fugit (1.5.3)
|
||||||
et-orbi (~> 1.1, >= 1.1.8)
|
et-orbi (~> 1, >= 1.2.7)
|
||||||
raabro (~> 1.4)
|
raabro (~> 1.4)
|
||||||
fuubar (2.5.1)
|
fuubar (2.5.1)
|
||||||
rspec-core (~> 3.0)
|
rspec-core (~> 3.0)
|
||||||
ruby-progressbar (~> 1.4)
|
ruby-progressbar (~> 1.4)
|
||||||
|
gitlab-omniauth-openid-connect (0.9.1)
|
||||||
|
addressable (~> 2.7)
|
||||||
|
omniauth (~> 1.9)
|
||||||
|
openid_connect (~> 1.2)
|
||||||
globalid (1.0.0)
|
globalid (1.0.0)
|
||||||
activesupport (>= 5.0)
|
activesupport (>= 5.0)
|
||||||
hamlit (2.13.0)
|
hamlit (2.13.0)
|
||||||
@ -272,10 +286,11 @@ GEM
|
|||||||
hamlit (>= 1.2.0)
|
hamlit (>= 1.2.0)
|
||||||
railties (>= 4.0.1)
|
railties (>= 4.0.1)
|
||||||
hashdiff (1.0.1)
|
hashdiff (1.0.1)
|
||||||
hashie (4.1.0)
|
hashie (5.0.0)
|
||||||
highline (2.0.3)
|
highline (2.0.3)
|
||||||
hiredis (0.6.3)
|
hiredis (0.6.3)
|
||||||
hkdf (0.3.0)
|
hkdf (0.3.0)
|
||||||
|
html_tokenizer (0.0.7)
|
||||||
htmlentities (4.3.4)
|
htmlentities (4.3.4)
|
||||||
http (5.0.4)
|
http (5.0.4)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
@ -286,14 +301,16 @@ GEM
|
|||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
http-form_data (2.3.0)
|
http-form_data (2.3.0)
|
||||||
http_accept_language (2.1.1)
|
http_accept_language (2.1.1)
|
||||||
|
httpclient (2.8.3)
|
||||||
httplog (1.5.0)
|
httplog (1.5.0)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rainbow (>= 2.0.0)
|
rainbow (>= 2.0.0)
|
||||||
i18n (1.9.1)
|
i18n (1.10.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
i18n-tasks (0.9.37)
|
i18n-tasks (1.0.9)
|
||||||
activesupport (>= 4.0.2)
|
activesupport (>= 4.0.2)
|
||||||
ast (>= 2.1.0)
|
ast (>= 2.1.0)
|
||||||
|
better_html (~> 1.0)
|
||||||
erubi
|
erubi
|
||||||
highline (>= 2.0.0)
|
highline (>= 2.0.0)
|
||||||
i18n
|
i18n
|
||||||
@ -303,9 +320,13 @@ GEM
|
|||||||
terminal-table (>= 1.5.1)
|
terminal-table (>= 1.5.1)
|
||||||
idn-ruby (0.1.4)
|
idn-ruby (0.1.4)
|
||||||
ipaddress (0.8.3)
|
ipaddress (0.8.3)
|
||||||
jmespath (1.6.0)
|
jmespath (1.6.1)
|
||||||
json (2.5.1)
|
json (2.5.1)
|
||||||
json-canonicalization (0.3.0)
|
json-canonicalization (0.3.0)
|
||||||
|
json-jwt (1.13.0)
|
||||||
|
activesupport (>= 4.2)
|
||||||
|
aes_key_wrap
|
||||||
|
bindata
|
||||||
json-ld (3.2.0)
|
json-ld (3.2.0)
|
||||||
htmlentities (~> 4.3)
|
htmlentities (~> 4.3)
|
||||||
json-canonicalization (~> 0.3)
|
json-canonicalization (~> 0.3)
|
||||||
@ -338,8 +359,8 @@ GEM
|
|||||||
terrapin (~> 0.6.0)
|
terrapin (~> 0.6.0)
|
||||||
launchy (2.5.0)
|
launchy (2.5.0)
|
||||||
addressable (~> 2.7)
|
addressable (~> 2.7)
|
||||||
letter_opener (1.7.0)
|
letter_opener (1.8.1)
|
||||||
launchy (~> 2.2)
|
launchy (>= 2.2, < 3)
|
||||||
letter_opener_web (2.0.0)
|
letter_opener_web (2.0.0)
|
||||||
actionmailer (>= 5.2)
|
actionmailer (>= 5.2)
|
||||||
letter_opener (~> 1.7)
|
letter_opener (~> 1.7)
|
||||||
@ -349,12 +370,12 @@ GEM
|
|||||||
llhttp-ffi (0.4.0)
|
llhttp-ffi (0.4.0)
|
||||||
ffi-compiler (~> 1.0)
|
ffi-compiler (~> 1.0)
|
||||||
rake (~> 13.0)
|
rake (~> 13.0)
|
||||||
lograge (0.11.2)
|
lograge (0.12.0)
|
||||||
actionpack (>= 4)
|
actionpack (>= 4)
|
||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
loofah (2.14.0)
|
loofah (2.16.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.7.1)
|
mail (2.7.1)
|
||||||
@ -376,7 +397,7 @@ GEM
|
|||||||
mini_mime (1.1.2)
|
mini_mime (1.1.2)
|
||||||
mini_portile2 (2.8.0)
|
mini_portile2 (2.8.0)
|
||||||
minitest (5.15.0)
|
minitest (5.15.0)
|
||||||
msgpack (1.4.4)
|
msgpack (1.5.1)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
multipart-post (2.1.1)
|
multipart-post (2.1.1)
|
||||||
net-ldap (0.17.0)
|
net-ldap (0.17.0)
|
||||||
@ -384,7 +405,7 @@ GEM
|
|||||||
net-ssh (>= 2.6.5, < 7.0.0)
|
net-ssh (>= 2.6.5, < 7.0.0)
|
||||||
net-ssh (6.1.0)
|
net-ssh (6.1.0)
|
||||||
nio4r (2.5.8)
|
nio4r (2.5.8)
|
||||||
nokogiri (1.13.3)
|
nokogiri (1.13.4)
|
||||||
mini_portile2 (~> 2.8.0)
|
mini_portile2 (~> 2.8.0)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nsa (0.2.8)
|
nsa (0.2.8)
|
||||||
@ -406,17 +427,27 @@ GEM
|
|||||||
omniauth-saml (1.10.3)
|
omniauth-saml (1.10.3)
|
||||||
omniauth (~> 1.3, >= 1.3.2)
|
omniauth (~> 1.3, >= 1.3.2)
|
||||||
ruby-saml (~> 1.9)
|
ruby-saml (~> 1.9)
|
||||||
|
openid_connect (1.3.0)
|
||||||
|
activemodel
|
||||||
|
attr_required (>= 1.0.0)
|
||||||
|
json-jwt (>= 1.5.0)
|
||||||
|
rack-oauth2 (>= 1.6.1)
|
||||||
|
swd (>= 1.0.0)
|
||||||
|
tzinfo
|
||||||
|
validate_email
|
||||||
|
validate_url
|
||||||
|
webfinger (>= 1.0.1)
|
||||||
openssl (2.2.0)
|
openssl (2.2.0)
|
||||||
openssl-signature_algorithm (0.4.0)
|
openssl-signature_algorithm (0.4.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
ox (2.14.9)
|
ox (2.14.11)
|
||||||
parallel (1.21.0)
|
parallel (1.22.1)
|
||||||
parser (3.1.0.0)
|
parser (3.1.1.0)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
parslet (2.0.0)
|
parslet (2.0.0)
|
||||||
pastel (0.8.0)
|
pastel (0.8.0)
|
||||||
tty-color (~> 0.5)
|
tty-color (~> 0.5)
|
||||||
pg (1.3.3)
|
pg (1.3.5)
|
||||||
pghero (2.8.2)
|
pghero (2.8.2)
|
||||||
activerecord (>= 5)
|
activerecord (>= 5)
|
||||||
pkg-config (1.4.7)
|
pkg-config (1.4.7)
|
||||||
@ -438,35 +469,41 @@ GEM
|
|||||||
pry-rails (0.3.9)
|
pry-rails (0.3.9)
|
||||||
pry (>= 0.10.4)
|
pry (>= 0.10.4)
|
||||||
public_suffix (4.0.6)
|
public_suffix (4.0.6)
|
||||||
puma (5.6.2)
|
puma (5.6.4)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
pundit (2.2.0)
|
pundit (2.2.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
raabro (1.4.0)
|
raabro (1.4.0)
|
||||||
racc (1.6.0)
|
racc (1.6.0)
|
||||||
rack (2.2.3)
|
rack (2.2.3)
|
||||||
rack-attack (6.5.0)
|
rack-attack (6.6.1)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rack-cors (1.1.1)
|
rack-cors (1.1.1)
|
||||||
rack (>= 2.0.0)
|
rack (>= 2.0.0)
|
||||||
|
rack-oauth2 (1.19.0)
|
||||||
|
activesupport
|
||||||
|
attr_required
|
||||||
|
httpclient
|
||||||
|
json-jwt (>= 1.11.0)
|
||||||
|
rack (>= 2.1.0)
|
||||||
rack-proxy (0.7.0)
|
rack-proxy (0.7.0)
|
||||||
rack
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (6.1.4.6)
|
rails (6.1.5)
|
||||||
actioncable (= 6.1.4.6)
|
actioncable (= 6.1.5)
|
||||||
actionmailbox (= 6.1.4.6)
|
actionmailbox (= 6.1.5)
|
||||||
actionmailer (= 6.1.4.6)
|
actionmailer (= 6.1.5)
|
||||||
actionpack (= 6.1.4.6)
|
actionpack (= 6.1.5)
|
||||||
actiontext (= 6.1.4.6)
|
actiontext (= 6.1.5)
|
||||||
actionview (= 6.1.4.6)
|
actionview (= 6.1.5)
|
||||||
activejob (= 6.1.4.6)
|
activejob (= 6.1.5)
|
||||||
activemodel (= 6.1.4.6)
|
activemodel (= 6.1.5)
|
||||||
activerecord (= 6.1.4.6)
|
activerecord (= 6.1.5)
|
||||||
activestorage (= 6.1.4.6)
|
activestorage (= 6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 6.1.4.6)
|
railties (= 6.1.5)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
@ -482,11 +519,11 @@ GEM
|
|||||||
railties (>= 6.0.0, < 7)
|
railties (>= 6.0.0, < 7)
|
||||||
rails-settings-cached (0.6.6)
|
rails-settings-cached (0.6.6)
|
||||||
rails (>= 4.2.0)
|
rails (>= 4.2.0)
|
||||||
railties (6.1.4.6)
|
railties (6.1.5)
|
||||||
actionpack (= 6.1.4.6)
|
actionpack (= 6.1.5)
|
||||||
activesupport (= 6.1.4.6)
|
activesupport (= 6.1.5)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.13)
|
rake (>= 12.2)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.0.6)
|
rake (13.0.6)
|
||||||
@ -495,10 +532,10 @@ GEM
|
|||||||
rdf-normalize (0.5.0)
|
rdf-normalize (0.5.0)
|
||||||
rdf (~> 3.2)
|
rdf (~> 3.2)
|
||||||
redis (4.5.1)
|
redis (4.5.1)
|
||||||
redis-namespace (1.8.1)
|
redis-namespace (1.8.2)
|
||||||
redis (>= 3.0.4)
|
redis (>= 3.0.4)
|
||||||
regexp_parser (2.2.0)
|
regexp_parser (2.3.0)
|
||||||
request_store (1.5.0)
|
request_store (1.5.1)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
responders (3.0.1)
|
responders (3.0.1)
|
||||||
actionpack (>= 5.0)
|
actionpack (>= 5.0)
|
||||||
@ -518,7 +555,7 @@ GEM
|
|||||||
rspec-mocks (3.11.0)
|
rspec-mocks (3.11.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.11.0)
|
rspec-support (~> 3.11.0)
|
||||||
rspec-rails (5.1.0)
|
rspec-rails (5.1.1)
|
||||||
actionpack (>= 5.2)
|
actionpack (>= 5.2)
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
@ -532,18 +569,18 @@ GEM
|
|||||||
rspec-support (3.11.0)
|
rspec-support (3.11.0)
|
||||||
rspec_junit_formatter (0.5.1)
|
rspec_junit_formatter (0.5.1)
|
||||||
rspec-core (>= 2, < 4, != 2.12.0)
|
rspec-core (>= 2, < 4, != 2.12.0)
|
||||||
rubocop (1.25.1)
|
rubocop (1.27.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.1.0.0)
|
parser (>= 3.1.0.0)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 1.8, < 3.0)
|
regexp_parser (>= 1.8, < 3.0)
|
||||||
rexml
|
rexml
|
||||||
rubocop-ast (>= 1.15.1, < 2.0)
|
rubocop-ast (>= 1.16.0, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 1.4.0, < 3.0)
|
unicode-display_width (>= 1.4.0, < 3.0)
|
||||||
rubocop-ast (1.15.1)
|
rubocop-ast (1.17.0)
|
||||||
parser (>= 3.0.1.1)
|
parser (>= 3.1.1.0)
|
||||||
rubocop-rails (2.13.2)
|
rubocop-rails (2.14.2)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.7.0, < 2.0)
|
rubocop (>= 1.7.0, < 2.0)
|
||||||
@ -570,14 +607,14 @@ GEM
|
|||||||
redis (>= 4.2.0)
|
redis (>= 4.2.0)
|
||||||
sidekiq-bulk (0.2.0)
|
sidekiq-bulk (0.2.0)
|
||||||
sidekiq
|
sidekiq
|
||||||
sidekiq-scheduler (3.1.1)
|
sidekiq-scheduler (3.2.0)
|
||||||
e2mmap
|
e2mmap
|
||||||
redis (>= 3, < 5)
|
redis (>= 3, < 5)
|
||||||
rufus-scheduler (~> 3.2)
|
rufus-scheduler (~> 3.2)
|
||||||
sidekiq (>= 3)
|
sidekiq (>= 3)
|
||||||
thwait
|
thwait
|
||||||
tilt (>= 1.4.0)
|
tilt (>= 1.4.0)
|
||||||
sidekiq-unique-jobs (7.1.15)
|
sidekiq-unique-jobs (7.1.21)
|
||||||
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
|
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.5)
|
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||||
sidekiq (>= 5.0, < 8.0)
|
sidekiq (>= 5.0, < 8.0)
|
||||||
@ -593,6 +630,7 @@ GEM
|
|||||||
simplecov_json_formatter (~> 0.1)
|
simplecov_json_formatter (~> 0.1)
|
||||||
simplecov-html (0.12.3)
|
simplecov-html (0.12.3)
|
||||||
simplecov_json_formatter (0.1.2)
|
simplecov_json_formatter (0.1.2)
|
||||||
|
smart_properties (1.17.0)
|
||||||
sprockets (3.7.2)
|
sprockets (3.7.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
rack (> 1, < 3)
|
rack (> 1, < 3)
|
||||||
@ -603,11 +641,15 @@ GEM
|
|||||||
sshkit (1.21.2)
|
sshkit (1.21.2)
|
||||||
net-scp (>= 1.1.2)
|
net-scp (>= 1.1.2)
|
||||||
net-ssh (>= 2.8.0)
|
net-ssh (>= 2.8.0)
|
||||||
stackprof (0.2.17)
|
stackprof (0.2.19)
|
||||||
statsd-ruby (1.5.0)
|
statsd-ruby (1.5.0)
|
||||||
stoplight (2.2.1)
|
stoplight (2.2.1)
|
||||||
strong_migrations (0.7.9)
|
strong_migrations (0.7.9)
|
||||||
activerecord (>= 5)
|
activerecord (>= 5)
|
||||||
|
swd (1.3.0)
|
||||||
|
activesupport (>= 3)
|
||||||
|
attr_required (>= 0.0.5)
|
||||||
|
httpclient (>= 2.4)
|
||||||
temple (0.8.2)
|
temple (0.8.2)
|
||||||
terminal-table (3.0.2)
|
terminal-table (3.0.2)
|
||||||
unicode-display_width (>= 1.1.1, < 3)
|
unicode-display_width (>= 1.1.1, < 3)
|
||||||
@ -635,13 +677,19 @@ GEM
|
|||||||
unf (~> 0.1.0)
|
unf (~> 0.1.0)
|
||||||
tzinfo (2.0.4)
|
tzinfo (2.0.4)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
tzinfo-data (1.2021.5)
|
tzinfo-data (1.2022.1)
|
||||||
tzinfo (>= 1.0.0)
|
tzinfo (>= 1.0.0)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.8)
|
unf_ext (0.0.8)
|
||||||
unicode-display_width (2.1.0)
|
unicode-display_width (2.1.0)
|
||||||
uniform_notifier (1.14.2)
|
uniform_notifier (1.14.2)
|
||||||
|
validate_email (0.1.6)
|
||||||
|
activemodel (>= 3.0)
|
||||||
|
mail (>= 2.2.5)
|
||||||
|
validate_url (1.0.13)
|
||||||
|
activemodel (>= 3.0.0)
|
||||||
|
public_suffix
|
||||||
warden (1.2.9)
|
warden (1.2.9)
|
||||||
rack (>= 2.0.9)
|
rack (>= 2.0.9)
|
||||||
webauthn (3.0.0.alpha1)
|
webauthn (3.0.0.alpha1)
|
||||||
@ -654,6 +702,9 @@ GEM
|
|||||||
safety_net_attestation (~> 0.4.0)
|
safety_net_attestation (~> 0.4.0)
|
||||||
securecompare (~> 1.0)
|
securecompare (~> 1.0)
|
||||||
tpm-key_attestation (~> 0.9.0)
|
tpm-key_attestation (~> 0.9.0)
|
||||||
|
webfinger (1.2.0)
|
||||||
|
activesupport
|
||||||
|
httpclient (>= 2.4)
|
||||||
webmock (3.14.0)
|
webmock (3.14.0)
|
||||||
addressable (>= 2.8.0)
|
addressable (>= 2.8.0)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
@ -687,12 +738,12 @@ DEPENDENCIES
|
|||||||
better_errors (~> 2.9)
|
better_errors (~> 2.9)
|
||||||
binding_of_caller (~> 1.0)
|
binding_of_caller (~> 1.0)
|
||||||
blurhash (~> 0.1)
|
blurhash (~> 0.1)
|
||||||
bootsnap (~> 1.10.3)
|
bootsnap (~> 1.11.1)
|
||||||
brakeman (~> 5.2)
|
brakeman (~> 5.2)
|
||||||
browser
|
browser
|
||||||
bullet (~> 7.0)
|
bullet (~> 7.0)
|
||||||
bundler-audit (~> 0.9)
|
bundler-audit (~> 0.9)
|
||||||
capistrano (~> 3.16)
|
capistrano (~> 3.17)
|
||||||
capistrano-rails (~> 1.6)
|
capistrano-rails (~> 1.6)
|
||||||
capistrano-rbenv (~> 2.2)
|
capistrano-rbenv (~> 2.2)
|
||||||
capistrano-yarn (~> 2.0)
|
capistrano-yarn (~> 2.0)
|
||||||
@ -710,29 +761,30 @@ DEPENDENCIES
|
|||||||
doorkeeper (~> 5.5)
|
doorkeeper (~> 5.5)
|
||||||
dotenv-rails (~> 2.7)
|
dotenv-rails (~> 2.7)
|
||||||
ed25519 (~> 1.3)
|
ed25519 (~> 1.3)
|
||||||
fabrication (~> 2.27)
|
fabrication (~> 2.28)
|
||||||
faker (~> 2.19)
|
faker (~> 2.20)
|
||||||
fast_blank (~> 1.0)
|
fast_blank (~> 1.0)
|
||||||
fastimage
|
fastimage
|
||||||
fog-core (<= 2.1.0)
|
fog-core (<= 2.1.0)
|
||||||
fog-openstack (~> 0.3)
|
fog-openstack (~> 0.3)
|
||||||
fuubar (~> 2.5)
|
fuubar (~> 2.5)
|
||||||
|
gitlab-omniauth-openid-connect (~> 0.9.1)
|
||||||
hamlit-rails (~> 0.2)
|
hamlit-rails (~> 0.2)
|
||||||
hiredis (~> 0.6)
|
hiredis (~> 0.6)
|
||||||
htmlentities (~> 4.3)
|
htmlentities (~> 4.3)
|
||||||
http (~> 5.0)
|
http (~> 5.0)
|
||||||
http_accept_language (~> 2.1)
|
http_accept_language (~> 2.1)
|
||||||
httplog (~> 1.5.0)
|
httplog (~> 1.5.0)
|
||||||
i18n-tasks (~> 0.9)
|
i18n-tasks (~> 1.0)
|
||||||
idn-ruby
|
idn-ruby
|
||||||
json-ld
|
json-ld
|
||||||
json-ld-preloaded (~> 3.2)
|
json-ld-preloaded (~> 3.2)
|
||||||
kaminari (~> 1.2)
|
kaminari (~> 1.2)
|
||||||
kt-paperclip (~> 7.1)
|
kt-paperclip (~> 7.1)
|
||||||
letter_opener (~> 1.7)
|
letter_opener (~> 1.8)
|
||||||
letter_opener_web (~> 2.0)
|
letter_opener_web (~> 2.0)
|
||||||
link_header (~> 0.0)
|
link_header (~> 0.0)
|
||||||
lograge (~> 0.11)
|
lograge (~> 0.12)
|
||||||
makara (~> 0.5)
|
makara (~> 0.5)
|
||||||
mario-redis-lock (~> 1.2)
|
mario-redis-lock (~> 1.2)
|
||||||
memory_profiler
|
memory_profiler
|
||||||
@ -759,9 +811,9 @@ DEPENDENCIES
|
|||||||
puma (~> 5.6)
|
puma (~> 5.6)
|
||||||
pundit (~> 2.2)
|
pundit (~> 2.2)
|
||||||
rack (~> 2.2.3)
|
rack (~> 2.2.3)
|
||||||
rack-attack (~> 6.5)
|
rack-attack (~> 6.6)
|
||||||
rack-cors (~> 1.1)
|
rack-cors (~> 1.1)
|
||||||
rails (~> 6.1.4)
|
rails (~> 6.1.5)
|
||||||
rails-controller-testing (~> 1.0)
|
rails-controller-testing (~> 1.0)
|
||||||
rails-i18n (~> 6.0)
|
rails-i18n (~> 6.0)
|
||||||
rails-settings-cached (~> 0.6)
|
rails-settings-cached (~> 0.6)
|
||||||
@ -773,14 +825,14 @@ DEPENDENCIES
|
|||||||
rspec-rails (~> 5.1)
|
rspec-rails (~> 5.1)
|
||||||
rspec-sidekiq (~> 3.1)
|
rspec-sidekiq (~> 3.1)
|
||||||
rspec_junit_formatter (~> 0.5)
|
rspec_junit_formatter (~> 0.5)
|
||||||
rubocop (~> 1.25)
|
rubocop (~> 1.27)
|
||||||
rubocop-rails (~> 2.13)
|
rubocop-rails (~> 2.14)
|
||||||
ruby-progressbar (~> 1.11)
|
ruby-progressbar (~> 1.11)
|
||||||
sanitize (~> 6.0)
|
sanitize (~> 6.0)
|
||||||
scenic (~> 1.6)
|
scenic (~> 1.6)
|
||||||
sidekiq (~> 6.4)
|
sidekiq (~> 6.4)
|
||||||
sidekiq-bulk (~> 0.2.0)
|
sidekiq-bulk (~> 0.2.0)
|
||||||
sidekiq-scheduler (~> 3.1)
|
sidekiq-scheduler (~> 3.2)
|
||||||
sidekiq-unique-jobs (~> 7.1)
|
sidekiq-unique-jobs (~> 7.1)
|
||||||
simple-navigation (~> 4.3)
|
simple-navigation (~> 4.3)
|
||||||
simple_form (~> 5.1)
|
simple_form (~> 5.1)
|
||||||
@ -793,7 +845,7 @@ DEPENDENCIES
|
|||||||
thor (~> 1.2)
|
thor (~> 1.2)
|
||||||
tty-prompt (~> 0.23)
|
tty-prompt (~> 0.23)
|
||||||
twitter-text (~> 3.1.0)
|
twitter-text (~> 3.1.0)
|
||||||
tzinfo-data (~> 1.2021)
|
tzinfo-data (~> 1.2022)
|
||||||
webauthn (~> 3.0.0.alpha1)
|
webauthn (~> 3.0.0.alpha1)
|
||||||
webmock (~> 3.14)
|
webmock (~> 3.14)
|
||||||
webpacker (~> 5.4)
|
webpacker (~> 5.4)
|
||||||
|
@ -28,7 +28,7 @@ Click below to **learn more** in a video:
|
|||||||
- [View sponsors](https://joinmastodon.org/sponsors)
|
- [View sponsors](https://joinmastodon.org/sponsors)
|
||||||
- [Blog](https://blog.joinmastodon.org)
|
- [Blog](https://blog.joinmastodon.org)
|
||||||
- [Documentation](https://docs.joinmastodon.org)
|
- [Documentation](https://docs.joinmastodon.org)
|
||||||
- [Browse Mastodon servers](https://joinmastodon.org/#getting-started)
|
- [Browse Mastodon servers](https://joinmastodon.org/communities)
|
||||||
- [Browse Mastodon apps](https://joinmastodon.org/apps)
|
- [Browse Mastodon apps](https://joinmastodon.org/apps)
|
||||||
|
|
||||||
[patreon]: https://www.patreon.com/mastodon
|
[patreon]: https://www.patreon.com/mastodon
|
||||||
@ -92,7 +92,7 @@ You can open issues for bugs you've found or features you think are missing. You
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (C) 2016-2021 Eugen Rochko & other Mastodon contributors (see [AUTHORS.md](AUTHORS.md))
|
Copyright (C) 2016-2022 Eugen Rochko & other Mastodon contributors (see [AUTHORS.md](AUTHORS.md))
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
19
SECURITY.md
19
SECURITY.md
@ -1,13 +1,20 @@
|
|||||||
# Security Policy
|
# Security Policy
|
||||||
|
|
||||||
|
If you believe you've identified a security vulnerability in Mastodon (a bug that allows something to happen that shouldn't be possible), you should submit the report through our [Bug Bounty Program][bug-bounty]. Alternatively, you can reach us at <hello@joinmastodon.org>.
|
||||||
|
|
||||||
|
You should *not* report such issues on GitHub or in other public spaces to give us time to publish a fix for the issue without exposing Mastodon's users to increased risk.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
A "vulnerability in Mastodon" is a vulnerability in the code distributed through our main source code repository on GitHub. Vulnerabilities that are specific to a given installation (e.g. misconfiguration) should be reported to the owner of that installation and not us.
|
||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| ------- | ------------------ |
|
| ------- | ------------------ |
|
||||||
| 3.4.x | :white_check_mark: |
|
| 3.5.x | Yes |
|
||||||
| 3.3.x | :white_check_mark: |
|
| 3.4.x | Yes |
|
||||||
| < 3.3 | :x: |
|
| 3.3.x | Yes |
|
||||||
|
| < 3.3 | No |
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
[bug-bounty]: https://app.intigriti.com/programs/mastodon/mastodonio/detail
|
||||||
|
|
||||||
hello@joinmastodon.org
|
|
||||||
|
5
app.json
5
app.json
@ -95,8 +95,5 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"postdeploy": "bundle exec rails db:migrate && bundle exec rails db:seed"
|
"postdeploy": "bundle exec rails db:migrate && bundle exec rails db:seed"
|
||||||
},
|
},
|
||||||
"addons": [
|
"addons": ["heroku-postgresql", "heroku-redis"]
|
||||||
"heroku-postgresql",
|
|
||||||
"heroku-redis"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class StatusesIndex < Chewy::Index
|
class StatusesIndex < Chewy::Index
|
||||||
|
include FormattingHelper
|
||||||
|
|
||||||
settings index: { refresh_interval: '15m' }, analysis: {
|
settings index: { refresh_interval: '15m' }, analysis: {
|
||||||
filter: {
|
filter: {
|
||||||
english_stop: {
|
english_stop: {
|
||||||
@ -53,11 +55,16 @@ class StatusesIndex < Chewy::Index
|
|||||||
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
crutch :votes do |collection|
|
||||||
|
data = ::PollVote.joins(:poll).where(poll: { status_id: collection.map(&:id) }).where(account: Account.local).pluck(:status_id, :account_id)
|
||||||
|
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
||||||
|
end
|
||||||
|
|
||||||
root date_detection: false do
|
root date_detection: false do
|
||||||
field :id, type: 'long'
|
field :id, type: 'long'
|
||||||
field :account_id, type: 'long'
|
field :account_id, type: 'long'
|
||||||
|
|
||||||
field :text, type: 'text', value: ->(status) { [status.spoiler_text, Formatter.instance.plaintext(status)].concat(status.media_attachments.map(&:description)).concat(status.preloadable_poll ? status.preloadable_poll.options : []).join("\n\n") } do
|
field :text, type: 'text', value: ->(status) { status.searchable_text } do
|
||||||
field :stemmed, type: 'text', analyzer: 'content'
|
field :stemmed, type: 'text', analyzer: 'content'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
class ActivityPub::BaseController < Api::BaseController
|
class ActivityPub::BaseController < Api::BaseController
|
||||||
skip_before_action :require_authenticated_user!
|
skip_before_action :require_authenticated_user!
|
||||||
|
skip_around_action :set_locale
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
|||||||
return unless page_requested?
|
return unless page_requested?
|
||||||
|
|
||||||
@statuses = cache_collection_paginated_by_id(
|
@statuses = cache_collection_paginated_by_id(
|
||||||
@account.statuses.permitted_for(@account, signed_request_account),
|
AccountStatusesFilter.new(@account, signed_request_account).results,
|
||||||
Status,
|
Status,
|
||||||
LIMIT,
|
LIMIT,
|
||||||
params_slice(:max_id, :min_id, :since_id)
|
params_slice(:max_id, :min_id, :since_id)
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
module Admin
|
module Admin
|
||||||
class DashboardController < BaseController
|
class DashboardController < BaseController
|
||||||
|
include Redisable
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@system_checks = Admin::SystemCheck.perform
|
@system_checks = Admin::SystemCheck.perform
|
||||||
@time_period = (29.days.ago.to_date...Time.now.utc.to_date)
|
@time_period = (29.days.ago.to_date...Time.now.utc.to_date)
|
||||||
@ -15,10 +17,10 @@ module Admin
|
|||||||
|
|
||||||
def redis_info
|
def redis_info
|
||||||
@redis_info ||= begin
|
@redis_info ||= begin
|
||||||
if Redis.current.is_a?(Redis::Namespace)
|
if redis.is_a?(Redis::Namespace)
|
||||||
Redis.current.redis.info
|
redis.redis.info
|
||||||
else
|
else
|
||||||
Redis.current.info
|
redis.info
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -56,10 +56,6 @@ module Admin
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
|
||||||
authorize @domain_block, :show?
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
authorize @domain_block, :destroy?
|
authorize @domain_block, :destroy?
|
||||||
UnblockDomainService.new.call(@domain_block)
|
UnblockDomainService.new.call(@domain_block)
|
||||||
|
@ -4,28 +4,26 @@ module Admin
|
|||||||
class InstancesController < BaseController
|
class InstancesController < BaseController
|
||||||
before_action :set_instances, only: :index
|
before_action :set_instances, only: :index
|
||||||
before_action :set_instance, except: :index
|
before_action :set_instance, except: :index
|
||||||
before_action :set_exhausted_deliveries_days, only: :show
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize :instance, :index?
|
authorize :instance, :index?
|
||||||
|
preload_delivery_failures!
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
authorize :instance, :show?
|
authorize :instance, :show?
|
||||||
|
@time_period = (6.days.ago.to_date...Time.now.utc.to_date)
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
authorize :instance, :destroy?
|
authorize :instance, :destroy?
|
||||||
|
|
||||||
Admin::DomainPurgeWorker.perform_async(@instance.domain)
|
Admin::DomainPurgeWorker.perform_async(@instance.domain)
|
||||||
|
|
||||||
log_action :destroy, @instance
|
log_action :destroy, @instance
|
||||||
redirect_to admin_instances_path, notice: I18n.t('admin.instances.destroyed_msg', domain: @instance.domain)
|
redirect_to admin_instances_path, notice: I18n.t('admin.instances.destroyed_msg', domain: @instance.domain)
|
||||||
end
|
end
|
||||||
|
|
||||||
def clear_delivery_errors
|
def clear_delivery_errors
|
||||||
authorize :delivery, :clear_delivery_errors?
|
authorize :delivery, :clear_delivery_errors?
|
||||||
|
|
||||||
@instance.delivery_failure_tracker.clear_failures!
|
@instance.delivery_failure_tracker.clear_failures!
|
||||||
redirect_to admin_instance_path(@instance.domain)
|
redirect_to admin_instance_path(@instance.domain)
|
||||||
end
|
end
|
||||||
@ -33,11 +31,9 @@ module Admin
|
|||||||
def restart_delivery
|
def restart_delivery
|
||||||
authorize :delivery, :restart_delivery?
|
authorize :delivery, :restart_delivery?
|
||||||
|
|
||||||
last_unavailable_domain = unavailable_domain
|
if @instance.unavailable?
|
||||||
|
|
||||||
if last_unavailable_domain.present?
|
|
||||||
@instance.delivery_failure_tracker.track_success!
|
@instance.delivery_failure_tracker.track_success!
|
||||||
log_action :destroy, last_unavailable_domain
|
log_action :destroy, @instance.unavailable_domain
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_to admin_instance_path(@instance.domain)
|
redirect_to admin_instance_path(@instance.domain)
|
||||||
@ -45,8 +41,7 @@ module Admin
|
|||||||
|
|
||||||
def stop_delivery
|
def stop_delivery
|
||||||
authorize :delivery, :stop_delivery?
|
authorize :delivery, :stop_delivery?
|
||||||
|
unavailable_domain = UnavailableDomain.create!(domain: @instance.domain)
|
||||||
UnavailableDomain.create(domain: @instance.domain)
|
|
||||||
log_action :create, unavailable_domain
|
log_action :create, unavailable_domain
|
||||||
redirect_to admin_instance_path(@instance.domain)
|
redirect_to admin_instance_path(@instance.domain)
|
||||||
end
|
end
|
||||||
@ -57,12 +52,11 @@ module Admin
|
|||||||
@instance = Instance.find(params[:id])
|
@instance = Instance.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_exhausted_deliveries_days
|
|
||||||
@exhausted_deliveries_days = @instance.delivery_failure_tracker.exhausted_deliveries_days
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_instances
|
def set_instances
|
||||||
@instances = filtered_instances.page(params[:page])
|
@instances = filtered_instances.page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
|
def preload_delivery_failures!
|
||||||
warning_domains_map = DeliveryFailureTracker.warning_domains_map
|
warning_domains_map = DeliveryFailureTracker.warning_domains_map
|
||||||
|
|
||||||
@instances.each do |instance|
|
@instances.each do |instance|
|
||||||
@ -70,10 +64,6 @@ module Admin
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def unavailable_domain
|
|
||||||
UnavailableDomain.find_by(domain: @instance.domain)
|
|
||||||
end
|
|
||||||
|
|
||||||
def filtered_instances
|
def filtered_instances
|
||||||
InstanceFilter.new(whitelist_mode? ? { allowed: true } : filter_params).results
|
InstanceFilter.new(whitelist_mode? ? { allowed: true } : filter_params).results
|
||||||
end
|
end
|
||||||
|
@ -7,7 +7,7 @@ class Admin::Reports::ActionsController < Admin::BaseController
|
|||||||
authorize @report, :show?
|
authorize @report, :show?
|
||||||
|
|
||||||
case action_from_button
|
case action_from_button
|
||||||
when 'delete'
|
when 'delete', 'mark_as_sensitive'
|
||||||
status_batch_action = Admin::StatusBatchAction.new(
|
status_batch_action = Admin::StatusBatchAction.new(
|
||||||
type: action_from_button,
|
type: action_from_button,
|
||||||
status_ids: @report.status_ids,
|
status_ids: @report.status_ids,
|
||||||
@ -41,6 +41,8 @@ class Admin::Reports::ActionsController < Admin::BaseController
|
|||||||
def action_from_button
|
def action_from_button
|
||||||
if params[:delete]
|
if params[:delete]
|
||||||
'delete'
|
'delete'
|
||||||
|
elsif params[:mark_as_sensitive]
|
||||||
|
'mark_as_sensitive'
|
||||||
elsif params[:silence]
|
elsif params[:silence]
|
||||||
'silence'
|
'silence'
|
||||||
elsif params[:suspend]
|
elsif params[:suspend]
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Admin
|
|
||||||
class SignInTokenAuthenticationsController < BaseController
|
|
||||||
before_action :set_target_user
|
|
||||||
|
|
||||||
def create
|
|
||||||
authorize @user, :enable_sign_in_token_auth?
|
|
||||||
@user.update(skip_sign_in_token: false)
|
|
||||||
log_action :enable_sign_in_token_auth, @user
|
|
||||||
redirect_to admin_account_path(@user.account_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
authorize @user, :disable_sign_in_token_auth?
|
|
||||||
@user.update(skip_sign_in_token: true)
|
|
||||||
log_action :disable_sign_in_token_auth, @user
|
|
||||||
redirect_to admin_account_path(@user.account_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def set_target_user
|
|
||||||
@user = User.find(params[:user_id])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -5,6 +5,7 @@ class Api::BaseController < ApplicationController
|
|||||||
DEFAULT_ACCOUNTS_LIMIT = 40
|
DEFAULT_ACCOUNTS_LIMIT = 40
|
||||||
|
|
||||||
include RateLimitHeaders
|
include RateLimitHeaders
|
||||||
|
include AccessTokenTrackingConcern
|
||||||
|
|
||||||
skip_before_action :store_current_location
|
skip_before_action :store_current_location
|
||||||
skip_before_action :require_functional!, unless: :whitelist_mode?
|
skip_before_action :require_functional!, unless: :whitelist_mode?
|
||||||
@ -14,8 +15,6 @@ class Api::BaseController < ApplicationController
|
|||||||
|
|
||||||
protect_from_forgery with: :null_session
|
protect_from_forgery with: :null_session
|
||||||
|
|
||||||
skip_around_action :set_locale
|
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
|
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
|
||||||
render json: { error: e.to_s }, status: 422
|
render json: { error: e.to_s }, status: 422
|
||||||
end
|
end
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Accounts::FamiliarFollowersController < Api::BaseController
|
||||||
|
before_action -> { doorkeeper_authorize! :read, :'read:follows' }
|
||||||
|
before_action :require_user!
|
||||||
|
before_action :set_accounts
|
||||||
|
|
||||||
|
def index
|
||||||
|
render json: familiar_followers.accounts, each_serializer: REST::FamiliarFollowersSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_accounts
|
||||||
|
@accounts = Account.without_suspended.where(id: account_ids).select('id, hide_collections').index_by(&:id).values_at(*account_ids).compact
|
||||||
|
end
|
||||||
|
|
||||||
|
def familiar_followers
|
||||||
|
FamiliarFollowersPresenter.new(@accounts, current_user.account_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_ids
|
||||||
|
Array(params[:id]).map(&:to_i)
|
||||||
|
end
|
||||||
|
end
|
@ -12,5 +12,7 @@ class Api::V1::Accounts::LookupController < Api::BaseController
|
|||||||
|
|
||||||
def set_account
|
def set_account
|
||||||
@account = ResolveAccountService.new.call(params[:acct], skip_webfinger: true) || raise(ActiveRecord::RecordNotFound)
|
@account = ResolveAccountService.new.call(params[:acct], skip_webfinger: true) || raise(ActiveRecord::RecordNotFound)
|
||||||
|
rescue Addressable::URI::InvalidURIError
|
||||||
|
raise(ActiveRecord::RecordNotFound)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -25,53 +25,16 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def cached_account_statuses
|
def cached_account_statuses
|
||||||
statuses = truthy_param?(:pinned) ? pinned_scope : permitted_account_statuses
|
|
||||||
|
|
||||||
statuses.merge!(only_media_scope) if truthy_param?(:only_media)
|
|
||||||
statuses.merge!(no_replies_scope) if truthy_param?(:exclude_replies)
|
|
||||||
statuses.merge!(no_reblogs_scope) if truthy_param?(:exclude_reblogs)
|
|
||||||
statuses.merge!(hashtag_scope) if params[:tagged].present?
|
|
||||||
|
|
||||||
cache_collection_paginated_by_id(
|
cache_collection_paginated_by_id(
|
||||||
statuses,
|
AccountStatusesFilter.new(@account, current_account, params).results,
|
||||||
Status,
|
Status,
|
||||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||||
params_slice(:max_id, :since_id, :min_id)
|
params_slice(:max_id, :since_id, :min_id)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def permitted_account_statuses
|
|
||||||
@account.statuses.permitted_for(@account, current_account)
|
|
||||||
end
|
|
||||||
|
|
||||||
def only_media_scope
|
|
||||||
Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def pinned_scope
|
|
||||||
@account.pinned_statuses.permitted_for(@account, current_account)
|
|
||||||
end
|
|
||||||
|
|
||||||
def no_replies_scope
|
|
||||||
Status.without_replies
|
|
||||||
end
|
|
||||||
|
|
||||||
def no_reblogs_scope
|
|
||||||
Status.without_reblogs
|
|
||||||
end
|
|
||||||
|
|
||||||
def hashtag_scope
|
|
||||||
tag = Tag.find_normalized(params[:tagged])
|
|
||||||
|
|
||||||
if tag
|
|
||||||
Status.tagged_with(tag.id)
|
|
||||||
else
|
|
||||||
Status.none
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_params(core_params)
|
def pagination_params(core_params)
|
||||||
params.slice(:limit, :only_media, :exclude_replies).permit(:limit, :only_media, :exclude_replies).merge(core_params)
|
params.slice(:limit, *AccountStatusesFilter::KEYS).permit(:limit, *AccountStatusesFilter::KEYS).merge(core_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
class Api::V1::AccountsController < Api::BaseController
|
class Api::V1::AccountsController < Api::BaseController
|
||||||
before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:create, :follow, :unfollow, :remove_from_followers, :block, :unblock, :mute, :unmute]
|
before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:create, :follow, :unfollow, :remove_from_followers, :block, :unblock, :mute, :unmute]
|
||||||
before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, only: [:follow, :unfollow, :remove_from_followers]
|
before_action -> { doorkeeper_authorize! :follow, :write, :'write:follows' }, only: [:follow, :unfollow, :remove_from_followers]
|
||||||
before_action -> { doorkeeper_authorize! :follow, :'write:mutes' }, only: [:mute, :unmute]
|
before_action -> { doorkeeper_authorize! :follow, :write, :'write:mutes' }, only: [:mute, :unmute]
|
||||||
before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, only: [:block, :unblock]
|
before_action -> { doorkeeper_authorize! :follow, :write, :'write:blocks' }, only: [:block, :unblock]
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create]
|
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create]
|
||||||
|
|
||||||
before_action :require_user!, except: [:show, :create]
|
before_action :require_user!, except: [:show, :create]
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Admin::AccountActionsController < Api::BaseController
|
class Api::V1::Admin::AccountActionsController < Api::BaseController
|
||||||
protect_from_forgery with: :exception
|
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :'admin:write', :'admin:write:accounts' }
|
before_action -> { authorize_if_got_token! :'admin:write', :'admin:write:accounts' }
|
||||||
before_action :require_staff!
|
before_action :require_staff!
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Admin::AccountsController < Api::BaseController
|
class Api::V1::Admin::AccountsController < Api::BaseController
|
||||||
protect_from_forgery with: :exception
|
|
||||||
|
|
||||||
include Authorization
|
include Authorization
|
||||||
include AccountableConcern
|
include AccountableConcern
|
||||||
|
|
||||||
@ -67,8 +65,9 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
|||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
authorize @account, :destroy?
|
authorize @account, :destroy?
|
||||||
|
json = render_to_body json: @account, serializer: REST::Admin::AccountSerializer
|
||||||
Admin::AccountDeletionWorker.perform_async(@account.id)
|
Admin::AccountDeletionWorker.perform_async(@account.id)
|
||||||
render json: @account, serializer: REST::Admin::AccountSerializer
|
render json: json
|
||||||
end
|
end
|
||||||
|
|
||||||
def unsensitive
|
def unsensitive
|
||||||
@ -104,13 +103,27 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def filtered_accounts
|
def filtered_accounts
|
||||||
AccountFilter.new(filter_params).results
|
AccountFilter.new(translated_filter_params).results
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_params
|
def filter_params
|
||||||
params.permit(*FILTER_PARAMS)
|
params.permit(*FILTER_PARAMS)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def translated_filter_params
|
||||||
|
translated_params = { origin: 'local', status: 'active' }.merge(filter_params.slice(*AccountFilter::KEYS))
|
||||||
|
|
||||||
|
translated_params[:origin] = 'remote' if params[:remote].present?
|
||||||
|
|
||||||
|
%i(active pending disabled silenced suspended).each do |status|
|
||||||
|
translated_params[:status] = status.to_s if params[status].present?
|
||||||
|
end
|
||||||
|
|
||||||
|
translated_params[:permissions] = 'staff' if params[:staff].present?
|
||||||
|
|
||||||
|
translated_params
|
||||||
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
set_pagination_headers(next_path, prev_path)
|
set_pagination_headers(next_path, prev_path)
|
||||||
end
|
end
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Admin::DimensionsController < Api::BaseController
|
class Api::V1::Admin::DimensionsController < Api::BaseController
|
||||||
protect_from_forgery with: :exception
|
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :'admin:read' }
|
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||||
before_action :require_staff!
|
before_action :require_staff!
|
||||||
before_action :set_dimensions
|
before_action :set_dimensions
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Admin::MeasuresController < Api::BaseController
|
class Api::V1::Admin::MeasuresController < Api::BaseController
|
||||||
protect_from_forgery with: :exception
|
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :'admin:read' }
|
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||||
before_action :require_staff!
|
before_action :require_staff!
|
||||||
before_action :set_measures
|
before_action :set_measures
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Admin::ReportsController < Api::BaseController
|
class Api::V1::Admin::ReportsController < Api::BaseController
|
||||||
protect_from_forgery with: :exception
|
|
||||||
|
|
||||||
include Authorization
|
include Authorization
|
||||||
include AccountableConcern
|
include AccountableConcern
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Admin::RetentionController < Api::BaseController
|
class Api::V1::Admin::RetentionController < Api::BaseController
|
||||||
protect_from_forgery with: :exception
|
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :'admin:read' }
|
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||||
before_action :require_staff!
|
before_action :require_staff!
|
||||||
before_action :set_cohorts
|
before_action :set_cohorts
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Admin::Trends::LinksController < Api::BaseController
|
class Api::V1::Admin::Trends::LinksController < Api::BaseController
|
||||||
protect_from_forgery with: :exception
|
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :'admin:read' }
|
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||||
before_action :require_staff!
|
before_action :require_staff!
|
||||||
before_action :set_links
|
before_action :set_links
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Admin::Trends::StatusesController < Api::BaseController
|
class Api::V1::Admin::Trends::StatusesController < Api::BaseController
|
||||||
protect_from_forgery with: :exception
|
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :'admin:read' }
|
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||||
before_action :require_staff!
|
before_action :require_staff!
|
||||||
before_action :set_statuses
|
before_action :set_statuses
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Admin::Trends::TagsController < Api::BaseController
|
class Api::V1::Admin::Trends::TagsController < Api::BaseController
|
||||||
protect_from_forgery with: :exception
|
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :'admin:read' }
|
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||||
before_action :require_staff!
|
before_action :require_staff!
|
||||||
before_action :set_tags
|
before_action :set_tags
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::BlocksController < Api::BaseController
|
class Api::V1::BlocksController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :follow, :'read:blocks' }
|
before_action -> { doorkeeper_authorize! :follow, :read, :'read:blocks' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ class Api::V1::BookmarksController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def results
|
def results
|
||||||
@_results ||= account_bookmarks.eager_load(:status).to_a_paginated_by_id(
|
@_results ||= account_bookmarks.joins(:status).eager_load(:status).to_a_paginated_by_id(
|
||||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||||
params_slice(:max_id, :since_id, :min_id)
|
params_slice(:max_id, :since_id, :min_id)
|
||||||
)
|
)
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
class Api::V1::DomainBlocksController < Api::BaseController
|
class Api::V1::DomainBlocksController < Api::BaseController
|
||||||
BLOCK_LIMIT = 100
|
BLOCK_LIMIT = 100
|
||||||
|
|
||||||
before_action -> { doorkeeper_authorize! :follow, :'read:blocks' }, only: :show
|
before_action -> { doorkeeper_authorize! :follow, :read, :'read:blocks' }, only: :show
|
||||||
before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, except: :show
|
before_action -> { doorkeeper_authorize! :follow, :write, :'write:blocks' }, except: :show
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers, only: :show
|
after_action :insert_pagination_headers, only: :show
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::Emails::ConfirmationsController < Api::BaseController
|
class Api::V1::Emails::ConfirmationsController < Api::BaseController
|
||||||
before_action :doorkeeper_authorize!
|
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }
|
||||||
before_action :require_user_owned_by_application!
|
before_action :require_user_owned_by_application!
|
||||||
before_action :require_user_not_confirmed!
|
before_action :require_user_not_confirmed!
|
||||||
|
|
||||||
@ -19,6 +19,6 @@ class Api::V1::Emails::ConfirmationsController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def require_user_not_confirmed!
|
def require_user_not_confirmed!
|
||||||
render json: { error: 'This method is only available while the e-mail is awaiting confirmation' }, status: :forbidden if current_user.confirmed? || current_user.unconfirmed_email.blank?
|
render json: { error: 'This method is only available while the e-mail is awaiting confirmation' }, status: :forbidden unless !current_user.confirmed? || current_user.unconfirmed_email.present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -24,7 +24,7 @@ class Api::V1::FavouritesController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def results
|
def results
|
||||||
@_results ||= account_favourites.eager_load(:status).to_a_paginated_by_id(
|
@_results ||= account_favourites.joins(:status).eager_load(:status).to_a_paginated_by_id(
|
||||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||||
params_slice(:max_id, :since_id, :min_id)
|
params_slice(:max_id, :since_id, :min_id)
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::FollowRequestsController < Api::BaseController
|
class Api::V1::FollowRequestsController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :follow, :'read:follows' }, only: :index
|
before_action -> { doorkeeper_authorize! :follow, :read, :'read:follows' }, only: :index
|
||||||
before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, except: :index
|
before_action -> { doorkeeper_authorize! :follow, :write, :'write:follows' }, except: :index
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers, only: :index
|
after_action :insert_pagination_headers, only: :index
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ class Api::V1::FollowRequestsController < Api::BaseController
|
|||||||
|
|
||||||
def authorize
|
def authorize
|
||||||
AuthorizeFollowService.new.call(account, current_account)
|
AuthorizeFollowService.new.call(account, current_account)
|
||||||
NotifyService.new.call(current_account, :follow, Follow.find_by(account: account, target_account: current_account))
|
LocalNotificationWorker.perform_async(current_account.id, Follow.find_by(account: account, target_account: current_account).id, 'Follow', 'follow')
|
||||||
render json: account, serializer: REST::RelationshipSerializer, relationships: relationships
|
render json: account, serializer: REST::RelationshipSerializer, relationships: relationships
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class Api::V1::MediaController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_media_attachment
|
def set_media_attachment
|
||||||
@media_attachment = current_account.media_attachments.unattached.find(params[:id])
|
@media_attachment = current_account.media_attachments.where(status_id: nil).find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_processing
|
def check_processing
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::V1::MutesController < Api::BaseController
|
class Api::V1::MutesController < Api::BaseController
|
||||||
before_action -> { doorkeeper_authorize! :follow, :'read:mutes' }
|
before_action -> { doorkeeper_authorize! :follow, :read, :'read:mutes' }
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
after_action :insert_pagination_headers
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
|
@ -35,13 +35,18 @@ class Api::V1::NotificationsController < Api::BaseController
|
|||||||
limit_param(DEFAULT_NOTIFICATIONS_LIMIT),
|
limit_param(DEFAULT_NOTIFICATIONS_LIMIT),
|
||||||
params_slice(:max_id, :since_id, :min_id)
|
params_slice(:max_id, :since_id, :min_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
Notification.preload_cache_collection_target_statuses(notifications) do |target_statuses|
|
Notification.preload_cache_collection_target_statuses(notifications) do |target_statuses|
|
||||||
cache_collection(target_statuses, Status)
|
cache_collection(target_statuses, Status)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def browserable_account_notifications
|
def browserable_account_notifications
|
||||||
current_account.notifications.without_suspended.browserable(exclude_types, from_account)
|
current_account.notifications.without_suspended.browserable(
|
||||||
|
types: Array(browserable_params[:types]),
|
||||||
|
exclude_types: Array(browserable_params[:exclude_types]),
|
||||||
|
from_account_id: browserable_params[:account_id]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def target_statuses_from_notifications
|
def target_statuses_from_notifications
|
||||||
@ -72,17 +77,11 @@ class Api::V1::NotificationsController < Api::BaseController
|
|||||||
@notifications.first.id
|
@notifications.first.id
|
||||||
end
|
end
|
||||||
|
|
||||||
def exclude_types
|
def browserable_params
|
||||||
val = params.permit(exclude_types: [])[:exclude_types] || []
|
params.permit(:account_id, types: [], exclude_types: [])
|
||||||
val = [val] unless val.is_a?(Enumerable)
|
|
||||||
val
|
|
||||||
end
|
|
||||||
|
|
||||||
def from_account
|
|
||||||
params[:account_id]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_params(core_params)
|
def pagination_params(core_params)
|
||||||
params.slice(:limit, :exclude_types).permit(:limit, exclude_types: []).merge(core_params)
|
params.slice(:limit, :account_id, :types, :exclude_types).permit(:limit, :account_id, types: [], exclude_types: []).merge(core_params)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -10,9 +10,7 @@ class Api::V1::ReportsController < Api::BaseController
|
|||||||
@report = ReportService.new.call(
|
@report = ReportService.new.call(
|
||||||
current_account,
|
current_account,
|
||||||
reported_account,
|
reported_account,
|
||||||
status_ids: reported_status_ids,
|
report_params
|
||||||
comment: report_params[:comment],
|
|
||||||
forward: report_params[:forward]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
render json: @report, serializer: REST::ReportSerializer
|
render json: @report, serializer: REST::ReportSerializer
|
||||||
@ -20,14 +18,6 @@ class Api::V1::ReportsController < Api::BaseController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def reported_status_ids
|
|
||||||
reported_account.statuses.with_discarded.find(status_ids).pluck(:id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def status_ids
|
|
||||||
Array(report_params[:status_ids])
|
|
||||||
end
|
|
||||||
|
|
||||||
def reported_account
|
def reported_account
|
||||||
Account.find(report_params[:account_id])
|
Account.find(report_params[:account_id])
|
||||||
end
|
end
|
||||||
|
@ -10,6 +10,7 @@ class Api::V1::StatusesController < Api::BaseController
|
|||||||
before_action :set_thread, only: [:create]
|
before_action :set_thread, only: [:create]
|
||||||
|
|
||||||
override_rate_limit_headers :create, family: :statuses
|
override_rate_limit_headers :create, family: :statuses
|
||||||
|
override_rate_limit_headers :update, family: :statuses
|
||||||
|
|
||||||
# This API was originally unlimited, pagination cannot be introduced without
|
# This API was originally unlimited, pagination cannot be introduced without
|
||||||
# breaking backwards-compatibility. Arbitrarily high number to cover most
|
# breaking backwards-compatibility. Arbitrarily high number to cover most
|
||||||
@ -80,10 +81,12 @@ class Api::V1::StatusesController < Api::BaseController
|
|||||||
authorize @status, :destroy?
|
authorize @status, :destroy?
|
||||||
|
|
||||||
@status.discard
|
@status.discard
|
||||||
RemovalWorker.perform_async(@status.id, { 'redraft' => true })
|
|
||||||
@status.account.statuses_count = @status.account.statuses_count - 1
|
@status.account.statuses_count = @status.account.statuses_count - 1
|
||||||
|
json = render_to_body json: @status, serializer: REST::StatusSerializer, source_requested: true
|
||||||
|
|
||||||
render json: @status, serializer: REST::StatusSerializer, source_requested: true
|
RemovalWorker.perform_async(@status.id, { 'redraft' => true })
|
||||||
|
|
||||||
|
render json: json
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -96,8 +99,9 @@ class Api::V1::StatusesController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_thread
|
def set_thread
|
||||||
@thread = status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id])
|
@thread = Status.find(status_params[:in_reply_to_id]) if status_params[:in_reply_to_id].present?
|
||||||
rescue ActiveRecord::RecordNotFound
|
authorize(@thread, :show?) if @thread.present?
|
||||||
|
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||||
render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404
|
render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
class Api::V1::Trends::LinksController < Api::BaseController
|
class Api::V1::Trends::LinksController < Api::BaseController
|
||||||
before_action :set_links
|
before_action :set_links
|
||||||
|
|
||||||
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
|
DEFAULT_LINKS_LIMIT = 10
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: @links, each_serializer: REST::Trends::LinkSerializer
|
render json: @links, each_serializer: REST::Trends::LinkSerializer
|
||||||
end
|
end
|
||||||
@ -20,6 +24,30 @@ class Api::V1::Trends::LinksController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def links_from_trends
|
def links_from_trends
|
||||||
Trends.links.query.allowed.in_locale(content_locale).limit(limit_param(10))
|
Trends.links.query.allowed.in_locale(content_locale).offset(offset_param).limit(limit_param(DEFAULT_LINKS_LIMIT))
|
||||||
|
end
|
||||||
|
|
||||||
|
def insert_pagination_headers
|
||||||
|
set_pagination_headers(next_path, prev_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_params(core_params)
|
||||||
|
params.slice(:limit).permit(:limit).merge(core_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_path
|
||||||
|
api_v1_trends_links_url pagination_params(offset: offset_param + limit_param(DEFAULT_LINKS_LIMIT)) if records_continue?
|
||||||
|
end
|
||||||
|
|
||||||
|
def prev_path
|
||||||
|
api_v1_trends_links_url pagination_params(offset: offset_param - limit_param(DEFAULT_LINKS_LIMIT)) if offset_param > limit_param(DEFAULT_LINKS_LIMIT)
|
||||||
|
end
|
||||||
|
|
||||||
|
def records_continue?
|
||||||
|
@links.size == limit_param(DEFAULT_LINKS_LIMIT)
|
||||||
|
end
|
||||||
|
|
||||||
|
def offset_param
|
||||||
|
params[:offset].to_i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
class Api::V1::Trends::StatusesController < Api::BaseController
|
class Api::V1::Trends::StatusesController < Api::BaseController
|
||||||
before_action :set_statuses
|
before_action :set_statuses
|
||||||
|
|
||||||
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer
|
render json: @statuses, each_serializer: REST::StatusSerializer
|
||||||
end
|
end
|
||||||
@ -22,6 +24,30 @@ class Api::V1::Trends::StatusesController < Api::BaseController
|
|||||||
def statuses_from_trends
|
def statuses_from_trends
|
||||||
scope = Trends.statuses.query.allowed.in_locale(content_locale)
|
scope = Trends.statuses.query.allowed.in_locale(content_locale)
|
||||||
scope = scope.filtered_for(current_account) if user_signed_in?
|
scope = scope.filtered_for(current_account) if user_signed_in?
|
||||||
scope.limit(limit_param(DEFAULT_STATUSES_LIMIT))
|
scope.offset(offset_param).limit(limit_param(DEFAULT_STATUSES_LIMIT))
|
||||||
|
end
|
||||||
|
|
||||||
|
def insert_pagination_headers
|
||||||
|
set_pagination_headers(next_path, prev_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_params(core_params)
|
||||||
|
params.slice(:limit).permit(:limit).merge(core_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_path
|
||||||
|
api_v1_trends_statuses_url pagination_params(offset: offset_param + limit_param(DEFAULT_STATUSES_LIMIT)) if records_continue?
|
||||||
|
end
|
||||||
|
|
||||||
|
def prev_path
|
||||||
|
api_v1_trends_statuses_url pagination_params(offset: offset_param - limit_param(DEFAULT_STATUSES_LIMIT)) if offset_param > limit_param(DEFAULT_STATUSES_LIMIT)
|
||||||
|
end
|
||||||
|
|
||||||
|
def offset_param
|
||||||
|
params[:offset].to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
def records_continue?
|
||||||
|
@statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
class Api::V1::Trends::TagsController < Api::BaseController
|
class Api::V1::Trends::TagsController < Api::BaseController
|
||||||
before_action :set_tags
|
before_action :set_tags
|
||||||
|
|
||||||
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
|
DEFAULT_TAGS_LIMIT = 10
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: @tags, each_serializer: REST::TagSerializer
|
render json: @tags, each_serializer: REST::TagSerializer
|
||||||
end
|
end
|
||||||
@ -12,10 +16,34 @@ class Api::V1::Trends::TagsController < Api::BaseController
|
|||||||
def set_tags
|
def set_tags
|
||||||
@tags = begin
|
@tags = begin
|
||||||
if Setting.trends
|
if Setting.trends
|
||||||
Trends.tags.query.allowed.limit(limit_param(10))
|
Trends.tags.query.allowed.offset(offset_param).limit(limit_param(DEFAULT_TAGS_LIMIT))
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def insert_pagination_headers
|
||||||
|
set_pagination_headers(next_path, prev_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_params(core_params)
|
||||||
|
params.slice(:limit).permit(:limit).merge(core_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_path
|
||||||
|
api_v1_trends_tags_url pagination_params(offset: offset_param + limit_param(DEFAULT_TAGS_LIMIT)) if records_continue?
|
||||||
|
end
|
||||||
|
|
||||||
|
def prev_path
|
||||||
|
api_v1_trends_tags_url pagination_params(offset: offset_param - limit_param(DEFAULT_TAGS_LIMIT)) if offset_param > limit_param(DEFAULT_TAGS_LIMIT)
|
||||||
|
end
|
||||||
|
|
||||||
|
def offset_param
|
||||||
|
params[:offset].to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
def records_continue?
|
||||||
|
@tags.size == limit_param(DEFAULT_TAGS_LIMIT)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
31
app/controllers/api/v2/admin/accounts_controller.rb
Normal file
31
app/controllers/api/v2/admin/accounts_controller.rb
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V2::Admin::AccountsController < Api::V1::Admin::AccountsController
|
||||||
|
FILTER_PARAMS = %i(
|
||||||
|
origin
|
||||||
|
status
|
||||||
|
permissions
|
||||||
|
username
|
||||||
|
by_domain
|
||||||
|
display_name
|
||||||
|
email
|
||||||
|
ip
|
||||||
|
invited_by
|
||||||
|
).freeze
|
||||||
|
|
||||||
|
PAGINATION_PARAMS = (%i(limit) + FILTER_PARAMS).freeze
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def filtered_accounts
|
||||||
|
AccountFilter.new(filter_params).results
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_params
|
||||||
|
params.permit(*FILTER_PARAMS)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_params(core_params)
|
||||||
|
params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params)
|
||||||
|
end
|
||||||
|
end
|
@ -11,6 +11,10 @@ class Api::V2::SearchController < Api::BaseController
|
|||||||
def index
|
def index
|
||||||
@search = Search.new(search_results)
|
@search = Search.new(search_results)
|
||||||
render json: @search, serializer: REST::SearchSerializer
|
render json: @search, serializer: REST::SearchSerializer
|
||||||
|
rescue Mastodon::SyntaxError
|
||||||
|
unprocessable_entity
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -15,7 +15,7 @@ class Api::Web::EmbedsController < Api::Web::BaseController
|
|||||||
return not_found if oembed.nil?
|
return not_found if oembed.nil?
|
||||||
|
|
||||||
begin
|
begin
|
||||||
oembed[:html] = Formatter.instance.sanitize(oembed[:html], Sanitize::Config::MASTODON_OEMBED)
|
oembed[:html] = Sanitize.fragment(oembed[:html], Sanitize::Config::MASTODON_OEMBED)
|
||||||
rescue ArgumentError
|
rescue ArgumentError
|
||||||
return not_found
|
return not_found
|
||||||
end
|
end
|
||||||
|
@ -4,8 +4,6 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||||||
skip_before_action :verify_authenticity_token
|
skip_before_action :verify_authenticity_token
|
||||||
|
|
||||||
def self.provides_callback_for(provider)
|
def self.provides_callback_for(provider)
|
||||||
provider_id = provider.to_s.chomp '_oauth2'
|
|
||||||
|
|
||||||
define_method provider do
|
define_method provider do
|
||||||
@user = User.find_for_oauth(request.env['omniauth.auth'], current_user)
|
@user = User.find_for_oauth(request.env['omniauth.auth'], current_user)
|
||||||
|
|
||||||
@ -20,7 +18,7 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||||||
)
|
)
|
||||||
|
|
||||||
sign_in_and_redirect @user, event: :authentication
|
sign_in_and_redirect @user, event: :authentication
|
||||||
set_flash_message(:notice, :success, kind: provider_id.capitalize) if is_navigational_format?
|
set_flash_message(:notice, :success, kind: Devise.omniauth_configs[provider].strategy.display_name.capitalize) if is_navigational_format?
|
||||||
else
|
else
|
||||||
session["devise.#{provider}_data"] = request.env['omniauth.auth']
|
session["devise.#{provider}_data"] = request.env['omniauth.auth']
|
||||||
redirect_to new_user_registration_url
|
redirect_to new_user_registration_url
|
||||||
@ -33,7 +31,7 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def after_sign_in_path_for(resource)
|
def after_sign_in_path_for(resource)
|
||||||
if resource.email_verified?
|
if resource.email_present?
|
||||||
root_path
|
root_path
|
||||||
else
|
else
|
||||||
auth_setup_path(missing_email: '1')
|
auth_setup_path(missing_email: '1')
|
||||||
|
@ -127,7 +127,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_strikes
|
def set_strikes
|
||||||
@strikes = current_account.strikes.active.latest
|
@strikes = current_account.strikes.recent.latest
|
||||||
end
|
end
|
||||||
|
|
||||||
def require_not_suspended!
|
def require_not_suspended!
|
||||||
|
@ -8,7 +8,6 @@ class Auth::SessionsController < Devise::SessionsController
|
|||||||
skip_before_action :update_user_sign_in
|
skip_before_action :update_user_sign_in
|
||||||
|
|
||||||
include TwoFactorAuthenticationConcern
|
include TwoFactorAuthenticationConcern
|
||||||
include SignInTokenAuthenticationConcern
|
|
||||||
|
|
||||||
before_action :set_instance_presenter, only: [:new]
|
before_action :set_instance_presenter, only: [:new]
|
||||||
before_action :set_body_classes
|
before_action :set_body_classes
|
||||||
@ -66,7 +65,7 @@ class Auth::SessionsController < Devise::SessionsController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
params.require(:user).permit(:email, :password, :otp_attempt, :sign_in_token_attempt, credential: {})
|
params.require(:user).permit(:email, :password, :otp_attempt, credential: {})
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_sign_in_path_for(resource)
|
def after_sign_in_path_for(resource)
|
||||||
@ -142,6 +141,12 @@ class Auth::SessionsController < Devise::SessionsController
|
|||||||
ip: request.remote_ip,
|
ip: request.remote_ip,
|
||||||
user_agent: request.user_agent
|
user_agent: request.user_agent
|
||||||
)
|
)
|
||||||
|
|
||||||
|
UserMailer.suspicious_sign_in(user, request.remote_ip, request.user_agent, Time.now.utc).deliver_later! if suspicious_sign_in?(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def suspicious_sign_in?(user)
|
||||||
|
SuspiciousSignInDetector.new(user).suspicious?(request)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_authentication_failure(user, security_measure, failure_reason)
|
def on_authentication_failure(user, security_measure, failure_reason)
|
||||||
|
@ -13,7 +13,7 @@ class AuthorizeInteractionsController < ApplicationController
|
|||||||
if @resource.is_a?(Account)
|
if @resource.is_a?(Account)
|
||||||
render :show
|
render :show
|
||||||
elsif @resource.is_a?(Status)
|
elsif @resource.is_a?(Status)
|
||||||
redirect_to web_url("statuses/#{@resource.id}")
|
redirect_to web_url("@#{@resource.account.pretty_acct}/#{@resource.id}")
|
||||||
else
|
else
|
||||||
render :error
|
render :error
|
||||||
end
|
end
|
||||||
@ -25,15 +25,17 @@ class AuthorizeInteractionsController < ApplicationController
|
|||||||
else
|
else
|
||||||
render :error
|
render :error
|
||||||
end
|
end
|
||||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
rescue ActiveRecord::RecordNotFound
|
||||||
render :error
|
render :error
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_resource
|
def set_resource
|
||||||
@resource = located_resource || render(:error)
|
@resource = located_resource
|
||||||
authorize(@resource, :show?) if @resource.is_a?(Status)
|
authorize(@resource, :show?) if @resource.is_a?(Status)
|
||||||
|
rescue Mastodon::NotPermittedError
|
||||||
|
not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
def located_resource
|
def located_resource
|
||||||
|
21
app/controllers/concerns/access_token_tracking_concern.rb
Normal file
21
app/controllers/concerns/access_token_tracking_concern.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module AccessTokenTrackingConcern
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
ACCESS_TOKEN_UPDATE_FREQUENCY = 24.hours.freeze
|
||||||
|
|
||||||
|
included do
|
||||||
|
before_action :update_access_token_last_used
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def update_access_token_last_used
|
||||||
|
doorkeeper_token.update_last_used(request) if access_token_needs_update?
|
||||||
|
end
|
||||||
|
|
||||||
|
def access_token_needs_update?
|
||||||
|
doorkeeper_token.present? && (doorkeeper_token.last_used_at.nil? || doorkeeper_token.last_used_at < ACCESS_TOKEN_UPDATE_FREQUENCY.ago)
|
||||||
|
end
|
||||||
|
end
|
@ -3,7 +3,7 @@
|
|||||||
module SessionTrackingConcern
|
module SessionTrackingConcern
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
UPDATE_SIGN_IN_HOURS = 24
|
SESSION_UPDATE_FREQUENCY = 24.hours.freeze
|
||||||
|
|
||||||
included do
|
included do
|
||||||
before_action :set_session_activity
|
before_action :set_session_activity
|
||||||
@ -17,6 +17,6 @@ module SessionTrackingConcern
|
|||||||
end
|
end
|
||||||
|
|
||||||
def session_needs_update?
|
def session_needs_update?
|
||||||
!current_session.nil? && current_session.updated_at < UPDATE_SIGN_IN_HOURS.hours.ago
|
!current_session.nil? && current_session.updated_at < SESSION_UPDATE_FREQUENCY.ago
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module SignInTokenAuthenticationConcern
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
included do
|
|
||||||
prepend_before_action :authenticate_with_sign_in_token, if: :sign_in_token_required?, only: [:create]
|
|
||||||
end
|
|
||||||
|
|
||||||
def sign_in_token_required?
|
|
||||||
find_user&.suspicious_sign_in?(request.remote_ip)
|
|
||||||
end
|
|
||||||
|
|
||||||
def valid_sign_in_token_attempt?(user)
|
|
||||||
Devise.secure_compare(user.sign_in_token, user_params[:sign_in_token_attempt])
|
|
||||||
end
|
|
||||||
|
|
||||||
def authenticate_with_sign_in_token
|
|
||||||
if user_params[:email].present?
|
|
||||||
user = self.resource = find_user_from_params
|
|
||||||
prompt_for_sign_in_token(user) if user&.external_or_valid_password?(user_params[:password])
|
|
||||||
elsif session[:attempt_user_id]
|
|
||||||
user = self.resource = User.find_by(id: session[:attempt_user_id])
|
|
||||||
return if user.nil?
|
|
||||||
|
|
||||||
if session[:attempt_user_updated_at] != user.updated_at.to_s
|
|
||||||
restart_session
|
|
||||||
elsif user_params.key?(:sign_in_token_attempt)
|
|
||||||
authenticate_with_sign_in_token_attempt(user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def authenticate_with_sign_in_token_attempt(user)
|
|
||||||
if valid_sign_in_token_attempt?(user)
|
|
||||||
on_authentication_success(user, :sign_in_token)
|
|
||||||
else
|
|
||||||
on_authentication_failure(user, :sign_in_token, :invalid_sign_in_token)
|
|
||||||
flash.now[:alert] = I18n.t('users.invalid_sign_in_token')
|
|
||||||
prompt_for_sign_in_token(user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def prompt_for_sign_in_token(user)
|
|
||||||
if user.sign_in_token_expired?
|
|
||||||
user.generate_sign_in_token && user.save
|
|
||||||
UserMailer.sign_in_token(user, request.remote_ip, request.user_agent, Time.now.utc.to_s).deliver_later!
|
|
||||||
end
|
|
||||||
|
|
||||||
set_attempt_session(user)
|
|
||||||
|
|
||||||
@body_classes = 'lighter'
|
|
||||||
|
|
||||||
set_locale { render :sign_in_token }
|
|
||||||
end
|
|
||||||
end
|
|
@ -3,7 +3,7 @@
|
|||||||
module UserTrackingConcern
|
module UserTrackingConcern
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
UPDATE_SIGN_IN_FREQUENCY = 24.hours.freeze
|
SIGN_IN_UPDATE_FREQUENCY = 24.hours.freeze
|
||||||
|
|
||||||
included do
|
included do
|
||||||
before_action :update_user_sign_in
|
before_action :update_user_sign_in
|
||||||
@ -16,6 +16,6 @@ module UserTrackingConcern
|
|||||||
end
|
end
|
||||||
|
|
||||||
def user_needs_sign_in_update?
|
def user_needs_sign_in_update?
|
||||||
user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_FREQUENCY.ago)
|
user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < SIGN_IN_UPDATE_FREQUENCY.ago)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Disputes::StrikesController < Disputes::BaseController
|
class Disputes::StrikesController < Disputes::BaseController
|
||||||
before_action :set_strike
|
before_action :set_strike, only: [:show]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@strikes = current_account.strikes.latest
|
||||||
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
authorize @strike, :show?
|
authorize @strike, :show?
|
||||||
|
@ -15,13 +15,13 @@ class FollowerAccountsController < ApplicationController
|
|||||||
format.html do
|
format.html do
|
||||||
expires_in 0, public: true unless user_signed_in?
|
expires_in 0, public: true unless user_signed_in?
|
||||||
|
|
||||||
next if @account.user_hides_network?
|
next if @account.hide_collections?
|
||||||
|
|
||||||
follows
|
follows
|
||||||
end
|
end
|
||||||
|
|
||||||
format.json do
|
format.json do
|
||||||
raise Mastodon::NotPermittedError if page_requested? && @account.user_hides_network?
|
raise Mastodon::NotPermittedError if page_requested? && @account.hide_collections?
|
||||||
|
|
||||||
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
|
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ class FollowerAccountsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def restrict_fields_to
|
def restrict_fields_to
|
||||||
if page_requested? || !@account.user_hides_network?
|
if page_requested? || !@account.hide_collections?
|
||||||
# Return all fields
|
# Return all fields
|
||||||
else
|
else
|
||||||
%i(id type total_items)
|
%i(id type total_items)
|
||||||
|
@ -15,13 +15,16 @@ class FollowingAccountsController < ApplicationController
|
|||||||
format.html do
|
format.html do
|
||||||
expires_in 0, public: true unless user_signed_in?
|
expires_in 0, public: true unless user_signed_in?
|
||||||
|
|
||||||
next if @account.user_hides_network?
|
next if @account.hide_collections?
|
||||||
|
|
||||||
follows
|
follows
|
||||||
end
|
end
|
||||||
|
|
||||||
format.json do
|
format.json do
|
||||||
raise Mastodon::NotPermittedError if page_requested? && @account.user_hides_network?
|
if page_requested? && @account.hide_collections?
|
||||||
|
forbidden
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
|
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
|
||||||
|
|
||||||
@ -82,7 +85,7 @@ class FollowingAccountsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def restrict_fields_to
|
def restrict_fields_to
|
||||||
if page_requested? || !@account.user_hides_network?
|
if page_requested? || !@account.hide_collections?
|
||||||
# Return all fields
|
# Return all fields
|
||||||
else
|
else
|
||||||
%i(id type total_items)
|
%i(id type total_items)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
class MediaProxyController < ApplicationController
|
class MediaProxyController < ApplicationController
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
include Authorization
|
include Authorization
|
||||||
|
include Redisable
|
||||||
|
|
||||||
skip_before_action :store_current_location
|
skip_before_action :store_current_location
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
@ -45,7 +46,7 @@ class MediaProxyController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def lock_options
|
def lock_options
|
||||||
{ redis: Redis.current, key: "media_download:#{params[:id]}", autorelease: 15.minutes.seconds }
|
{ redis: redis, key: "media_download:#{params[:id]}", autorelease: 15.minutes.seconds }
|
||||||
end
|
end
|
||||||
|
|
||||||
def reject_media?
|
def reject_media?
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
class Oauth::TokensController < Doorkeeper::TokensController
|
class Oauth::TokensController < Doorkeeper::TokensController
|
||||||
def revoke
|
def revoke
|
||||||
unsubscribe_for_token if authorized? && token.accessible?
|
unsubscribe_for_token if token.present? && authorized? && token.accessible?
|
||||||
|
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
class Settings::ExportsController < Settings::BaseController
|
class Settings::ExportsController < Settings::BaseController
|
||||||
include Authorization
|
include Authorization
|
||||||
|
include Redisable
|
||||||
|
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
@ -28,6 +29,6 @@ class Settings::ExportsController < Settings::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def lock_options
|
def lock_options
|
||||||
{ redis: Redis.current, key: "backup:#{current_user.id}" }
|
{ redis: redis, key: "backup:#{current_user.id}" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -47,7 +47,6 @@ class Settings::PreferencesController < Settings::BaseController
|
|||||||
:setting_system_font_ui,
|
:setting_system_font_ui,
|
||||||
:setting_noindex,
|
:setting_noindex,
|
||||||
:setting_theme,
|
:setting_theme,
|
||||||
:setting_hide_network,
|
|
||||||
:setting_aggregate_reblogs,
|
:setting_aggregate_reblogs,
|
||||||
:setting_show_application,
|
:setting_show_application,
|
||||||
:setting_advanced_layout,
|
:setting_advanced_layout,
|
||||||
@ -55,7 +54,8 @@ class Settings::PreferencesController < Settings::BaseController
|
|||||||
:setting_use_pending_items,
|
:setting_use_pending_items,
|
||||||
:setting_trends,
|
:setting_trends,
|
||||||
:setting_crop_images,
|
:setting_crop_images,
|
||||||
notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag),
|
:setting_always_send_emails,
|
||||||
|
notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag appeal),
|
||||||
interactions: %i(must_be_follower must_be_following must_be_following_dm)
|
interactions: %i(must_be_follower must_be_following must_be_following_dm)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -20,7 +20,7 @@ class Settings::ProfilesController < Settings::BaseController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def account_params
|
def account_params
|
||||||
params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, fields_attributes: [:name, :value])
|
params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, :hide_collections, fields_attributes: [:name, :value])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_account
|
def set_account
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
module AccountsHelper
|
module AccountsHelper
|
||||||
def display_name(account, **options)
|
def display_name(account, **options)
|
||||||
|
str = account.display_name.presence || account.username
|
||||||
|
|
||||||
if options[:custom_emojify]
|
if options[:custom_emojify]
|
||||||
Formatter.instance.format_display_name(account, **options)
|
prerender_custom_emojis(h(str), account.emojis)
|
||||||
else
|
else
|
||||||
account.display_name.presence || account.username
|
str
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -95,7 +97,7 @@ module AccountsHelper
|
|||||||
].join(' '),
|
].join(' '),
|
||||||
].join(', ')
|
].join(', ')
|
||||||
|
|
||||||
[prepend_str, account.note].join(' · ')
|
[prepend_str, account.note].join(' · ')
|
||||||
end
|
end
|
||||||
|
|
||||||
def svg_logo
|
def svg_logo
|
||||||
|
@ -12,9 +12,6 @@ module Admin::Trends::StatusesHelper
|
|||||||
|
|
||||||
return '' if text.blank?
|
return '' if text.blank?
|
||||||
|
|
||||||
html = Formatter.instance.send(:encode, text)
|
prerender_custom_emojis(h(text), status.emojis)
|
||||||
html = Formatter.instance.send(:encode_custom_emojis, html, status.emojis, prefers_autoplay?)
|
|
||||||
|
|
||||||
html.html_safe # rubocop:disable Rails/OutputSafety
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -9,9 +9,9 @@ module ApplicationHelper
|
|||||||
|
|
||||||
RTL_LOCALES = %i(
|
RTL_LOCALES = %i(
|
||||||
ar
|
ar
|
||||||
|
ckb
|
||||||
fa
|
fa
|
||||||
he
|
he
|
||||||
ku
|
|
||||||
).freeze
|
).freeze
|
||||||
|
|
||||||
def friendly_number_to_human(number, **options)
|
def friendly_number_to_human(number, **options)
|
||||||
@ -19,8 +19,11 @@ module ApplicationHelper
|
|||||||
# is looked up from the locales definition, and rails-i18n comes with
|
# is looked up from the locales definition, and rails-i18n comes with
|
||||||
# values that don't seem to make much sense for many languages, so
|
# values that don't seem to make much sense for many languages, so
|
||||||
# override these values with a default of 3 digits of precision.
|
# override these values with a default of 3 digits of precision.
|
||||||
options[:precision] = 3
|
options = options.merge(
|
||||||
options[:strip_insignificant_zeros] = true
|
precision: 3,
|
||||||
|
strip_insignificant_zeros: true,
|
||||||
|
significant: true
|
||||||
|
)
|
||||||
|
|
||||||
number_to_human(number, **options)
|
number_to_human(number, **options)
|
||||||
end
|
end
|
||||||
@ -224,4 +227,23 @@ module ApplicationHelper
|
|||||||
content_tag(:script, json_escape(json).html_safe, id: 'initial-state', type: 'application/json')
|
content_tag(:script, json_escape(json).html_safe, id: 'initial-state', type: 'application/json')
|
||||||
# rubocop:enable Rails/OutputSafety
|
# rubocop:enable Rails/OutputSafety
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def grouped_scopes(scopes)
|
||||||
|
scope_parser = ScopeParser.new
|
||||||
|
scope_transformer = ScopeTransformer.new
|
||||||
|
|
||||||
|
scopes.each_with_object({}) do |str, h|
|
||||||
|
scope = scope_transformer.apply(scope_parser.parse(str))
|
||||||
|
|
||||||
|
if h[scope.key]
|
||||||
|
h[scope.key].merge!(scope)
|
||||||
|
else
|
||||||
|
h[scope.key] = scope
|
||||||
|
end
|
||||||
|
end.values
|
||||||
|
end
|
||||||
|
|
||||||
|
def prerender_custom_emojis(html, custom_emojis)
|
||||||
|
EmojiFormatter.new(html, custom_emojis, animate: prefers_autoplay?).to_s
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
33
app/helpers/formatting_helper.rb
Normal file
33
app/helpers/formatting_helper.rb
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module FormattingHelper
|
||||||
|
def html_aware_format(text, local, options = {})
|
||||||
|
HtmlAwareFormatter.new(text, local, options).to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def linkify(text, options = {})
|
||||||
|
TextFormatter.new(text, options).to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_status_plain_text(status)
|
||||||
|
PlainTextFormatter.new(status.text, status.local?).to_s
|
||||||
|
end
|
||||||
|
module_function :extract_status_plain_text
|
||||||
|
|
||||||
|
def status_content_format(status)
|
||||||
|
html_aware_format(
|
||||||
|
status.text,
|
||||||
|
status.local?,
|
||||||
|
preloaded_accounts: [status.account] + (status.respond_to?(:active_mentions) ? status.active_mentions.map(&:account) : []),
|
||||||
|
quote: status.respond_to?(:quote) && status.quote,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_bio_format(account)
|
||||||
|
html_aware_format(account.note, account.local?)
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_field_value_format(field, with_rel_me: true)
|
||||||
|
html_aware_format(field.value, field.account.local?, with_rel_me: with_rel_me, with_domains: true, multiline: false)
|
||||||
|
end
|
||||||
|
end
|
@ -15,6 +15,14 @@ module JsonLdHelper
|
|||||||
value.is_a?(Array) ? value.first : value
|
value.is_a?(Array) ? value.first : value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def uri_from_bearcap(str)
|
||||||
|
if str&.start_with?('bear:')
|
||||||
|
Addressable::URI.parse(str).query_values['u']
|
||||||
|
else
|
||||||
|
str
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# The url attribute can be a string, an array of strings, or an array of objects.
|
# The url attribute can be a string, an array of strings, or an array of objects.
|
||||||
# The objects could include a mimeType. Not-included mimeType means it's text/html.
|
# The objects could include a mimeType. Not-included mimeType means it's text/html.
|
||||||
def url_to_href(value, preferred_type = nil)
|
def url_to_href(value, preferred_type = nil)
|
||||||
@ -54,7 +62,7 @@ module JsonLdHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
def unsupported_uri_scheme?(uri)
|
def unsupported_uri_scheme?(uri)
|
||||||
!uri.start_with?('http://', 'https://')
|
uri.nil? || !uri.start_with?('http://', 'https://')
|
||||||
end
|
end
|
||||||
|
|
||||||
def invalid_origin?(url)
|
def invalid_origin?(url)
|
||||||
|
@ -88,7 +88,7 @@ module LanguagesHelper
|
|||||||
ko: ['Korean', '한국어'].freeze,
|
ko: ['Korean', '한국어'].freeze,
|
||||||
kr: ['Kanuri', 'Kanuri'].freeze,
|
kr: ['Kanuri', 'Kanuri'].freeze,
|
||||||
ks: ['Kashmiri', 'कश्मीरी'].freeze,
|
ks: ['Kashmiri', 'कश्मीरी'].freeze,
|
||||||
ku: ['Kurdish', 'Kurdî'].freeze,
|
ku: ['Kurmanji (Kurdish)', 'Kurmancî'].freeze,
|
||||||
kv: ['Komi', 'коми кыв'].freeze,
|
kv: ['Komi', 'коми кыв'].freeze,
|
||||||
kw: ['Cornish', 'Kernewek'].freeze,
|
kw: ['Cornish', 'Kernewek'].freeze,
|
||||||
ky: ['Kyrgyz', 'Кыргызча'].freeze,
|
ky: ['Kyrgyz', 'Кыргызча'].freeze,
|
||||||
@ -108,7 +108,7 @@ module LanguagesHelper
|
|||||||
ml: ['Malayalam', 'മലയാളം'].freeze,
|
ml: ['Malayalam', 'മലയാളം'].freeze,
|
||||||
mn: ['Mongolian', 'Монгол хэл'].freeze,
|
mn: ['Mongolian', 'Монгол хэл'].freeze,
|
||||||
mr: ['Marathi', 'मराठी'].freeze,
|
mr: ['Marathi', 'मराठी'].freeze,
|
||||||
ms: ['Malay', 'Bahasa Malaysia'].freeze,
|
ms: ['Malay', 'Bahasa Melayu'].freeze,
|
||||||
mt: ['Maltese', 'Malti'].freeze,
|
mt: ['Maltese', 'Malti'].freeze,
|
||||||
my: ['Burmese', 'ဗမာစာ'].freeze,
|
my: ['Burmese', 'ဗမာစာ'].freeze,
|
||||||
na: ['Nauru', 'Ekakairũ Naoero'].freeze,
|
na: ['Nauru', 'Ekakairũ Naoero'].freeze,
|
||||||
@ -117,7 +117,7 @@ module LanguagesHelper
|
|||||||
ne: ['Nepali', 'नेपाली'].freeze,
|
ne: ['Nepali', 'नेपाली'].freeze,
|
||||||
ng: ['Ndonga', 'Owambo'].freeze,
|
ng: ['Ndonga', 'Owambo'].freeze,
|
||||||
nl: ['Dutch', 'Nederlands'].freeze,
|
nl: ['Dutch', 'Nederlands'].freeze,
|
||||||
nn: ['Norwegian Nynorsk', 'Norsk nynorsk'].freeze,
|
nn: ['Norwegian Nynorsk', 'Norsk Nynorsk'].freeze,
|
||||||
no: ['Norwegian', 'Norsk'].freeze,
|
no: ['Norwegian', 'Norsk'].freeze,
|
||||||
nr: ['Southern Ndebele', 'isiNdebele'].freeze,
|
nr: ['Southern Ndebele', 'isiNdebele'].freeze,
|
||||||
nv: ['Navajo', 'Diné bizaad'].freeze,
|
nv: ['Navajo', 'Diné bizaad'].freeze,
|
||||||
@ -188,8 +188,9 @@ module LanguagesHelper
|
|||||||
|
|
||||||
ISO_639_3 = {
|
ISO_639_3 = {
|
||||||
ast: ['Asturian', 'Asturianu'].freeze,
|
ast: ['Asturian', 'Asturianu'].freeze,
|
||||||
|
ckb: ['Sorani (Kurdish)', 'سۆرانی'].freeze,
|
||||||
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
||||||
kmr: ['Northern Kurdish', 'Kurmancî'].freeze,
|
kmr: ['Kurmanji (Kurdish)', 'Kurmancî'].freeze,
|
||||||
zgh: ['Standard Moroccan Tamazight', 'ⵜⴰⵎⴰⵣⵉⵖⵜ'].freeze,
|
zgh: ['Standard Moroccan Tamazight', 'ⵜⴰⵎⴰⵣⵉⵖⵜ'].freeze,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
@ -241,6 +242,15 @@ module LanguagesHelper
|
|||||||
code
|
code
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def valid_locale_cascade(*arr)
|
||||||
|
arr.each do |str|
|
||||||
|
locale = valid_locale_or_nil(str)
|
||||||
|
return locale if locale.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
def valid_locale?(locale)
|
def valid_locale?(locale)
|
||||||
locale.present? && SUPPORTED_LOCALES.key?(locale.to_sym)
|
locale.present? && SUPPORTED_LOCALES.key?(locale.to_sym)
|
||||||
end
|
end
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
module RoutingHelper
|
module RoutingHelper
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
include Rails.application.routes.url_helpers
|
include Rails.application.routes.url_helpers
|
||||||
include ActionView::Helpers::AssetTagHelper
|
include ActionView::Helpers::AssetTagHelper
|
||||||
include Webpacker::Helper
|
include Webpacker::Helper
|
||||||
@ -22,8 +23,6 @@ module RoutingHelper
|
|||||||
full_asset_url(asset_pack_path(source, **options))
|
full_asset_url(asset_pack_path(source, **options))
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def use_storage?
|
def use_storage?
|
||||||
Rails.configuration.x.use_s3 || Rails.configuration.x.use_swift
|
Rails.configuration.x.use_s3 || Rails.configuration.x.use_swift
|
||||||
end
|
end
|
||||||
|
@ -113,26 +113,12 @@ module StatusesHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def simplified_text(text)
|
|
||||||
text.dup.tap do |new_text|
|
|
||||||
URI.extract(new_text).each do |url|
|
|
||||||
new_text.gsub!(url, '')
|
|
||||||
end
|
|
||||||
|
|
||||||
new_text.gsub!(Account::MENTION_RE, '')
|
|
||||||
new_text.gsub!(Tag::HASHTAG_RE, '')
|
|
||||||
new_text.gsub!(/\s+/, '')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def embedded_view?
|
def embedded_view?
|
||||||
params[:controller] == EMBEDDED_CONTROLLER && params[:action] == EMBEDDED_ACTION
|
params[:controller] == EMBEDDED_CONTROLLER && params[:action] == EMBEDDED_ACTION
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_video_component(status, **options)
|
def render_video_component(status, **options)
|
||||||
video = status.media_attachments.first
|
video = status.ordered_media_attachments.first
|
||||||
|
|
||||||
meta = video.file.meta || {}
|
meta = video.file.meta || {}
|
||||||
|
|
||||||
@ -150,12 +136,12 @@ module StatusesHelper
|
|||||||
}.merge(**options)
|
}.merge(**options)
|
||||||
|
|
||||||
react_component :video, component_params do
|
react_component :video, component_params do
|
||||||
render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
|
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_audio_component(status, **options)
|
def render_audio_component(status, **options)
|
||||||
audio = status.media_attachments.first
|
audio = status.ordered_media_attachments.first
|
||||||
|
|
||||||
meta = audio.file.meta || {}
|
meta = audio.file.meta || {}
|
||||||
|
|
||||||
@ -170,7 +156,7 @@ module StatusesHelper
|
|||||||
}.merge(**options)
|
}.merge(**options)
|
||||||
|
|
||||||
react_component :audio, component_params do
|
react_component :audio, component_params do
|
||||||
render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
|
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -178,11 +164,11 @@ module StatusesHelper
|
|||||||
component_params = {
|
component_params = {
|
||||||
sensitive: sensitized?(status, current_account),
|
sensitive: sensitized?(status, current_account),
|
||||||
autoplay: prefers_autoplay?,
|
autoplay: prefers_autoplay?,
|
||||||
media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json },
|
media: status.ordered_media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json },
|
||||||
}.merge(**options)
|
}.merge(**options)
|
||||||
|
|
||||||
react_component :media_gallery, component_params do
|
react_component :media_gallery, component_params do
|
||||||
render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
|
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -7,6 +7,10 @@ import {
|
|||||||
expandHomeTimeline,
|
expandHomeTimeline,
|
||||||
connectTimeline,
|
connectTimeline,
|
||||||
disconnectTimeline,
|
disconnectTimeline,
|
||||||
|
fillHomeTimelineGaps,
|
||||||
|
fillPublicTimelineGaps,
|
||||||
|
fillCommunityTimelineGaps,
|
||||||
|
fillListTimelineGaps,
|
||||||
} from './timelines';
|
} from './timelines';
|
||||||
import { updateNotifications, expandNotifications } from './notifications';
|
import { updateNotifications, expandNotifications } from './notifications';
|
||||||
import { updateConversations } from './conversations';
|
import { updateConversations } from './conversations';
|
||||||
@ -35,6 +39,7 @@ const randomUpTo = max =>
|
|||||||
* @param {Object.<string, string>} params
|
* @param {Object.<string, string>} params
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
* @param {function(Function, Function): void} [options.fallback]
|
* @param {function(Function, Function): void} [options.fallback]
|
||||||
|
* @param {function(): void} [options.fillGaps]
|
||||||
* @param {function(object): boolean} [options.accept]
|
* @param {function(object): boolean} [options.accept]
|
||||||
* @return {function(): void}
|
* @return {function(): void}
|
||||||
*/
|
*/
|
||||||
@ -61,6 +66,10 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
|
|||||||
clearTimeout(pollingId);
|
clearTimeout(pollingId);
|
||||||
pollingId = null;
|
pollingId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.fillGaps) {
|
||||||
|
dispatch(options.fillGaps());
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onDisconnect() {
|
onDisconnect() {
|
||||||
@ -119,7 +128,7 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => {
|
|||||||
* @return {function(): void}
|
* @return {function(): void}
|
||||||
*/
|
*/
|
||||||
export const connectUserStream = () =>
|
export const connectUserStream = () =>
|
||||||
connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification });
|
connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification, fillGaps: fillHomeTimelineGaps });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
@ -127,7 +136,7 @@ export const connectUserStream = () =>
|
|||||||
* @return {function(): void}
|
* @return {function(): void}
|
||||||
*/
|
*/
|
||||||
export const connectCommunityStream = ({ onlyMedia } = {}) =>
|
export const connectCommunityStream = ({ onlyMedia } = {}) =>
|
||||||
connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
|
connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`, {}, { fillGaps: () => (fillCommunityTimelineGaps({ onlyMedia })) });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
@ -136,7 +145,7 @@ export const connectCommunityStream = ({ onlyMedia } = {}) =>
|
|||||||
* @return {function(): void}
|
* @return {function(): void}
|
||||||
*/
|
*/
|
||||||
export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) =>
|
export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) =>
|
||||||
connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`);
|
connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, {}, { fillGaps: () => fillPublicTimelineGaps({ onlyMedia, onlyRemote }) });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} columnId
|
* @param {string} columnId
|
||||||
@ -159,4 +168,4 @@ export const connectDirectStream = () =>
|
|||||||
* @return {function(): void}
|
* @return {function(): void}
|
||||||
*/
|
*/
|
||||||
export const connectListStream = listId =>
|
export const connectListStream = listId =>
|
||||||
connectTimelineStream(`list:${listId}`, 'list', { list: listId });
|
connectTimelineStream(`list:${listId}`, 'list', { list: listId }, { fillGaps: () => fillListTimelineGaps(listId) });
|
||||||
|
@ -128,6 +128,22 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function fillTimelineGaps(timelineId, path, params = {}, done = noOp) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
|
||||||
|
const items = timeline.get('items');
|
||||||
|
const nullIndexes = items.map((statusId, index) => statusId === null ? index : null);
|
||||||
|
const gaps = nullIndexes.map(index => index > 0 ? items.get(index - 1) : null);
|
||||||
|
|
||||||
|
// Only expand at most two gaps to avoid doing too many requests
|
||||||
|
done = gaps.take(2).reduce((done, maxId) => {
|
||||||
|
return (() => dispatch(expandTimeline(timelineId, path, { ...params, maxId }, done)));
|
||||||
|
}, done);
|
||||||
|
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
||||||
export const expandPublicTimeline = ({ maxId, onlyMedia, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia }, done);
|
export const expandPublicTimeline = ({ maxId, onlyMedia, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||||
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||||
@ -145,6 +161,11 @@ export const expandHashtagTimeline = (hashtag, { maxId, tags, local } =
|
|||||||
}, done);
|
}, done);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const fillHomeTimelineGaps = (done = noOp) => fillTimelineGaps('home', '/api/v1/timelines/home', {}, done);
|
||||||
|
export const fillPublicTimelineGaps = ({ onlyMedia, onlyRemote } = {}, done = noOp) => fillTimelineGaps(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, only_media: !!onlyMedia }, done);
|
||||||
|
export const fillCommunityTimelineGaps = ({ onlyMedia } = {}, done = noOp) => fillTimelineGaps(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, only_media: !!onlyMedia }, done);
|
||||||
|
export const fillListTimelineGaps = (id, done = noOp) => fillTimelineGaps(`list:${id}`, `/api/v1/timelines/list/${id}`, {}, done);
|
||||||
|
|
||||||
export function expandTimelineRequest(timeline, isLoadingMore) {
|
export function expandTimelineRequest(timeline, isLoadingMore) {
|
||||||
return {
|
return {
|
||||||
type: TIMELINE_EXPAND_REQUEST,
|
type: TIMELINE_EXPAND_REQUEST,
|
||||||
@ -188,6 +209,7 @@ export function connectTimeline(timeline) {
|
|||||||
return {
|
return {
|
||||||
type: TIMELINE_CONNECT,
|
type: TIMELINE_CONNECT,
|
||||||
timeline,
|
timeline,
|
||||||
|
usePendingItems: preferPendingItems,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import api from '../api';
|
import api, { getLinks } from '../api';
|
||||||
import { importFetchedStatuses } from './importer';
|
import { importFetchedStatuses } from './importer';
|
||||||
|
|
||||||
export const TRENDS_TAGS_FETCH_REQUEST = 'TRENDS_TAGS_FETCH_REQUEST';
|
export const TRENDS_TAGS_FETCH_REQUEST = 'TRENDS_TAGS_FETCH_REQUEST';
|
||||||
@ -13,6 +13,10 @@ export const TRENDS_STATUSES_FETCH_REQUEST = 'TRENDS_STATUSES_FETCH_REQUEST';
|
|||||||
export const TRENDS_STATUSES_FETCH_SUCCESS = 'TRENDS_STATUSES_FETCH_SUCCESS';
|
export const TRENDS_STATUSES_FETCH_SUCCESS = 'TRENDS_STATUSES_FETCH_SUCCESS';
|
||||||
export const TRENDS_STATUSES_FETCH_FAIL = 'TRENDS_STATUSES_FETCH_FAIL';
|
export const TRENDS_STATUSES_FETCH_FAIL = 'TRENDS_STATUSES_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const TRENDS_STATUSES_EXPAND_REQUEST = 'TRENDS_STATUSES_EXPAND_REQUEST';
|
||||||
|
export const TRENDS_STATUSES_EXPAND_SUCCESS = 'TRENDS_STATUSES_EXPAND_SUCCESS';
|
||||||
|
export const TRENDS_STATUSES_EXPAND_FAIL = 'TRENDS_STATUSES_EXPAND_FAIL';
|
||||||
|
|
||||||
export const fetchTrendingHashtags = () => (dispatch, getState) => {
|
export const fetchTrendingHashtags = () => (dispatch, getState) => {
|
||||||
dispatch(fetchTrendingHashtagsRequest());
|
dispatch(fetchTrendingHashtagsRequest());
|
||||||
|
|
||||||
@ -68,11 +72,16 @@ export const fetchTrendingLinksFail = error => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const fetchTrendingStatuses = () => (dispatch, getState) => {
|
export const fetchTrendingStatuses = () => (dispatch, getState) => {
|
||||||
|
if (getState().getIn(['status_lists', 'trending', 'isLoading'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(fetchTrendingStatusesRequest());
|
dispatch(fetchTrendingStatusesRequest());
|
||||||
|
|
||||||
api(getState).get('/api/v1/trends/statuses').then(({ data }) => {
|
api(getState).get('/api/v1/trends/statuses').then(response => {
|
||||||
dispatch(importFetchedStatuses(data));
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
dispatch(fetchTrendingStatusesSuccess(data));
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch(fetchTrendingStatusesSuccess(response.data, next ? next.uri : null));
|
||||||
}).catch(err => dispatch(fetchTrendingStatusesFail(err)));
|
}).catch(err => dispatch(fetchTrendingStatusesFail(err)));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -81,9 +90,10 @@ export const fetchTrendingStatusesRequest = () => ({
|
|||||||
skipLoading: true,
|
skipLoading: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const fetchTrendingStatusesSuccess = statuses => ({
|
export const fetchTrendingStatusesSuccess = (statuses, next) => ({
|
||||||
type: TRENDS_STATUSES_FETCH_SUCCESS,
|
type: TRENDS_STATUSES_FETCH_SUCCESS,
|
||||||
statuses,
|
statuses,
|
||||||
|
next,
|
||||||
skipLoading: true,
|
skipLoading: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -93,3 +103,37 @@ export const fetchTrendingStatusesFail = error => ({
|
|||||||
skipLoading: true,
|
skipLoading: true,
|
||||||
skipAlert: true,
|
skipAlert: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export const expandTrendingStatuses = () => (dispatch, getState) => {
|
||||||
|
const url = getState().getIn(['status_lists', 'trending', 'next'], null);
|
||||||
|
|
||||||
|
if (url === null || getState().getIn(['status_lists', 'trending', 'isLoading'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandTrendingStatusesRequest());
|
||||||
|
|
||||||
|
api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch(expandTrendingStatusesSuccess(response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandTrendingStatusesFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const expandTrendingStatusesRequest = () => ({
|
||||||
|
type: TRENDS_STATUSES_EXPAND_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const expandTrendingStatusesSuccess = (statuses, next) => ({
|
||||||
|
type: TRENDS_STATUSES_EXPAND_SUCCESS,
|
||||||
|
statuses,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const expandTrendingStatusesFail = error => ({
|
||||||
|
type: TRENDS_STATUSES_EXPAND_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
@ -33,6 +33,7 @@ export default class Counter extends React.PureComponent {
|
|||||||
label: PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
href: PropTypes.string,
|
href: PropTypes.string,
|
||||||
params: PropTypes.object,
|
params: PropTypes.object,
|
||||||
|
target: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -54,7 +55,7 @@ export default class Counter extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { label, href } = this.props;
|
const { label, href, target } = this.props;
|
||||||
const { loading, data } = this.state;
|
const { loading, data } = this.state;
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
@ -68,12 +69,12 @@ export default class Counter extends React.PureComponent {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const measure = data[0];
|
const measure = data[0];
|
||||||
const percentChange = percIncrease(measure.previous_total * 1, measure.total * 1);
|
const percentChange = measure.previous_total && percIncrease(measure.previous_total * 1, measure.total * 1);
|
||||||
|
|
||||||
content = (
|
content = (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<span className='sparkline__value__total'><FormattedNumber value={measure.total} /></span>
|
<span className='sparkline__value__total'>{measure.human_value || <FormattedNumber value={measure.total} />}</span>
|
||||||
<span className={classNames('sparkline__value__change', { positive: percentChange > 0, negative: percentChange < 0 })}>{percentChange > 0 && '+'}<FormattedNumber value={percentChange} style='percent' /></span>
|
{measure.previous_total && (<span className={classNames('sparkline__value__change', { positive: percentChange > 0, negative: percentChange < 0 })}>{percentChange > 0 && '+'}<FormattedNumber value={percentChange} style='percent' /></span>)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -100,7 +101,7 @@ export default class Counter extends React.PureComponent {
|
|||||||
|
|
||||||
if (href) {
|
if (href) {
|
||||||
return (
|
return (
|
||||||
<a href={href} className='sparkline'>
|
<a href={href} className='sparkline' target={target}>
|
||||||
{inner}
|
{inner}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
@ -25,7 +25,7 @@ export function counterRenderer(counterType, isBold = true) {
|
|||||||
return (displayNumber, pluralReady) => (
|
return (displayNumber, pluralReady) => (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='account.statuses_counter'
|
id='account.statuses_counter'
|
||||||
defaultMessage='{count, plural, one {{counter} Toot} other {{counter} Toots}}'
|
defaultMessage='{count, plural, one {{counter} Post} other {{counter} Posts}}'
|
||||||
values={{
|
values={{
|
||||||
count: pluralReady,
|
count: pluralReady,
|
||||||
counter: renderCounter(displayNumber),
|
counter: renderCounter(displayNumber),
|
||||||
|
116
app/javascript/mastodon/components/media_attachments.js
Normal file
116
app/javascript/mastodon/components/media_attachments.js
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import { MediaGallery, Video, Audio } from 'mastodon/features/ui/util/async-components';
|
||||||
|
import Bundle from 'mastodon/features/ui/components/bundle';
|
||||||
|
import noop from 'lodash/noop';
|
||||||
|
|
||||||
|
export default class MediaAttachments extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
|
height: PropTypes.number,
|
||||||
|
width: PropTypes.number,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
height: 110,
|
||||||
|
width: 239,
|
||||||
|
};
|
||||||
|
|
||||||
|
updateOnProps = [
|
||||||
|
'status',
|
||||||
|
];
|
||||||
|
|
||||||
|
renderLoadingMediaGallery = () => {
|
||||||
|
const { height, width } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='media-gallery' style={{ height, width }} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLoadingVideoPlayer = () => {
|
||||||
|
const { height, width } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='video-player' style={{ height, width }} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLoadingAudioPlayer = () => {
|
||||||
|
const { height, width } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='audio-player' style={{ height, width }} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { status, width, height } = this.props;
|
||||||
|
const mediaAttachments = status.get('media_attachments');
|
||||||
|
|
||||||
|
if (mediaAttachments.size === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mediaAttachments.getIn([0, 'type']) === 'audio') {
|
||||||
|
const audio = mediaAttachments.get(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Bundle fetchComponent={Audio} loading={this.renderLoadingAudioPlayer} >
|
||||||
|
{Component => (
|
||||||
|
<Component
|
||||||
|
src={audio.get('url')}
|
||||||
|
alt={audio.get('description')}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
poster={audio.get('preview_url') || status.getIn(['account', 'avatar_static'])}
|
||||||
|
backgroundColor={audio.getIn(['meta', 'colors', 'background'])}
|
||||||
|
foregroundColor={audio.getIn(['meta', 'colors', 'foreground'])}
|
||||||
|
accentColor={audio.getIn(['meta', 'colors', 'accent'])}
|
||||||
|
duration={audio.getIn(['meta', 'original', 'duration'], 0)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Bundle>
|
||||||
|
);
|
||||||
|
} else if (mediaAttachments.getIn([0, 'type']) === 'video') {
|
||||||
|
const video = mediaAttachments.get(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Bundle fetchComponent={Video} loading={this.renderLoadingVideoPlayer} >
|
||||||
|
{Component => (
|
||||||
|
<Component
|
||||||
|
preview={video.get('preview_url')}
|
||||||
|
frameRate={video.getIn(['meta', 'original', 'frame_rate'])}
|
||||||
|
blurhash={video.get('blurhash')}
|
||||||
|
src={video.get('url')}
|
||||||
|
alt={video.get('description')}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
inline
|
||||||
|
sensitive={status.get('sensitive')}
|
||||||
|
onOpenVideo={noop}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Bundle>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery} >
|
||||||
|
{Component => (
|
||||||
|
<Component
|
||||||
|
media={mediaAttachments}
|
||||||
|
sensitive={status.get('sensitive')}
|
||||||
|
defaultWidth={width}
|
||||||
|
height={height}
|
||||||
|
onOpenMedia={noop}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Bundle>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -151,7 +151,7 @@ class ScrollableList extends PureComponent {
|
|||||||
|
|
||||||
attachFullscreenListener(this.onFullScreenChange);
|
attachFullscreenListener(this.onFullScreenChange);
|
||||||
|
|
||||||
// Handle initial scroll posiiton
|
// Handle initial scroll position
|
||||||
this.handleScroll();
|
this.handleScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ const messages = defineMessages({
|
|||||||
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||||
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
|
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
|
||||||
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers-only' },
|
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers-only' },
|
||||||
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' },
|
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
|
||||||
edited: { id: 'status.edited', defaultMessage: 'Edited {date}' },
|
edited: { id: 'status.edited', defaultMessage: 'Edited {date}' },
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -449,7 +449,7 @@ class Status extends ImmutablePureComponent {
|
|||||||
prepend = (
|
prepend = (
|
||||||
<div className='status__prepend'>
|
<div className='status__prepend'>
|
||||||
<div className='status__prepend-icon-wrapper'><Icon id='thumb-tack' className='status__prepend-icon' fixedWidth /></div>
|
<div className='status__prepend-icon-wrapper'><Icon id='thumb-tack' className='status__prepend-icon' fixedWidth /></div>
|
||||||
<FormattedMessage id='status.pinned' defaultMessage='Pinned toot' />
|
<FormattedMessage id='status.pinned' defaultMessage='Pinned post' />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (status.get('reblog', null) !== null && typeof status.get('reblog') === 'object') {
|
} else if (status.get('reblog', null) !== null && typeof status.get('reblog') === 'object') {
|
||||||
|
@ -281,7 +281,6 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick });
|
menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick });
|
||||||
} else {
|
} else {
|
||||||
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.handleMentionClick });
|
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.handleMentionClick });
|
||||||
menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.handleDirectClick });
|
|
||||||
menu.push(null);
|
menu.push(null);
|
||||||
|
|
||||||
if (relationship && relationship.get('muting')) {
|
if (relationship && relationship.get('muting')) {
|
||||||
|
@ -43,7 +43,7 @@ export default class MediaContainer extends PureComponent {
|
|||||||
|
|
||||||
handleOpenVideo = (options) => {
|
handleOpenVideo = (options) => {
|
||||||
const { components } = this.props;
|
const { components } = this.props;
|
||||||
const { media } = JSON.parse(components[options.componetIndex].getAttribute('data-props'));
|
const { media } = JSON.parse(components[options.componentIndex].getAttribute('data-props'));
|
||||||
const mediaList = fromJS(media);
|
const mediaList = fromJS(media);
|
||||||
|
|
||||||
document.body.classList.add('with-modals--active');
|
document.body.classList.add('with-modals--active');
|
||||||
@ -87,7 +87,7 @@ export default class MediaContainer extends PureComponent {
|
|||||||
...(hashtag ? { hashtag: fromJS(hashtag) } : {}),
|
...(hashtag ? { hashtag: fromJS(hashtag) } : {}),
|
||||||
|
|
||||||
...(componentName === 'Video' ? {
|
...(componentName === 'Video' ? {
|
||||||
componetIndex: i,
|
componentIndex: i,
|
||||||
onOpenVideo: this.handleOpenVideo,
|
onOpenVideo: this.handleOpenVideo,
|
||||||
} : {
|
} : {
|
||||||
onOpenMedia: this.handleOpenMedia,
|
onOpenMedia: this.handleOpenMedia,
|
||||||
|
@ -38,7 +38,7 @@ const messages = defineMessages({
|
|||||||
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },
|
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },
|
||||||
enableNotifications: { id: 'account.enable_notifications', defaultMessage: 'Notify me when @{name} posts' },
|
enableNotifications: { id: 'account.enable_notifications', defaultMessage: 'Notify me when @{name} posts' },
|
||||||
disableNotifications: { id: 'account.disable_notifications', defaultMessage: 'Stop notifying me when @{name} posts' },
|
disableNotifications: { id: 'account.disable_notifications', defaultMessage: 'Stop notifying me when @{name} posts' },
|
||||||
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
|
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' },
|
||||||
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
||||||
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||||
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
|
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
|
||||||
@ -177,7 +177,6 @@ class Header extends ImmutablePureComponent {
|
|||||||
|
|
||||||
if (account.get('id') !== me) {
|
if (account.get('id') !== me) {
|
||||||
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention });
|
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention });
|
||||||
menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.props.onDirect });
|
|
||||||
menu.push(null);
|
menu.push(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,8 +121,8 @@ export default class Header extends ImmutablePureComponent {
|
|||||||
|
|
||||||
{!hideTabs && (
|
{!hideTabs && (
|
||||||
<div className='account__section-headline'>
|
<div className='account__section-headline'>
|
||||||
<NavLink exact to={`/@${account.get('acct')}`}><FormattedMessage id='account.posts' defaultMessage='Toots' /></NavLink>
|
<NavLink exact to={`/@${account.get('acct')}`}><FormattedMessage id='account.posts' defaultMessage='Posts' /></NavLink>
|
||||||
<NavLink exact to={`/@${account.get('acct')}/with_replies`}><FormattedMessage id='account.posts_with_replies' defaultMessage='Toots and replies' /></NavLink>
|
<NavLink exact to={`/@${account.get('acct')}/with_replies`}><FormattedMessage id='account.posts_with_replies' defaultMessage='Posts and replies' /></NavLink>
|
||||||
<NavLink exact to={`/@${account.get('acct')}/media`}><FormattedMessage id='account.media' defaultMessage='Media' /></NavLink>
|
<NavLink exact to={`/@${account.get('acct')}/media`}><FormattedMessage id='account.media' defaultMessage='Media' /></NavLink>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user