mirror of
https://framagit.org/tykayn/mastodon.git
synced 2023-08-25 08:33:12 +02:00
up from glitch
This commit is contained in:
commit
8f91509323
@ -1,8 +1,8 @@
|
|||||||
version: 2.1
|
version: 2.1
|
||||||
|
|
||||||
orbs:
|
orbs:
|
||||||
ruby: circleci/ruby@1.2.0
|
ruby: circleci/ruby@1.4.0
|
||||||
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:
|
||||||
@ -32,7 +32,7 @@ commands:
|
|||||||
name: Install system dependencies
|
name: Install system dependencies
|
||||||
command: |
|
command: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y libicu-dev libidn11-dev libprotobuf-dev protobuf-compiler
|
sudo apt-get install -y libicu-dev libidn11-dev
|
||||||
install-ruby-dependencies:
|
install-ruby-dependencies:
|
||||||
parameters:
|
parameters:
|
||||||
ruby-version:
|
ruby-version:
|
||||||
@ -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
|
@ -107,7 +107,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)
|
||||||
|
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.
|
||||||
|
27
.github/workflows/build-image.yml
vendored
27
.github/workflows/build-image.yml
vendored
@ -3,32 +3,41 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- "main"
|
- 'main'
|
||||||
tags:
|
tags:
|
||||||
- "*"
|
- '*'
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- .github/workflows/build-image.yml
|
||||||
|
- Dockerfile
|
||||||
jobs:
|
jobs:
|
||||||
build-image:
|
build-image:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: docker/setup-qemu-action@v1
|
||||||
- uses: docker/setup-buildx-action@v1
|
- uses: docker/setup-buildx-action@v1
|
||||||
- uses: docker/login-action@v1
|
- uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
registry: ghcr.io
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
- uses: docker/metadata-action@v3
|
- uses: docker/metadata-action@v3
|
||||||
id: meta
|
id: meta
|
||||||
with:
|
with:
|
||||||
images: tootsuite/mastodon
|
images: ghcr.io/${{ github.repository_owner }}/mastodon
|
||||||
flavor: |
|
flavor: |
|
||||||
latest=auto
|
latest=true
|
||||||
tags: |
|
tags: |
|
||||||
type=edge,branch=main
|
type=edge,branch=main
|
||||||
type=semver,pattern={{ raw }}
|
type=match,pattern=v(.*),group=0
|
||||||
|
type=ref,event=pr
|
||||||
- uses: docker/build-push-action@v2
|
- uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
cache-from: type=registry,ref=tootsuite/mastodon:latest
|
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/mastodon:latest
|
||||||
cache-to: type=inline
|
cache-to: type=inline
|
||||||
|
2
.github/workflows/check-i18n.yml
vendored
2
.github/workflows/check-i18n.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
- name: Install system dependencies
|
- name: Install system dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y libicu-dev libidn11-dev libprotobuf-dev protobuf-compiler
|
sudo apt-get install -y libicu-dev libidn11-dev
|
||||||
- name: Set up Ruby
|
- name: Set up Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
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,13 +29,17 @@ Layout/EmptyLineAfterMagicComment:
|
|||||||
Layout/EmptyLineAfterGuardClause:
|
Layout/EmptyLineAfterGuardClause:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Layout/EmptyLineBetweenDefs:
|
||||||
|
AllowAdjacentOneLineDefs: true
|
||||||
|
|
||||||
Layout/EmptyLinesAroundAttributeAccessor:
|
Layout/EmptyLinesAroundAttributeAccessor:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
||||||
|
Layout/FirstHashElementIndentation:
|
||||||
|
EnforcedStyle: consistent
|
||||||
|
|
||||||
Layout/HashAlignment:
|
Layout/HashAlignment:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
# EnforcedHashRocketStyle: table
|
|
||||||
# EnforcedColonStyle: table
|
|
||||||
|
|
||||||
Layout/SpaceAroundMethodCallOperator:
|
Layout/SpaceAroundMethodCallOperator:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
675
AUTHORS.md
675
AUTHORS.md
File diff suppressed because it is too large
Load Diff
2
Aptfile
2
Aptfile
@ -4,10 +4,8 @@ libicu-dev
|
|||||||
libidn11
|
libidn11
|
||||||
libidn11-dev
|
libidn11-dev
|
||||||
libpq-dev
|
libpq-dev
|
||||||
libprotobuf-dev
|
|
||||||
libxdamage1
|
libxdamage1
|
||||||
libxfixes3
|
libxfixes3
|
||||||
protobuf-compiler
|
|
||||||
zlib1g-dev
|
zlib1g-dev
|
||||||
libcairo2
|
libcairo2
|
||||||
libcroco3
|
libcroco3
|
||||||
|
222
CHANGELOG.md
222
CHANGELOG.md
@ -3,12 +3,202 @@ 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.
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
### 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 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 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))
|
||||||
|
|
||||||
## [3.4.6] - 2022-02-03
|
## [3.4.6] - 2022-02-03
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fix `mastodon:webpush:generate_vapid_key` task requiring a functional environment ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17338))
|
- Fix `mastodon:webpush:generate_vapid_key` task requiring a functional environment ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17338))
|
||||||
- Fix spurious errors when receiving an Add activity for a private post ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17425))
|
- Fix spurious errors when receiving an Add activity for a private post ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17425))
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
- Fix error-prone SQL queries ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15828))
|
- Fix error-prone SQL queries ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15828))
|
||||||
- Fix not compacting incoming signed JSON-LD activities ([puckipedia](https://github.com/mastodon/mastodon/pull/17426), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17428)) (CVE-2022-24307)
|
- Fix not compacting incoming signed JSON-LD activities ([puckipedia](https://github.com/mastodon/mastodon/pull/17426), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17428)) (CVE-2022-24307)
|
||||||
- Fix insufficient sanitization of report comments ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17430))
|
- Fix insufficient sanitization of report comments ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17430))
|
||||||
@ -17,10 +207,12 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
## [3.4.5] - 2022-01-31
|
## [3.4.5] - 2022-01-31
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add more advanced migration tests ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17393))
|
- Add more advanced migration tests ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17393))
|
||||||
- Add github workflow to build Docker images ([unasuke](https://github.com/mastodon/mastodon/pull/16973), [Gargron](https://github.com/mastodon/mastodon/pull/16980), [Gargron](https://github.com/mastodon/mastodon/pull/17000))
|
- Add github workflow to build Docker images ([unasuke](https://github.com/mastodon/mastodon/pull/16973), [Gargron](https://github.com/mastodon/mastodon/pull/16980), [Gargron](https://github.com/mastodon/mastodon/pull/17000))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fix some old migrations failing when skipping releases ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17394))
|
- Fix some old migrations failing when skipping releases ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17394))
|
||||||
- Fix migrations script failing in certain edge cases ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17398))
|
- Fix migrations script failing in certain edge cases ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17398))
|
||||||
- Fix Docker build ([tribela](https://github.com/mastodon/mastodon/pull/17188))
|
- Fix Docker build ([tribela](https://github.com/mastodon/mastodon/pull/17188))
|
||||||
@ -83,7 +275,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))
|
||||||
|
|
||||||
@ -416,7 +608,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))
|
||||||
@ -503,7 +695,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))
|
||||||
@ -526,7 +718,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))
|
||||||
@ -552,7 +744,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))
|
||||||
@ -568,14 +760,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))
|
||||||
@ -587,7 +779,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))
|
||||||
@ -702,7 +894,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))
|
||||||
@ -1191,7 +1383,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))
|
||||||
@ -1201,8 +1393,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))
|
||||||
@ -1492,7 +1684,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))
|
||||||
@ -1669,7 +1861,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 \
|
||||||
@ -51,7 +51,7 @@ RUN npm install -g npm@latest && \
|
|||||||
gem install bundler && \
|
gem install bundler && \
|
||||||
apt-get update && \
|
apt-get update && \
|
||||||
apt-get install -y --no-install-recommends git libicu-dev libidn11-dev \
|
apt-get install -y --no-install-recommends git libicu-dev libidn11-dev \
|
||||||
libpq-dev libprotobuf-dev protobuf-compiler shared-mime-info
|
libpq-dev shared-mime-info
|
||||||
|
|
||||||
COPY Gemfile* package.json yarn.lock /opt/mastodon/
|
COPY Gemfile* package.json yarn.lock /opt/mastodon/
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selectio
|
|||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get -y --no-install-recommends install \
|
apt-get -y --no-install-recommends install \
|
||||||
libssl1.1 libpq5 imagemagick ffmpeg libjemalloc2 \
|
libssl1.1 libpq5 imagemagick ffmpeg libjemalloc2 \
|
||||||
libicu66 libprotobuf17 libidn11 libyaml-0-2 \
|
libicu66 libidn11 libyaml-0-2 \
|
||||||
file ca-certificates tzdata libreadline8 gcc tini apt-utils && \
|
file ca-certificates tzdata libreadline8 gcc tini apt-utils && \
|
||||||
ln -s /opt/mastodon /mastodon && \
|
ln -s /opt/mastodon /mastodon && \
|
||||||
gem install bundler && \
|
gem install bundler && \
|
||||||
|
35
Gemfile
35
Gemfile
@ -6,8 +6,8 @@ ruby '>= 2.5.0', '< 3.1.0'
|
|||||||
gem 'pkg-config', '~> 1.4'
|
gem 'pkg-config', '~> 1.4'
|
||||||
gem 'rexml', '~> 3.2'
|
gem 'rexml', '~> 3.2'
|
||||||
|
|
||||||
gem 'puma', '~> 5.5'
|
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'
|
||||||
@ -18,20 +18,18 @@ gem 'makara', '~> 0.5'
|
|||||||
gem 'pghero', '~> 2.8'
|
gem 'pghero', '~> 2.8'
|
||||||
gem 'dotenv-rails', '~> 2.7'
|
gem 'dotenv-rails', '~> 2.7'
|
||||||
|
|
||||||
gem 'aws-sdk-s3', '~> 1.111', require: false
|
gem 'aws-sdk-s3', '~> 1.113', require: false
|
||||||
gem 'fog-core', '<= 2.1.0'
|
gem 'fog-core', '<= 2.1.0'
|
||||||
gem 'fog-openstack', '~> 0.3', require: false
|
gem 'fog-openstack', '~> 0.3', require: false
|
||||||
gem 'kt-paperclip', '~> 7.0'
|
gem 'kt-paperclip', '~> 7.1'
|
||||||
gem 'blurhash', '~> 0.1'
|
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.2', require: false
|
gem 'bootsnap', '~> 1.10.3', require: false
|
||||||
gem 'browser'
|
gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.7'
|
gem 'charlock_holmes', '~> 0.7.7'
|
||||||
gem 'iso-639'
|
|
||||||
gem 'chewy', '~> 7.2'
|
gem 'chewy', '~> 7.2'
|
||||||
gem 'cld3', '~> 3.4.4'
|
|
||||||
gem 'devise', '~> 4.8'
|
gem 'devise', '~> 4.8'
|
||||||
gem 'devise-two-factor', '~> 4.0'
|
gem 'devise-two-factor', '~> 4.0'
|
||||||
|
|
||||||
@ -42,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.5.0', 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,9 +66,9 @@ gem 'oj', '~> 3.13'
|
|||||||
gem 'ox', '~> 2.14'
|
gem 'ox', '~> 2.14'
|
||||||
gem 'parslet'
|
gem 'parslet'
|
||||||
gem 'posix-spawn'
|
gem 'posix-spawn'
|
||||||
gem 'pundit', '~> 2.1'
|
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 +77,7 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
|||||||
gem 'rqrcode', '~> 2.1'
|
gem 'rqrcode', '~> 2.1'
|
||||||
gem 'ruby-progressbar', '~> 1.11'
|
gem 'ruby-progressbar', '~> 1.11'
|
||||||
gem 'sanitize', '~> 6.0'
|
gem 'sanitize', '~> 6.0'
|
||||||
gem 'scenic', '~> 1.5'
|
gem 'scenic', '~> 1.6'
|
||||||
gem 'sidekiq', '~> 6.4'
|
gem 'sidekiq', '~> 6.4'
|
||||||
gem 'sidekiq-scheduler', '~> 3.1'
|
gem 'sidekiq-scheduler', '~> 3.1'
|
||||||
gem 'sidekiq-unique-jobs', '~> 7.1'
|
gem 'sidekiq-unique-jobs', '~> 7.1'
|
||||||
@ -90,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'
|
||||||
@ -102,12 +101,12 @@ gem 'rdf-normalize', '~> 0.5'
|
|||||||
gem 'redcarpet', '~> 3.5'
|
gem 'redcarpet', '~> 3.5'
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'fabrication', '~> 2.24'
|
gem 'fabrication', '~> 2.27'
|
||||||
gem 'fuubar', '~> 2.5'
|
gem 'fuubar', '~> 2.5'
|
||||||
gem 'i18n-tasks', '~> 0.9', require: false
|
gem 'i18n-tasks', '~> 0.9', 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.0'
|
gem 'rspec-rails', '~> 5.1'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :production, :test do
|
group :production, :test do
|
||||||
@ -117,7 +116,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 +127,15 @@ end
|
|||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'active_record_query_trace', '~> 1.8'
|
gem 'active_record_query_trace', '~> 1.8'
|
||||||
gem 'annotate', '~> 3.1'
|
gem 'annotate', '~> 3.2'
|
||||||
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.26', 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
|
||||||
|
|
||||||
|
322
Gemfile.lock
322
Gemfile.lock
@ -1,40 +1,40 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.1.4.4)
|
actioncable (6.1.5)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.5)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.1.4.4)
|
actionmailbox (6.1.5)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.5)
|
||||||
activejob (= 6.1.4.4)
|
activejob (= 6.1.5)
|
||||||
activerecord (= 6.1.4.4)
|
activerecord (= 6.1.5)
|
||||||
activestorage (= 6.1.4.4)
|
activestorage (= 6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.5)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.1.4.4)
|
actionmailer (6.1.5)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.5)
|
||||||
actionview (= 6.1.4.4)
|
actionview (= 6.1.5)
|
||||||
activejob (= 6.1.4.4)
|
activejob (= 6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
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.4)
|
actionpack (6.1.5)
|
||||||
actionview (= 6.1.4.4)
|
actionview (= 6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
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.4)
|
actiontext (6.1.5)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.5)
|
||||||
activerecord (= 6.1.4.4)
|
activerecord (= 6.1.5)
|
||||||
activestorage (= 6.1.4.4)
|
activestorage (= 6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.5)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.1.4.4)
|
actionview (6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
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.4)
|
activejob (6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.5)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.1.4.4)
|
activemodel (6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.5)
|
||||||
activerecord (6.1.4.4)
|
activerecord (6.1.5)
|
||||||
activemodel (= 6.1.4.4)
|
activemodel (= 6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.5)
|
||||||
activestorage (6.1.4.4)
|
activestorage (6.1.5)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.5)
|
||||||
activejob (= 6.1.4.4)
|
activejob (= 6.1.5)
|
||||||
activerecord (= 6.1.4.4)
|
activerecord (= 6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
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.4)
|
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,28 +68,30 @@ 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)
|
||||||
annotate (3.1.1)
|
annotate (3.2.0)
|
||||||
activerecord (>= 3.2, < 7.0)
|
activerecord (>= 3.2, < 8.0)
|
||||||
rake (>= 10.4, < 14.0)
|
rake (>= 10.4, < 14.0)
|
||||||
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.549.0)
|
aws-partitions (1.558.0)
|
||||||
aws-sdk-core (3.125.5)
|
aws-sdk-core (3.127.0)
|
||||||
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.53.0)
|
aws-sdk-kms (1.55.0)
|
||||||
aws-sdk-core (~> 3, >= 3.125.0)
|
aws-sdk-core (~> 3, >= 3.127.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sdk-s3 (1.111.3)
|
aws-sdk-s3 (1.113.0)
|
||||||
aws-sdk-core (~> 3, >= 3.125.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.4.0)
|
||||||
@ -102,11 +104,11 @@ GEM
|
|||||||
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.2)
|
bootsnap (1.10.3)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (5.2.0)
|
brakeman (5.2.1)
|
||||||
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)
|
||||||
@ -126,7 +128,7 @@ GEM
|
|||||||
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)
|
||||||
@ -147,13 +149,11 @@ GEM
|
|||||||
activesupport
|
activesupport
|
||||||
cbor (0.5.9.6)
|
cbor (0.5.9.6)
|
||||||
charlock_holmes (0.7.7)
|
charlock_holmes (0.7.7)
|
||||||
chewy (7.2.3)
|
chewy (7.2.4)
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
elasticsearch (>= 7.12.0, < 7.14.0)
|
elasticsearch (>= 7.12.0, < 7.14.0)
|
||||||
elasticsearch-dsl
|
elasticsearch-dsl
|
||||||
chunky_png (1.4.0)
|
chunky_png (1.4.0)
|
||||||
cld3 (3.4.4)
|
|
||||||
ffi (>= 1.1.0, < 1.16.0)
|
|
||||||
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)
|
||||||
@ -183,7 +183,7 @@ GEM
|
|||||||
devise_pam_authenticatable2 (9.2.0)
|
devise_pam_authenticatable2 (9.2.0)
|
||||||
devise (>= 4.0.0)
|
devise (>= 4.0.0)
|
||||||
rpam2 (~> 4.0)
|
rpam2 (~> 4.0)
|
||||||
diff-lcs (1.4.4)
|
diff-lcs (1.5.0)
|
||||||
discard (1.2.1)
|
discard (1.2.1)
|
||||||
activerecord (>= 4.2, < 8)
|
activerecord (>= 4.2, < 8)
|
||||||
docile (1.3.4)
|
docile (1.3.4)
|
||||||
@ -208,31 +208,35 @@ 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.4)
|
et-orbi (1.2.6)
|
||||||
tzinfo
|
tzinfo
|
||||||
excon (0.76.0)
|
excon (0.76.0)
|
||||||
fabrication (2.24.0)
|
fabrication (2.27.0)
|
||||||
faker (2.19.0)
|
faker (2.20.0)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
faraday (1.8.0)
|
faraday (1.9.3)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-em_http (~> 1.0)
|
||||||
faraday-em_synchrony (~> 1.0)
|
faraday-em_synchrony (~> 1.0)
|
||||||
faraday-excon (~> 1.1)
|
faraday-excon (~> 1.1)
|
||||||
faraday-httpclient (~> 1.0.1)
|
faraday-httpclient (~> 1.0)
|
||||||
|
faraday-multipart (~> 1.0)
|
||||||
faraday-net_http (~> 1.0)
|
faraday-net_http (~> 1.0)
|
||||||
faraday-net_http_persistent (~> 1.1)
|
faraday-net_http_persistent (~> 1.0)
|
||||||
faraday-patron (~> 1.0)
|
faraday-patron (~> 1.0)
|
||||||
faraday-rack (~> 1.0)
|
faraday-rack (~> 1.0)
|
||||||
multipart-post (>= 1.2, < 3)
|
faraday-retry (~> 1.0)
|
||||||
ruby2_keywords (>= 0.0.4)
|
ruby2_keywords (>= 0.0.4)
|
||||||
faraday-em_http (1.0.0)
|
faraday-em_http (1.0.0)
|
||||||
faraday-em_synchrony (1.0.0)
|
faraday-em_synchrony (1.0.0)
|
||||||
faraday-excon (1.1.0)
|
faraday-excon (1.1.0)
|
||||||
faraday-httpclient (1.0.1)
|
faraday-httpclient (1.0.1)
|
||||||
|
faraday-multipart (1.0.3)
|
||||||
|
multipart-post (>= 1.2, < 3)
|
||||||
faraday-net_http (1.0.1)
|
faraday-net_http (1.0.1)
|
||||||
faraday-net_http_persistent (1.2.0)
|
faraday-net_http_persistent (1.2.0)
|
||||||
faraday-patron (1.0.0)
|
faraday-patron (1.0.0)
|
||||||
faraday-rack (1.0.0)
|
faraday-rack (1.0.0)
|
||||||
|
faraday-retry (1.0.3)
|
||||||
fast_blank (1.0.1)
|
fast_blank (1.0.1)
|
||||||
fastimage (2.2.6)
|
fastimage (2.2.6)
|
||||||
ffi (1.15.5)
|
ffi (1.15.5)
|
||||||
@ -252,12 +256,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.4.5)
|
fugit (1.5.2)
|
||||||
et-orbi (~> 1.1, >= 1.1.8)
|
et-orbi (~> 1.1, >= 1.1.8)
|
||||||
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.5.0)
|
||||||
|
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)
|
||||||
@ -286,10 +294,11 @@ 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.8.11)
|
i18n (1.10.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
i18n-tasks (0.9.37)
|
i18n-tasks (0.9.37)
|
||||||
activesupport (>= 4.0.2)
|
activesupport (>= 4.0.2)
|
||||||
@ -303,10 +312,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)
|
||||||
iso-639 (0.3.5)
|
jmespath (1.6.0)
|
||||||
jmespath (1.5.0)
|
|
||||||
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)
|
||||||
@ -331,7 +343,7 @@ GEM
|
|||||||
activerecord
|
activerecord
|
||||||
kaminari-core (= 1.2.2)
|
kaminari-core (= 1.2.2)
|
||||||
kaminari-core (1.2.2)
|
kaminari-core (1.2.2)
|
||||||
kt-paperclip (7.0.1)
|
kt-paperclip (7.1.1)
|
||||||
activemodel (>= 4.2.0)
|
activemodel (>= 4.2.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
marcel (~> 1.0.1)
|
marcel (~> 1.0.1)
|
||||||
@ -339,8 +351,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)
|
||||||
@ -355,14 +367,14 @@ GEM
|
|||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
loofah (2.13.0)
|
loofah (2.15.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)
|
||||||
mini_mime (>= 0.1.1)
|
mini_mime (>= 0.1.1)
|
||||||
makara (0.5.1)
|
makara (0.5.1)
|
||||||
activerecord (>= 5.2.0)
|
activerecord (>= 5.2.0)
|
||||||
marcel (1.0.1)
|
marcel (1.0.2)
|
||||||
mario-redis-lock (1.2.1)
|
mario-redis-lock (1.2.1)
|
||||||
redis (>= 3.0.5)
|
redis (>= 3.0.5)
|
||||||
matrix (0.4.2)
|
matrix (0.4.2)
|
||||||
@ -373,9 +385,9 @@ GEM
|
|||||||
nokogiri (~> 1.10)
|
nokogiri (~> 1.10)
|
||||||
mime-types (3.4.1)
|
mime-types (3.4.1)
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2021.1115)
|
mime-types-data (3.2022.0105)
|
||||||
mini_mime (1.1.2)
|
mini_mime (1.1.2)
|
||||||
mini_portile2 (2.7.1)
|
mini_portile2 (2.8.0)
|
||||||
minitest (5.15.0)
|
minitest (5.15.0)
|
||||||
msgpack (1.4.4)
|
msgpack (1.4.4)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
@ -385,8 +397,8 @@ 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.1)
|
nokogiri (1.13.3)
|
||||||
mini_portile2 (~> 2.7.0)
|
mini_portile2 (~> 2.8.0)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nsa (0.2.8)
|
nsa (0.2.8)
|
||||||
activesupport (>= 4.2, < 7)
|
activesupport (>= 4.2, < 7)
|
||||||
@ -407,17 +419,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.2.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.6)
|
ox (2.14.10)
|
||||||
parallel (1.21.0)
|
parallel (1.22.0)
|
||||||
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.0)
|
pg (1.3.4)
|
||||||
pghero (2.8.2)
|
pghero (2.8.2)
|
||||||
activerecord (>= 5)
|
activerecord (>= 5)
|
||||||
pkg-config (1.4.7)
|
pkg-config (1.4.7)
|
||||||
@ -439,35 +461,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.5.2)
|
puma (5.6.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
pundit (2.1.1)
|
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.0)
|
||||||
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.16.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.4)
|
rails (6.1.5)
|
||||||
actioncable (= 6.1.4.4)
|
actioncable (= 6.1.5)
|
||||||
actionmailbox (= 6.1.4.4)
|
actionmailbox (= 6.1.5)
|
||||||
actionmailer (= 6.1.4.4)
|
actionmailer (= 6.1.5)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.5)
|
||||||
actiontext (= 6.1.4.4)
|
actiontext (= 6.1.5)
|
||||||
actionview (= 6.1.4.4)
|
actionview (= 6.1.5)
|
||||||
activejob (= 6.1.4.4)
|
activejob (= 6.1.5)
|
||||||
activemodel (= 6.1.4.4)
|
activemodel (= 6.1.5)
|
||||||
activerecord (= 6.1.4.4)
|
activerecord (= 6.1.5)
|
||||||
activestorage (= 6.1.4.4)
|
activestorage (= 6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
activesupport (= 6.1.5)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 6.1.4.4)
|
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)
|
||||||
@ -483,11 +511,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.4)
|
railties (6.1.5)
|
||||||
actionpack (= 6.1.4.4)
|
actionpack (= 6.1.5)
|
||||||
activesupport (= 6.1.4.4)
|
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)
|
||||||
@ -497,9 +525,9 @@ GEM
|
|||||||
rdf (~> 3.2)
|
rdf (~> 3.2)
|
||||||
redcarpet (3.5.1)
|
redcarpet (3.5.1)
|
||||||
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.2.1)
|
||||||
request_store (1.5.0)
|
request_store (1.5.0)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
responders (3.0.1)
|
responders (3.0.1)
|
||||||
@ -508,19 +536,19 @@ GEM
|
|||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
rotp (6.2.0)
|
rotp (6.2.0)
|
||||||
rpam2 (4.0.2)
|
rpam2 (4.0.2)
|
||||||
rqrcode (2.1.0)
|
rqrcode (2.1.1)
|
||||||
chunky_png (~> 1.0)
|
chunky_png (~> 1.0)
|
||||||
rqrcode_core (~> 1.0)
|
rqrcode_core (~> 1.0)
|
||||||
rqrcode_core (1.2.0)
|
rqrcode_core (1.2.0)
|
||||||
rspec-core (3.10.1)
|
rspec-core (3.11.0)
|
||||||
rspec-support (~> 3.10.0)
|
rspec-support (~> 3.11.0)
|
||||||
rspec-expectations (3.10.1)
|
rspec-expectations (3.11.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.10.0)
|
rspec-support (~> 3.11.0)
|
||||||
rspec-mocks (3.10.2)
|
rspec-mocks (3.11.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.10.0)
|
rspec-support (~> 3.11.0)
|
||||||
rspec-rails (5.0.2)
|
rspec-rails (5.1.1)
|
||||||
actionpack (>= 5.2)
|
actionpack (>= 5.2)
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
@ -531,21 +559,21 @@ GEM
|
|||||||
rspec-sidekiq (3.1.0)
|
rspec-sidekiq (3.1.0)
|
||||||
rspec-core (~> 3.0, >= 3.0.0)
|
rspec-core (~> 3.0, >= 3.0.0)
|
||||||
sidekiq (>= 2.4.0)
|
sidekiq (>= 2.4.0)
|
||||||
rspec-support (3.10.3)
|
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.0)
|
rubocop (1.26.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.16.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)
|
||||||
@ -554,32 +582,32 @@ GEM
|
|||||||
nokogiri (>= 1.10.5)
|
nokogiri (>= 1.10.5)
|
||||||
rexml
|
rexml
|
||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
rufus-scheduler (3.7.0)
|
rufus-scheduler (3.8.1)
|
||||||
fugit (~> 1.1, >= 1.1.6)
|
fugit (~> 1.1, >= 1.1.6)
|
||||||
safety_net_attestation (0.4.0)
|
safety_net_attestation (0.4.0)
|
||||||
jwt (~> 2.0)
|
jwt (~> 2.0)
|
||||||
sanitize (6.0.0)
|
sanitize (6.0.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.12.0)
|
nokogiri (>= 1.12.0)
|
||||||
scenic (1.5.5)
|
scenic (1.6.0)
|
||||||
activerecord (>= 4.0.0)
|
activerecord (>= 4.0.0)
|
||||||
railties (>= 4.0.0)
|
railties (>= 4.0.0)
|
||||||
securecompare (1.0.0)
|
securecompare (1.0.0)
|
||||||
semantic_range (3.0.0)
|
semantic_range (3.0.0)
|
||||||
sidekiq (6.4.0)
|
sidekiq (6.4.1)
|
||||||
connection_pool (>= 2.2.2)
|
connection_pool (>= 2.2.2)
|
||||||
rack (~> 2.0)
|
rack (~> 2.0)
|
||||||
redis (>= 4.2.0)
|
redis (>= 4.2.0)
|
||||||
sidekiq-bulk (0.2.0)
|
sidekiq-bulk (0.2.0)
|
||||||
sidekiq
|
sidekiq
|
||||||
sidekiq-scheduler (3.1.0)
|
sidekiq-scheduler (3.1.1)
|
||||||
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.12)
|
sidekiq-unique-jobs (7.1.15)
|
||||||
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)
|
||||||
@ -605,11 +633,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.2.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)
|
||||||
@ -637,13 +669,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)
|
||||||
@ -656,6 +694,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.1.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)
|
||||||
@ -675,7 +716,7 @@ GEM
|
|||||||
xorcist (1.1.2)
|
xorcist (1.1.2)
|
||||||
xpath (3.2.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
zeitwerk (2.5.3)
|
zeitwerk (2.5.4)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
@ -684,12 +725,12 @@ DEPENDENCIES
|
|||||||
active_model_serializers (~> 0.10)
|
active_model_serializers (~> 0.10)
|
||||||
active_record_query_trace (~> 1.8)
|
active_record_query_trace (~> 1.8)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
annotate (~> 3.1)
|
annotate (~> 3.2)
|
||||||
aws-sdk-s3 (~> 1.111)
|
aws-sdk-s3 (~> 1.113)
|
||||||
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.2)
|
bootsnap (~> 1.10.3)
|
||||||
brakeman (~> 5.2)
|
brakeman (~> 5.2)
|
||||||
browser
|
browser
|
||||||
bullet (~> 7.0)
|
bullet (~> 7.0)
|
||||||
@ -701,7 +742,6 @@ DEPENDENCIES
|
|||||||
capybara (~> 3.36)
|
capybara (~> 3.36)
|
||||||
charlock_holmes (~> 0.7.7)
|
charlock_holmes (~> 0.7.7)
|
||||||
chewy (~> 7.2)
|
chewy (~> 7.2)
|
||||||
cld3 (~> 3.4.4)
|
|
||||||
climate_control (~> 0.2)
|
climate_control (~> 0.2)
|
||||||
color_diff (~> 0.1)
|
color_diff (~> 0.1)
|
||||||
concurrent-ruby
|
concurrent-ruby
|
||||||
@ -713,13 +753,14 @@ DEPENDENCIES
|
|||||||
doorkeeper (~> 5.5)
|
doorkeeper (~> 5.5)
|
||||||
dotenv-rails (~> 2.7)
|
dotenv-rails (~> 2.7)
|
||||||
ed25519 (~> 1.3)
|
ed25519 (~> 1.3)
|
||||||
fabrication (~> 2.24)
|
fabrication (~> 2.27)
|
||||||
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.5.0)
|
||||||
hamlit-rails (~> 0.2)
|
hamlit-rails (~> 0.2)
|
||||||
hcaptcha (~> 7.1)
|
hcaptcha (~> 7.1)
|
||||||
hiredis (~> 0.6)
|
hiredis (~> 0.6)
|
||||||
@ -729,12 +770,11 @@ DEPENDENCIES
|
|||||||
httplog (~> 1.5.0)
|
httplog (~> 1.5.0)
|
||||||
i18n-tasks (~> 0.9)
|
i18n-tasks (~> 0.9)
|
||||||
idn-ruby
|
idn-ruby
|
||||||
iso-639
|
|
||||||
json-ld
|
json-ld
|
||||||
json-ld-preloaded (~> 3.2)
|
json-ld-preloaded (~> 3.2)
|
||||||
kaminari (~> 1.2)
|
kaminari (~> 1.2)
|
||||||
kt-paperclip (~> 7.0)
|
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.11)
|
||||||
@ -761,12 +801,12 @@ DEPENDENCIES
|
|||||||
private_address_check (~> 0.5)
|
private_address_check (~> 0.5)
|
||||||
pry-byebug (~> 3.9)
|
pry-byebug (~> 3.9)
|
||||||
pry-rails (~> 0.3)
|
pry-rails (~> 0.3)
|
||||||
puma (~> 5.5)
|
puma (~> 5.6)
|
||||||
pundit (~> 2.1)
|
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)
|
||||||
@ -776,14 +816,14 @@ DEPENDENCIES
|
|||||||
redis-namespace (~> 1.8)
|
redis-namespace (~> 1.8)
|
||||||
rexml (~> 3.2)
|
rexml (~> 3.2)
|
||||||
rqrcode (~> 2.1)
|
rqrcode (~> 2.1)
|
||||||
rspec-rails (~> 5.0)
|
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.26)
|
||||||
rubocop-rails (~> 2.13)
|
rubocop-rails (~> 2.14)
|
||||||
ruby-progressbar (~> 1.11)
|
ruby-progressbar (~> 1.11)
|
||||||
sanitize (~> 6.0)
|
sanitize (~> 6.0)
|
||||||
scenic (~> 1.5)
|
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.1)
|
||||||
@ -799,7 +839,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)
|
||||||
|
18
SECURITY.md
18
SECURITY.md
@ -1,13 +1,19 @@
|
|||||||
# 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.4.x | Yes |
|
||||||
| 3.3.x | :white_check_mark: |
|
| 3.3.x | Yes |
|
||||||
| < 3.3 | :x: |
|
| < 3.3 | No |
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
[bug-bounty]: https://app.intigriti.com/programs/mastodon/mastodonio/detail
|
||||||
|
|
||||||
hello@joinmastodon.org
|
|
||||||
|
2
Vagrantfile
vendored
2
Vagrantfile
vendored
@ -33,11 +33,9 @@ sudo apt-get install \
|
|||||||
redis-tools \
|
redis-tools \
|
||||||
postgresql \
|
postgresql \
|
||||||
postgresql-contrib \
|
postgresql-contrib \
|
||||||
protobuf-compiler \
|
|
||||||
yarn \
|
yarn \
|
||||||
libicu-dev \
|
libicu-dev \
|
||||||
libidn11-dev \
|
libidn11-dev \
|
||||||
libprotobuf-dev \
|
|
||||||
libreadline-dev \
|
libreadline-dev \
|
||||||
libpam0g-dev \
|
libpam0g-dev \
|
||||||
-y
|
-y
|
||||||
|
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"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ class StatusesIndex < Chewy::Index
|
|||||||
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.spoiler_text, Formatter.instance.plaintext(status)].concat(status.ordered_media_attachments.map(&:description)).concat(status.preloadable_poll ? status.preloadable_poll.options : []).join("\n\n") } 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)
|
||||||
|
@ -63,15 +63,29 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def next_page
|
def next_page
|
||||||
only_other_accounts = !(@replies&.last&.account_id == @account.id && @replies.size == DESCENDANTS_LIMIT)
|
if only_other_accounts?
|
||||||
|
# Only consider remote accounts
|
||||||
|
return nil if @replies.size < DESCENDANTS_LIMIT
|
||||||
|
|
||||||
account_status_replies_url(
|
account_status_replies_url(
|
||||||
@account,
|
@account,
|
||||||
@status,
|
@status,
|
||||||
page: true,
|
page: true,
|
||||||
min_id: only_other_accounts && !only_other_accounts? ? nil : @replies&.last&.id,
|
min_id: @replies&.last&.id,
|
||||||
only_other_accounts: only_other_accounts
|
only_other_accounts: true
|
||||||
)
|
)
|
||||||
|
else
|
||||||
|
# For now, we're serving only self-replies, but next page might be other accounts
|
||||||
|
next_only_other_accounts = @replies&.last&.account_id != @account.id || @replies.size < DESCENDANTS_LIMIT
|
||||||
|
|
||||||
|
account_status_replies_url(
|
||||||
|
@account,
|
||||||
|
@status,
|
||||||
|
page: true,
|
||||||
|
min_id: next_only_other_accounts ? nil : @replies&.last&.id,
|
||||||
|
only_other_accounts: next_only_other_accounts
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def page_params
|
def page_params
|
||||||
|
@ -28,7 +28,7 @@ module Admin
|
|||||||
@deletion_request = @account.deletion_request
|
@deletion_request = @account.deletion_request
|
||||||
@account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)
|
@account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)
|
||||||
@moderation_notes = @account.targeted_moderation_notes.latest
|
@moderation_notes = @account.targeted_moderation_notes.latest
|
||||||
@warnings = @account.strikes.custom.latest
|
@warnings = @account.strikes.includes(:target_account, :account, :appeal).latest
|
||||||
@domain_block = DomainBlock.rule_for(@account.domain)
|
@domain_block = DomainBlock.rule_for(@account.domain)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ module Admin
|
|||||||
end
|
end
|
||||||
|
|
||||||
def filter_params
|
def filter_params
|
||||||
params.slice(*AccountFilter::KEYS).permit(*AccountFilter::KEYS)
|
params.slice(:page, *AccountFilter::KEYS).permit(:page, *AccountFilter::KEYS)
|
||||||
end
|
end
|
||||||
|
|
||||||
def form_account_batch_params
|
def form_account_batch_params
|
||||||
|
@ -35,6 +35,9 @@ module Admin
|
|||||||
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
||||||
rescue Mastodon::NotPermittedError
|
rescue Mastodon::NotPermittedError
|
||||||
flash[:alert] = I18n.t('admin.custom_emojis.not_permitted')
|
flash[:alert] = I18n.t('admin.custom_emojis.not_permitted')
|
||||||
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
|
error_message = action_from_button == 'copy' ? 'admin.custom_emojis.batch_copy_error' : 'admin.custom_emojis.batch_error'
|
||||||
|
flash[:alert] = I18n.t(error_message, message: e.message)
|
||||||
ensure
|
ensure
|
||||||
redirect_to admin_custom_emojis_path(filter_params)
|
redirect_to admin_custom_emojis_path(filter_params)
|
||||||
end
|
end
|
||||||
|
@ -8,6 +8,7 @@ module Admin
|
|||||||
@pending_users_count = User.pending.count
|
@pending_users_count = User.pending.count
|
||||||
@pending_reports_count = Report.unresolved.count
|
@pending_reports_count = Report.unresolved.count
|
||||||
@pending_tags_count = Tag.pending_review.count
|
@pending_tags_count = Tag.pending_review.count
|
||||||
|
@pending_appeals_count = Appeal.pending.count
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
40
app/controllers/admin/disputes/appeals_controller.rb
Normal file
40
app/controllers/admin/disputes/appeals_controller.rb
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Admin::Disputes::AppealsController < Admin::BaseController
|
||||||
|
before_action :set_appeal, except: :index
|
||||||
|
|
||||||
|
def index
|
||||||
|
authorize :appeal, :index?
|
||||||
|
|
||||||
|
@appeals = filtered_appeals.page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
|
def approve
|
||||||
|
authorize @appeal, :approve?
|
||||||
|
log_action :approve, @appeal
|
||||||
|
ApproveAppealService.new.call(@appeal, current_account)
|
||||||
|
redirect_to disputes_strike_path(@appeal.strike)
|
||||||
|
end
|
||||||
|
|
||||||
|
def reject
|
||||||
|
authorize @appeal, :approve?
|
||||||
|
log_action :reject, @appeal
|
||||||
|
@appeal.reject!(current_account)
|
||||||
|
UserMailer.appeal_rejected(@appeal.account.user, @appeal)
|
||||||
|
redirect_to disputes_strike_path(@appeal.strike)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def filtered_appeals
|
||||||
|
Admin::AppealFilter.new(filter_params.with_defaults(status: 'pending')).results.includes(strike: :account)
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_params
|
||||||
|
params.slice(:page, *Admin::AppealFilter::KEYS).permit(:page, *Admin::AppealFilter::KEYS)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_appeal
|
||||||
|
@appeal = Appeal.find(params[:id])
|
||||||
|
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)
|
||||||
|
@ -6,7 +6,20 @@ module Admin
|
|||||||
|
|
||||||
def index
|
def index
|
||||||
authorize :email_domain_block, :index?
|
authorize :email_domain_block, :index?
|
||||||
|
|
||||||
@email_domain_blocks = EmailDomainBlock.where(parent_id: nil).includes(:children).order(id: :desc).page(params[:page])
|
@email_domain_blocks = EmailDomainBlock.where(parent_id: nil).includes(:children).order(id: :desc).page(params[:page])
|
||||||
|
@form = Form::EmailDomainBlockBatch.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def batch
|
||||||
|
@form = Form::EmailDomainBlockBatch.new(form_email_domain_block_batch_params.merge(current_account: current_account, action: action_from_button))
|
||||||
|
@form.save
|
||||||
|
rescue ActionController::ParameterMissing
|
||||||
|
flash[:alert] = I18n.t('admin.email_domain_blocks.no_email_domain_block_selected')
|
||||||
|
rescue Mastodon::NotPermittedError
|
||||||
|
flash[:alert] = I18n.t('admin.custom_emojis.not_permitted')
|
||||||
|
ensure
|
||||||
|
redirect_to admin_email_domain_blocks_path
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@ -19,41 +32,27 @@ module Admin
|
|||||||
|
|
||||||
@email_domain_block = EmailDomainBlock.new(resource_params)
|
@email_domain_block = EmailDomainBlock.new(resource_params)
|
||||||
|
|
||||||
if @email_domain_block.save
|
if action_from_button == 'save'
|
||||||
|
EmailDomainBlock.transaction do
|
||||||
|
@email_domain_block.save!
|
||||||
log_action :create, @email_domain_block
|
log_action :create, @email_domain_block
|
||||||
|
|
||||||
if @email_domain_block.with_dns_records?
|
(@email_domain_block.other_domains || []).uniq.each do |domain|
|
||||||
hostnames = []
|
next if EmailDomainBlock.where(domain: domain).exists?
|
||||||
ips = []
|
|
||||||
|
|
||||||
Resolv::DNS.open do |dns|
|
other_email_domain_block = EmailDomainBlock.create!(domain: domain, parent: @email_domain_block)
|
||||||
dns.timeouts = 5
|
log_action :create, other_email_domain_block
|
||||||
|
|
||||||
hostnames = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }
|
|
||||||
|
|
||||||
([@email_domain_block.domain] + hostnames).uniq.each do |hostname|
|
|
||||||
ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::A).to_a.map { |e| e.address.to_s })
|
|
||||||
ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::AAAA).to_a.map { |e| e.address.to_s })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
(hostnames + ips).each do |hostname|
|
|
||||||
another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: @email_domain_block)
|
|
||||||
log_action :create, another_email_domain_block if another_email_domain_block.save
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg')
|
redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg')
|
||||||
else
|
else
|
||||||
|
set_resolved_records
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
rescue ActiveRecord::RecordInvalid
|
||||||
|
set_resolved_records
|
||||||
def destroy
|
render :new
|
||||||
authorize @email_domain_block, :destroy?
|
|
||||||
@email_domain_block.destroy!
|
|
||||||
log_action :destroy, @email_domain_block
|
|
||||||
redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.destroyed_msg')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -62,8 +61,27 @@ module Admin
|
|||||||
@email_domain_block = EmailDomainBlock.find(params[:id])
|
@email_domain_block = EmailDomainBlock.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_resolved_records
|
||||||
|
Resolv::DNS.open do |dns|
|
||||||
|
dns.timeouts = 5
|
||||||
|
@resolved_records = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def resource_params
|
def resource_params
|
||||||
params.require(:email_domain_block).permit(:domain, :with_dns_records)
|
params.require(:email_domain_block).permit(:domain, other_domains: [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def form_email_domain_block_batch_params
|
||||||
|
params.require(:form_email_domain_block_batch).permit(email_domain_block_ids: [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def action_from_button
|
||||||
|
if params[:delete]
|
||||||
|
'delete'
|
||||||
|
elsif params[:save]
|
||||||
|
'save'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -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
|
||||||
|
@ -9,7 +9,8 @@ module Admin
|
|||||||
def index
|
def index
|
||||||
authorize :account, :index?
|
authorize :account, :index?
|
||||||
|
|
||||||
@accounts = RelationshipFilter.new(@account, filter_params).results.page(params[:page]).per(PER_PAGE)
|
@accounts = RelationshipFilter.new(@account, filter_params).results.includes(:account_stat, user: [:ips, :invite_request]).page(params[:page]).per(PER_PAGE)
|
||||||
|
@form = Form::AccountBatch.new
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
52
app/controllers/admin/reports/actions_controller.rb
Normal file
52
app/controllers/admin/reports/actions_controller.rb
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Admin::Reports::ActionsController < Admin::BaseController
|
||||||
|
before_action :set_report
|
||||||
|
|
||||||
|
def create
|
||||||
|
authorize @report, :show?
|
||||||
|
|
||||||
|
case action_from_button
|
||||||
|
when 'delete', 'mark_as_sensitive'
|
||||||
|
status_batch_action = Admin::StatusBatchAction.new(
|
||||||
|
type: action_from_button,
|
||||||
|
status_ids: @report.status_ids,
|
||||||
|
current_account: current_account,
|
||||||
|
report_id: @report.id,
|
||||||
|
send_email_notification: !@report.spam?
|
||||||
|
)
|
||||||
|
|
||||||
|
status_batch_action.save!
|
||||||
|
when 'silence', 'suspend'
|
||||||
|
account_action = Admin::AccountAction.new(
|
||||||
|
type: action_from_button,
|
||||||
|
report_id: @report.id,
|
||||||
|
target_account: @report.target_account,
|
||||||
|
current_account: current_account,
|
||||||
|
send_email_notification: !@report.spam?
|
||||||
|
)
|
||||||
|
|
||||||
|
account_action.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to admin_reports_path
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_report
|
||||||
|
@report = Report.find(params[:report_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def action_from_button
|
||||||
|
if params[:delete]
|
||||||
|
'delete'
|
||||||
|
elsif params[:mark_as_sensitive]
|
||||||
|
'mark_as_sensitive'
|
||||||
|
elsif params[:silence]
|
||||||
|
'silence'
|
||||||
|
elsif params[:suspend]
|
||||||
|
'suspend'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -29,8 +29,9 @@ module Admin
|
|||||||
end
|
end
|
||||||
|
|
||||||
def after_create_redirect_path
|
def after_create_redirect_path
|
||||||
if @status_batch_action.report_id.present?
|
report_id = @status_batch_action&.report_id || params[:report_id]
|
||||||
admin_report_path(@status_batch_action.report_id)
|
if report_id.present?
|
||||||
|
admin_report_path(report_id)
|
||||||
else
|
else
|
||||||
admin_account_statuses_path(params[:account_id], current_params)
|
admin_account_statuses_path(params[:account_id], current_params)
|
||||||
end
|
end
|
||||||
@ -48,6 +49,10 @@ module Admin
|
|||||||
params.slice(*Admin::StatusFilter::KEYS).permit(*Admin::StatusFilter::KEYS)
|
params.slice(*Admin::StatusFilter::KEYS).permit(*Admin::StatusFilter::KEYS)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def current_params
|
||||||
|
params.slice(:media, :page).permit(:media, :page)
|
||||||
|
end
|
||||||
|
|
||||||
def action_from_button
|
def action_from_button
|
||||||
if params[:report]
|
if params[:report]
|
||||||
'report'
|
'report'
|
||||||
|
@ -5,11 +5,11 @@ class Admin::Trends::Links::PreviewCardProvidersController < Admin::BaseControll
|
|||||||
authorize :preview_card_provider, :index?
|
authorize :preview_card_provider, :index?
|
||||||
|
|
||||||
@preview_card_providers = filtered_preview_card_providers.page(params[:page])
|
@preview_card_providers = filtered_preview_card_providers.page(params[:page])
|
||||||
@form = Form::PreviewCardProviderBatch.new
|
@form = Trends::PreviewCardProviderBatch.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def batch
|
def batch
|
||||||
@form = Form::PreviewCardProviderBatch.new(form_preview_card_provider_batch_params.merge(current_account: current_account, action: action_from_button))
|
@form = Trends::PreviewCardProviderBatch.new(trends_preview_card_provider_batch_params.merge(current_account: current_account, action: action_from_button))
|
||||||
@form.save
|
@form.save
|
||||||
rescue ActionController::ParameterMissing
|
rescue ActionController::ParameterMissing
|
||||||
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
||||||
@ -20,15 +20,15 @@ class Admin::Trends::Links::PreviewCardProvidersController < Admin::BaseControll
|
|||||||
private
|
private
|
||||||
|
|
||||||
def filtered_preview_card_providers
|
def filtered_preview_card_providers
|
||||||
PreviewCardProviderFilter.new(filter_params).results
|
Trends::PreviewCardProviderFilter.new(filter_params).results
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_params
|
def filter_params
|
||||||
params.slice(:page, *PreviewCardProviderFilter::KEYS).permit(:page, *PreviewCardProviderFilter::KEYS)
|
params.slice(:page, *Trends::PreviewCardProviderFilter::KEYS).permit(:page, *Trends::PreviewCardProviderFilter::KEYS)
|
||||||
end
|
end
|
||||||
|
|
||||||
def form_preview_card_provider_batch_params
|
def trends_preview_card_provider_batch_params
|
||||||
params.require(:form_preview_card_provider_batch).permit(:action, preview_card_provider_ids: [])
|
params.require(:trends_preview_card_provider_batch).permit(:action, preview_card_provider_ids: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def action_from_button
|
def action_from_button
|
||||||
|
@ -5,11 +5,11 @@ class Admin::Trends::LinksController < Admin::BaseController
|
|||||||
authorize :preview_card, :index?
|
authorize :preview_card, :index?
|
||||||
|
|
||||||
@preview_cards = filtered_preview_cards.page(params[:page])
|
@preview_cards = filtered_preview_cards.page(params[:page])
|
||||||
@form = Form::PreviewCardBatch.new
|
@form = Trends::PreviewCardBatch.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def batch
|
def batch
|
||||||
@form = Form::PreviewCardBatch.new(form_preview_card_batch_params.merge(current_account: current_account, action: action_from_button))
|
@form = Trends::PreviewCardBatch.new(trends_preview_card_batch_params.merge(current_account: current_account, action: action_from_button))
|
||||||
@form.save
|
@form.save
|
||||||
rescue ActionController::ParameterMissing
|
rescue ActionController::ParameterMissing
|
||||||
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
||||||
@ -20,26 +20,26 @@ class Admin::Trends::LinksController < Admin::BaseController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def filtered_preview_cards
|
def filtered_preview_cards
|
||||||
PreviewCardFilter.new(filter_params.with_defaults(trending: 'all')).results
|
Trends::PreviewCardFilter.new(filter_params.with_defaults(trending: 'all')).results
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_params
|
def filter_params
|
||||||
params.slice(:page, *PreviewCardFilter::KEYS).permit(:page, *PreviewCardFilter::KEYS)
|
params.slice(:page, *Trends::PreviewCardFilter::KEYS).permit(:page, *Trends::PreviewCardFilter::KEYS)
|
||||||
end
|
end
|
||||||
|
|
||||||
def form_preview_card_batch_params
|
def trends_preview_card_batch_params
|
||||||
params.require(:form_preview_card_batch).permit(:action, preview_card_ids: [])
|
params.require(:trends_preview_card_batch).permit(:action, preview_card_ids: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def action_from_button
|
def action_from_button
|
||||||
if params[:approve]
|
if params[:approve]
|
||||||
'approve'
|
'approve'
|
||||||
elsif params[:approve_all]
|
elsif params[:approve_providers]
|
||||||
'approve_all'
|
'approve_providers'
|
||||||
elsif params[:reject]
|
elsif params[:reject]
|
||||||
'reject'
|
'reject'
|
||||||
elsif params[:reject_all]
|
elsif params[:reject_providers]
|
||||||
'reject_all'
|
'reject_providers'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
45
app/controllers/admin/trends/statuses_controller.rb
Normal file
45
app/controllers/admin/trends/statuses_controller.rb
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Admin::Trends::StatusesController < Admin::BaseController
|
||||||
|
def index
|
||||||
|
authorize :status, :index?
|
||||||
|
|
||||||
|
@statuses = filtered_statuses.page(params[:page])
|
||||||
|
@form = Trends::StatusBatch.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def batch
|
||||||
|
@form = Trends::StatusBatch.new(trends_status_batch_params.merge(current_account: current_account, action: action_from_button))
|
||||||
|
@form.save
|
||||||
|
rescue ActionController::ParameterMissing
|
||||||
|
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
||||||
|
ensure
|
||||||
|
redirect_to admin_trends_statuses_path(filter_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def filtered_statuses
|
||||||
|
Trends::StatusFilter.new(filter_params.with_defaults(trending: 'all')).results.includes(:account, :media_attachments, :active_mentions)
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_params
|
||||||
|
params.slice(:page, *Trends::StatusFilter::KEYS).permit(:page, *Trends::StatusFilter::KEYS)
|
||||||
|
end
|
||||||
|
|
||||||
|
def trends_status_batch_params
|
||||||
|
params.require(:trends_status_batch).permit(:action, status_ids: [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def action_from_button
|
||||||
|
if params[:approve]
|
||||||
|
'approve'
|
||||||
|
elsif params[:approve_accounts]
|
||||||
|
'approve_accounts'
|
||||||
|
elsif params[:reject]
|
||||||
|
'reject'
|
||||||
|
elsif params[:reject_accounts]
|
||||||
|
'reject_accounts'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -5,11 +5,11 @@ class Admin::Trends::TagsController < Admin::BaseController
|
|||||||
authorize :tag, :index?
|
authorize :tag, :index?
|
||||||
|
|
||||||
@tags = filtered_tags.page(params[:page])
|
@tags = filtered_tags.page(params[:page])
|
||||||
@form = Form::TagBatch.new
|
@form = Trends::TagBatch.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def batch
|
def batch
|
||||||
@form = Form::TagBatch.new(form_tag_batch_params.merge(current_account: current_account, action: action_from_button))
|
@form = Trends::TagBatch.new(trends_tag_batch_params.merge(current_account: current_account, action: action_from_button))
|
||||||
@form.save
|
@form.save
|
||||||
rescue ActionController::ParameterMissing
|
rescue ActionController::ParameterMissing
|
||||||
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
flash[:alert] = I18n.t('admin.accounts.no_account_selected')
|
||||||
@ -20,15 +20,15 @@ class Admin::Trends::TagsController < Admin::BaseController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def filtered_tags
|
def filtered_tags
|
||||||
TagFilter.new(filter_params).results
|
Trends::TagFilter.new(filter_params).results
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_params
|
def filter_params
|
||||||
params.slice(:page, *TagFilter::KEYS).permit(:page, *TagFilter::KEYS)
|
params.slice(:page, *Trends::TagFilter::KEYS).permit(:page, *Trends::TagFilter::KEYS)
|
||||||
end
|
end
|
||||||
|
|
||||||
def form_tag_batch_params
|
def trends_tag_batch_params
|
||||||
params.require(:form_tag_batch).permit(:action, tag_ids: [])
|
params.require(:trends_tag_batch).permit(:action, tag_ids: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def action_from_button
|
def action_from_button
|
||||||
|
@ -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
|
@ -22,53 +22,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]
|
||||||
|
19
app/controllers/api/v1/admin/trends/links_controller.rb
Normal file
19
app/controllers/api/v1/admin/trends/links_controller.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Admin::Trends::LinksController < Api::BaseController
|
||||||
|
protect_from_forgery with: :exception
|
||||||
|
|
||||||
|
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||||
|
before_action :require_staff!
|
||||||
|
before_action :set_links
|
||||||
|
|
||||||
|
def index
|
||||||
|
render json: @links, each_serializer: REST::Trends::LinkSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_links
|
||||||
|
@links = Trends.links.query.limit(limit_param(10))
|
||||||
|
end
|
||||||
|
end
|
19
app/controllers/api/v1/admin/trends/statuses_controller.rb
Normal file
19
app/controllers/api/v1/admin/trends/statuses_controller.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Admin::Trends::StatusesController < Api::BaseController
|
||||||
|
protect_from_forgery with: :exception
|
||||||
|
|
||||||
|
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||||
|
before_action :require_staff!
|
||||||
|
before_action :set_statuses
|
||||||
|
|
||||||
|
def index
|
||||||
|
render json: @statuses, each_serializer: REST::StatusSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_statuses
|
||||||
|
@statuses = cache_collection(Trends.statuses.query.limit(limit_param(DEFAULT_STATUSES_LIMIT)), Status)
|
||||||
|
end
|
||||||
|
end
|
@ -14,6 +14,6 @@ class Api::V1::Admin::Trends::TagsController < Api::BaseController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def set_tags
|
def set_tags
|
||||||
@tags = Trends.tags.get(false, limit_param(10))
|
@tags = Trends.tags.query.limit(limit_param(10))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ class Api::V1::MediaController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@media_attachment.update!(media_attachment_params)
|
@media_attachment.update!(updateable_media_attachment_params)
|
||||||
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment
|
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment
|
||||||
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
|
||||||
@ -42,6 +42,10 @@ class Api::V1::MediaController < Api::BaseController
|
|||||||
params.permit(:file, :thumbnail, :description, :focus)
|
params.permit(:file, :thumbnail, :description, :focus)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def updateable_media_attachment_params
|
||||||
|
params.permit(:thumbnail, :description, :focus)
|
||||||
|
end
|
||||||
|
|
||||||
def file_type_error
|
def file_type_error
|
||||||
{ error: 'File type of uploaded media could not be verified' }
|
{ error: 'File type of uploaded media could not be verified' }
|
||||||
end
|
end
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -44,13 +44,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
|
||||||
@ -81,17 +86,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,19 +18,11 @@ 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
|
||||||
|
|
||||||
def report_params
|
def report_params
|
||||||
params.permit(:account_id, :comment, :forward, status_ids: [])
|
params.permit(:account_id, :comment, :category, :forward, status_ids: [], rule_ids: [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -7,7 +7,7 @@ class Api::V1::Statuses::HistoriesController < Api::BaseController
|
|||||||
before_action :set_status
|
before_action :set_status
|
||||||
|
|
||||||
def show
|
def show
|
||||||
render json: @status.edits, each_serializer: REST::StatusEditSerializer
|
render json: @status.edits.includes(:account, status: [:account]), each_serializer: REST::StatusEditSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
class Api::V1::StatusesController < Api::BaseController
|
class Api::V1::StatusesController < Api::BaseController
|
||||||
include Authorization
|
include Authorization
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :read, :'read:statuses' }, except: [:create, :destroy]
|
before_action -> { authorize_if_got_token! :read, :'read:statuses' }, except: [:create, :update, :destroy]
|
||||||
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :destroy]
|
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :update, :destroy]
|
||||||
before_action :require_user!, except: [:show, :context]
|
before_action :require_user!, except: [:show, :context]
|
||||||
before_action :set_status, only: [:show, :context]
|
before_action :set_status, only: [:show, :context]
|
||||||
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
|
||||||
@ -35,25 +36,46 @@ class Api::V1::StatusesController < Api::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@status = PostStatusService.new.call(current_user.account,
|
@status = PostStatusService.new.call(
|
||||||
|
current_user.account,
|
||||||
text: status_params[:status],
|
text: status_params[:status],
|
||||||
thread: @thread,
|
thread: @thread,
|
||||||
media_ids: status_params[:media_ids],
|
media_ids: status_params[:media_ids],
|
||||||
sensitive: status_params[:sensitive],
|
sensitive: status_params[:sensitive],
|
||||||
spoiler_text: status_params[:spoiler_text],
|
spoiler_text: status_params[:spoiler_text],
|
||||||
visibility: status_params[:visibility],
|
visibility: status_params[:visibility],
|
||||||
|
language: status_params[:language],
|
||||||
scheduled_at: status_params[:scheduled_at],
|
scheduled_at: status_params[:scheduled_at],
|
||||||
application: doorkeeper_token.application,
|
application: doorkeeper_token.application,
|
||||||
poll: status_params[:poll],
|
poll: status_params[:poll],
|
||||||
content_type: status_params[:content_type],
|
content_type: status_params[:content_type],
|
||||||
idempotency: request.headers['Idempotency-Key'],
|
idempotency: request.headers['Idempotency-Key'],
|
||||||
with_rate_limit: true)
|
with_rate_limit: true
|
||||||
|
)
|
||||||
|
|
||||||
render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer
|
render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@status = Status.where(account: current_account).find(params[:id])
|
||||||
|
authorize @status, :update?
|
||||||
|
|
||||||
|
UpdateStatusService.new.call(
|
||||||
|
@status,
|
||||||
|
current_account.id,
|
||||||
|
text: status_params[:status],
|
||||||
|
media_ids: status_params[:media_ids],
|
||||||
|
sensitive: status_params[:sensitive],
|
||||||
|
spoiler_text: status_params[:spoiler_text],
|
||||||
|
poll: status_params[:poll],
|
||||||
|
content_type: status_params[:content_type]
|
||||||
|
)
|
||||||
|
|
||||||
|
render json: @status, serializer: REST::StatusSerializer
|
||||||
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@status = Status.where(account_id: current_user.account).find(params[:id])
|
@status = Status.where(account: current_account).find(params[:id])
|
||||||
authorize @status, :destroy?
|
authorize @status, :destroy?
|
||||||
|
|
||||||
@status.discard
|
@status.discard
|
||||||
@ -73,8 +95,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
|
||||||
|
|
||||||
@ -85,6 +108,7 @@ class Api::V1::StatusesController < Api::BaseController
|
|||||||
:sensitive,
|
:sensitive,
|
||||||
:spoiler_text,
|
:spoiler_text,
|
||||||
:visibility,
|
:visibility,
|
||||||
|
:language,
|
||||||
:scheduled_at,
|
:scheduled_at,
|
||||||
:content_type,
|
:content_type,
|
||||||
media_ids: [],
|
media_ids: [],
|
||||||
|
@ -12,10 +12,14 @@ class Api::V1::Trends::LinksController < Api::BaseController
|
|||||||
def set_links
|
def set_links
|
||||||
@links = begin
|
@links = begin
|
||||||
if Setting.trends
|
if Setting.trends
|
||||||
Trends.links.get(true, limit_param(10))
|
links_from_trends
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def links_from_trends
|
||||||
|
Trends.links.query.allowed.in_locale(content_locale).limit(limit_param(10))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
27
app/controllers/api/v1/trends/statuses_controller.rb
Normal file
27
app/controllers/api/v1/trends/statuses_controller.rb
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Trends::StatusesController < Api::BaseController
|
||||||
|
before_action :set_statuses
|
||||||
|
|
||||||
|
def index
|
||||||
|
render json: @statuses, each_serializer: REST::StatusSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_statuses
|
||||||
|
@statuses = begin
|
||||||
|
if Setting.trends
|
||||||
|
cache_collection(statuses_from_trends, Status)
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def statuses_from_trends
|
||||||
|
scope = Trends.statuses.query.allowed.in_locale(content_locale)
|
||||||
|
scope = scope.filtered_for(current_account) if user_signed_in?
|
||||||
|
scope.limit(limit_param(DEFAULT_STATUSES_LIMIT))
|
||||||
|
end
|
||||||
|
end
|
@ -12,7 +12,7 @@ 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.get(true, limit_param(10))
|
Trends.tags.query.allowed.limit(limit_param(10))
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
@ -17,16 +17,7 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
|||||||
|
|
||||||
data = {
|
data = {
|
||||||
policy: 'all',
|
policy: 'all',
|
||||||
|
alerts: Notification::TYPES.index_with { alerts_enabled },
|
||||||
alerts: {
|
|
||||||
follow: alerts_enabled,
|
|
||||||
follow_request: alerts_enabled,
|
|
||||||
favourite: alerts_enabled,
|
|
||||||
reblog: alerts_enabled,
|
|
||||||
mention: alerts_enabled,
|
|
||||||
poll: alerts_enabled,
|
|
||||||
status: alerts_enabled,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data.deep_merge!(data_params) if params[:data]
|
data.deep_merge!(data_params) if params[:data]
|
||||||
@ -61,6 +52,6 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def data_params
|
def data_params
|
||||||
@data_params ||= params.require(:data).permit(:policy, alerts: [:follow, :follow_request, :favourite, :reblog, :mention, :poll, :status])
|
@data_params ||= params.require(:data).permit(:policy, alerts: Notification::TYPES)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -136,16 +136,6 @@ class ApplicationController < ActionController::Base
|
|||||||
@current_session = SessionActivation.find_by(session_id: cookies.signed['_session_id']) if cookies.signed['_session_id'].present?
|
@current_session = SessionActivation.find_by(session_id: cookies.signed['_session_id']) if cookies.signed['_session_id'].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_flavour
|
|
||||||
return Setting.flavour unless Themes.instance.flavours.include? current_user&.setting_flavour
|
|
||||||
current_user.setting_flavour
|
|
||||||
end
|
|
||||||
|
|
||||||
def current_skin
|
|
||||||
return Setting.skin unless Themes.instance.skins_for(current_flavour).include? current_user&.setting_skin
|
|
||||||
current_user.setting_skin
|
|
||||||
end
|
|
||||||
|
|
||||||
def respond_with_error(code)
|
def respond_with_error(code)
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.any do
|
format.any do
|
||||||
|
@ -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')
|
||||||
|
@ -10,6 +10,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||||||
before_action :configure_sign_up_params, only: [:create]
|
before_action :configure_sign_up_params, only: [:create]
|
||||||
before_action :set_pack
|
before_action :set_pack
|
||||||
before_action :set_sessions, only: [:edit, :update]
|
before_action :set_sessions, only: [:edit, :update]
|
||||||
|
before_action :set_strikes, only: [:edit, :update]
|
||||||
before_action :set_instance_presenter, only: [:new, :create, :update]
|
before_action :set_instance_presenter, only: [:new, :create, :update]
|
||||||
before_action :set_body_classes, only: [:new, :create, :edit, :update]
|
before_action :set_body_classes, only: [:new, :create, :edit, :update]
|
||||||
before_action :require_not_suspended!, only: [:update]
|
before_action :require_not_suspended!, only: [:update]
|
||||||
@ -116,8 +117,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_invite
|
def set_invite
|
||||||
invite = invite_code.present? ? Invite.find_by(code: invite_code) : nil
|
@invite = begin
|
||||||
@invite = invite&.valid_for_use? ? invite : nil
|
invite = Invite.find_by(code: invite_code) if invite_code.present?
|
||||||
|
invite if invite&.valid_for_use?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def determine_layout
|
def determine_layout
|
||||||
@ -128,6 +131,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||||||
@sessions = current_user.session_activations
|
@sessions = current_user.session_activations
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_strikes
|
||||||
|
@strikes = current_account.strikes.recent.latest
|
||||||
|
end
|
||||||
|
|
||||||
def require_not_suspended!
|
def require_not_suspended!
|
||||||
forbidden if current_account.suspended?
|
forbidden if current_account.suspended?
|
||||||
end
|
end
|
||||||
|
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 Authorization
|
module Authorization
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
include Pundit
|
include Pundit::Authorization
|
||||||
|
|
||||||
def pundit_user
|
def pundit_user
|
||||||
current_account
|
current_account
|
||||||
|
@ -7,27 +7,28 @@ module Localized
|
|||||||
around_action :set_locale
|
around_action :set_locale
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_locale
|
def set_locale(&block)
|
||||||
locale = current_user.locale if respond_to?(:user_signed_in?) && user_signed_in?
|
I18n.with_locale(requested_locale || I18n.default_locale, &block)
|
||||||
locale ||= session[:locale] ||= default_locale
|
|
||||||
locale = default_locale unless I18n.available_locales.include?(locale.to_sym)
|
|
||||||
|
|
||||||
I18n.with_locale(locale) do
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def default_locale
|
def requested_locale
|
||||||
if ENV['DEFAULT_LOCALE'].present?
|
requested_locale_name = available_locale_or_nil(params[:lang])
|
||||||
I18n.default_locale
|
requested_locale_name ||= available_locale_or_nil(current_user.locale) if respond_to?(:user_signed_in?) && user_signed_in?
|
||||||
else
|
requested_locale_name ||= http_accept_language if ENV['DEFAULT_LOCALE'].blank?
|
||||||
request_locale || I18n.default_locale
|
requested_locale_name
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def request_locale
|
def http_accept_language
|
||||||
http_accept_language.language_region_compatible_from(I18n.available_locales)
|
HttpAcceptLanguage::Parser.new(request.headers.fetch('Accept-Language')).language_region_compatible_from(I18n.available_locales) if request.headers.key?('Accept-Language')
|
||||||
|
end
|
||||||
|
|
||||||
|
def available_locale_or_nil(locale_name)
|
||||||
|
locale_name.to_sym if locale_name.present? && I18n.available_locales.include?(locale_name.to_sym)
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_locale
|
||||||
|
@content_locale ||= I18n.locale.to_s.split(/[_-]/).first
|
||||||
end
|
end
|
||||||
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
|
||||||
|
@ -10,8 +10,17 @@ module ThemingConcern
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def current_flavour
|
||||||
|
[current_user&.setting_flavour, Setting.flavour, 'glitch', 'vanilla'].find { |flavour| Themes.instance.flavours.include?(flavour) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_skin
|
||||||
|
skins = Themes.instance.skins_for(current_flavour)
|
||||||
|
[current_user&.setting_skin, Setting.skin, 'default'].find { |skin| skins.include?(skin) }
|
||||||
|
end
|
||||||
|
|
||||||
def valid_pack_data?(data, pack_name)
|
def valid_pack_data?(data, pack_name)
|
||||||
data['pack'].is_a?(Hash) && [String, Hash].any? { |c| data['pack'][pack_name].is_a?(c) }
|
data['pack'].is_a?(Hash) && data['pack'][pack_name].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def nil_pack(data)
|
def nil_pack(data)
|
||||||
|
@ -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
|
||||||
|
26
app/controllers/disputes/appeals_controller.rb
Normal file
26
app/controllers/disputes/appeals_controller.rb
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Disputes::AppealsController < Disputes::BaseController
|
||||||
|
before_action :set_strike
|
||||||
|
|
||||||
|
def create
|
||||||
|
authorize @strike, :appeal?
|
||||||
|
|
||||||
|
@appeal = AppealService.new.call(@strike, appeal_params[:text])
|
||||||
|
|
||||||
|
redirect_to disputes_strike_path(@strike), notice: I18n.t('disputes.strikes.appealed_msg')
|
||||||
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
|
@appeal = e.record
|
||||||
|
render template: 'disputes/strikes/show'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_strike
|
||||||
|
@strike = current_account.strikes.find(params[:strike_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def appeal_params
|
||||||
|
params.require(:appeal).permit(:text)
|
||||||
|
end
|
||||||
|
end
|
23
app/controllers/disputes/base_controller.rb
Normal file
23
app/controllers/disputes/base_controller.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Disputes::BaseController < ApplicationController
|
||||||
|
include Authorization
|
||||||
|
|
||||||
|
layout 'admin'
|
||||||
|
|
||||||
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
|
before_action :set_body_classes
|
||||||
|
before_action :authenticate_user!
|
||||||
|
before_action :set_pack
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_pack
|
||||||
|
use_pack 'admin'
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_body_classes
|
||||||
|
@body_classes = 'admin'
|
||||||
|
end
|
||||||
|
end
|
21
app/controllers/disputes/strikes_controller.rb
Normal file
21
app/controllers/disputes/strikes_controller.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Disputes::StrikesController < Disputes::BaseController
|
||||||
|
before_action :set_strike, only: [:show]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@strikes = current_account.strikes.latest
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
authorize @strike, :show?
|
||||||
|
|
||||||
|
@appeal = @strike.appeal || @strike.build_appeal
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_strike
|
||||||
|
@strike = AccountWarning.find(params[:id])
|
||||||
|
end
|
||||||
|
end
|
@ -16,13 +16,13 @@ class FollowerAccountsController < ApplicationController
|
|||||||
use_pack 'public'
|
use_pack 'public'
|
||||||
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?)
|
||||||
|
|
||||||
@ -83,7 +83,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)
|
||||||
|
@ -16,13 +16,13 @@ class FollowingAccountsController < ApplicationController
|
|||||||
use_pack 'public'
|
use_pack 'public'
|
||||||
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?)
|
||||||
|
|
||||||
@ -83,7 +83,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 InstanceActorsController < ApplicationController
|
class InstanceActorsController < ApplicationController
|
||||||
include AccountControllerConcern
|
include AccountControllerConcern
|
||||||
|
|
||||||
|
skip_before_action :check_account_confirmation
|
||||||
skip_around_action :set_locale
|
skip_around_action :set_locale
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@ -48,7 +48,6 @@ class Settings::PreferencesController < Settings::BaseController
|
|||||||
:setting_system_font_ui,
|
:setting_system_font_ui,
|
||||||
:setting_system_emoji_font,
|
:setting_system_emoji_font,
|
||||||
:setting_noindex,
|
:setting_noindex,
|
||||||
:setting_hide_network,
|
|
||||||
:setting_hide_followers_count,
|
:setting_hide_followers_count,
|
||||||
:setting_aggregate_reblogs,
|
:setting_aggregate_reblogs,
|
||||||
:setting_show_application,
|
:setting_show_application,
|
||||||
@ -58,7 +57,7 @@ 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),
|
notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag trending_link trending_status),
|
||||||
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
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Admin::AccountModerationNotesHelper
|
module Admin::AccountModerationNotesHelper
|
||||||
def admin_account_link_to(account)
|
def admin_account_link_to(account, path: nil)
|
||||||
return if account.nil?
|
return if account.nil?
|
||||||
|
|
||||||
link_to admin_account_path(account.id), class: name_tag_classes(account), title: account.acct do
|
link_to path || admin_account_path(account.id), class: name_tag_classes(account), title: account.acct do
|
||||||
safe_join([
|
safe_join([
|
||||||
image_tag(account.avatar.url, width: 15, height: 15, alt: display_name(account), class: 'avatar'),
|
image_tag(account.avatar.url, width: 15, height: 15, alt: display_name(account), class: 'avatar'),
|
||||||
content_tag(:span, account.acct, class: 'username'),
|
content_tag(:span, account.acct, class: 'username'),
|
||||||
|
@ -33,6 +33,8 @@ module Admin::ActionLogsHelper
|
|||||||
"#{record.ip}/#{record.ip.prefix} (#{I18n.t("simple_form.labels.ip_block.severities.#{record.severity}")})"
|
"#{record.ip}/#{record.ip.prefix} (#{I18n.t("simple_form.labels.ip_block.severities.#{record.severity}")})"
|
||||||
when 'Instance'
|
when 'Instance'
|
||||||
record.domain
|
record.domain
|
||||||
|
when 'Appeal'
|
||||||
|
link_to record.account.acct, disputes_strike_path(record.strike)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,9 +5,10 @@ module Admin::FilterHelper
|
|||||||
AccountFilter::KEYS,
|
AccountFilter::KEYS,
|
||||||
CustomEmojiFilter::KEYS,
|
CustomEmojiFilter::KEYS,
|
||||||
ReportFilter::KEYS,
|
ReportFilter::KEYS,
|
||||||
TagFilter::KEYS,
|
Trends::TagFilter::KEYS,
|
||||||
PreviewCardProviderFilter::KEYS,
|
Trends::PreviewCardProviderFilter::KEYS,
|
||||||
PreviewCardFilter::KEYS,
|
Trends::PreviewCardFilter::KEYS,
|
||||||
|
Trends::StatusFilter::KEYS,
|
||||||
InstanceFilter::KEYS,
|
InstanceFilter::KEYS,
|
||||||
InviteFilter::KEYS,
|
InviteFilter::KEYS,
|
||||||
RelationshipFilter::KEYS,
|
RelationshipFilter::KEYS,
|
||||||
|
20
app/helpers/admin/trends/statuses_helper.rb
Normal file
20
app/helpers/admin/trends/statuses_helper.rb
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Admin::Trends::StatusesHelper
|
||||||
|
def one_line_preview(status)
|
||||||
|
text = begin
|
||||||
|
if status.local?
|
||||||
|
status.text.split("\n").first
|
||||||
|
else
|
||||||
|
Nokogiri::HTML(status.text).css('html > body > *').first&.text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return '' if text.blank?
|
||||||
|
|
||||||
|
html = Formatter.instance.send(:encode, text)
|
||||||
|
html = Formatter.instance.send(:encode_custom_emojis, html, status.emojis, prefers_autoplay?)
|
||||||
|
|
||||||
|
html.html_safe # rubocop:disable Rails/OutputSafety
|
||||||
|
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)
|
||||||
@ -225,4 +225,19 @@ 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
|
||||||
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)
|
||||||
|
@ -1,94 +1,257 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module LanguagesHelper
|
module LanguagesHelper
|
||||||
HUMAN_LOCALES = {
|
ISO_639_1 = {
|
||||||
af: 'Afrikaans',
|
aa: ['Afar', 'Afaraf'].freeze,
|
||||||
ar: 'العربية',
|
ab: ['Abkhaz', 'аҧсуа бызшәа'].freeze,
|
||||||
ast: 'Asturianu',
|
ae: ['Avestan', 'avesta'].freeze,
|
||||||
bg: 'Български',
|
af: ['Afrikaans', 'Afrikaans'].freeze,
|
||||||
bn: 'বাংলা',
|
ak: ['Akan', 'Akan'].freeze,
|
||||||
br: 'Breton',
|
am: ['Amharic', 'አማርኛ'].freeze,
|
||||||
ca: 'Català',
|
an: ['Aragonese', 'aragonés'].freeze,
|
||||||
co: 'Corsu',
|
ar: ['Arabic', 'اللغة العربية'].freeze,
|
||||||
cs: 'Čeština',
|
as: ['Assamese', 'অসমীয়া'].freeze,
|
||||||
cy: 'Cymraeg',
|
av: ['Avaric', 'авар мацӀ'].freeze,
|
||||||
da: 'Dansk',
|
ay: ['Aymara', 'aymar aru'].freeze,
|
||||||
de: 'Deutsch',
|
az: ['Azerbaijani', 'azərbaycan dili'].freeze,
|
||||||
el: 'Ελληνικά',
|
ba: ['Bashkir', 'башҡорт теле'].freeze,
|
||||||
en: 'English',
|
be: ['Belarusian', 'беларуская мова'].freeze,
|
||||||
eo: 'Esperanto',
|
bg: ['Bulgarian', 'български език'].freeze,
|
||||||
|
bh: ['Bihari', 'भोजपुरी'].freeze,
|
||||||
|
bi: ['Bislama', 'Bislama'].freeze,
|
||||||
|
bm: ['Bambara', 'bamanankan'].freeze,
|
||||||
|
bn: ['Bengali', 'বাংলা'].freeze,
|
||||||
|
bo: ['Tibetan', 'བོད་ཡིག'].freeze,
|
||||||
|
br: ['Breton', 'brezhoneg'].freeze,
|
||||||
|
bs: ['Bosnian', 'bosanski jezik'].freeze,
|
||||||
|
ca: ['Catalan', 'Català'].freeze,
|
||||||
|
ce: ['Chechen', 'нохчийн мотт'].freeze,
|
||||||
|
ch: ['Chamorro', 'Chamoru'].freeze,
|
||||||
|
co: ['Corsican', 'corsu'].freeze,
|
||||||
|
cr: ['Cree', 'ᓀᐦᐃᔭᐍᐏᐣ'].freeze,
|
||||||
|
cs: ['Czech', 'čeština'].freeze,
|
||||||
|
cu: ['Old Church Slavonic', 'ѩзыкъ словѣньскъ'].freeze,
|
||||||
|
cv: ['Chuvash', 'чӑваш чӗлхи'].freeze,
|
||||||
|
cy: ['Welsh', 'Cymraeg'].freeze,
|
||||||
|
da: ['Danish', 'dansk'].freeze,
|
||||||
|
de: ['German', 'Deutsch'].freeze,
|
||||||
|
dv: ['Divehi', 'Dhivehi'].freeze,
|
||||||
|
dz: ['Dzongkha', 'རྫོང་ཁ'].freeze,
|
||||||
|
ee: ['Ewe', 'Eʋegbe'].freeze,
|
||||||
|
el: ['Greek', 'Ελληνικά'].freeze,
|
||||||
|
en: ['English', 'English'].freeze,
|
||||||
|
eo: ['Esperanto', 'Esperanto'].freeze,
|
||||||
|
es: ['Spanish', 'Español'].freeze,
|
||||||
|
et: ['Estonian', 'eesti'].freeze,
|
||||||
|
eu: ['Basque', 'euskara'].freeze,
|
||||||
|
fa: ['Persian', 'فارسی'].freeze,
|
||||||
|
ff: ['Fula', 'Fulfulde'].freeze,
|
||||||
|
fi: ['Finnish', 'suomi'].freeze,
|
||||||
|
fj: ['Fijian', 'Vakaviti'].freeze,
|
||||||
|
fo: ['Faroese', 'føroyskt'].freeze,
|
||||||
|
fr: ['French', 'Français'].freeze,
|
||||||
|
fy: ['Western Frisian', 'Frysk'].freeze,
|
||||||
|
ga: ['Irish', 'Gaeilge'].freeze,
|
||||||
|
gd: ['Scottish Gaelic', 'Gàidhlig'].freeze,
|
||||||
|
gl: ['Galician', 'galego'].freeze,
|
||||||
|
gu: ['Gujarati', 'ગુજરાતી'].freeze,
|
||||||
|
gv: ['Manx', 'Gaelg'].freeze,
|
||||||
|
ha: ['Hausa', 'هَوُسَ'].freeze,
|
||||||
|
he: ['Hebrew', 'עברית'].freeze,
|
||||||
|
hi: ['Hindi', 'हिन्दी'].freeze,
|
||||||
|
ho: ['Hiri Motu', 'Hiri Motu'].freeze,
|
||||||
|
hr: ['Croatian', 'Hrvatski'].freeze,
|
||||||
|
ht: ['Haitian', 'Kreyòl ayisyen'].freeze,
|
||||||
|
hu: ['Hungarian', 'magyar'].freeze,
|
||||||
|
hy: ['Armenian', 'Հայերեն'].freeze,
|
||||||
|
hz: ['Herero', 'Otjiherero'].freeze,
|
||||||
|
ia: ['Interlingua', 'Interlingua'].freeze,
|
||||||
|
id: ['Indonesian', 'Bahasa Indonesia'].freeze,
|
||||||
|
ie: ['Interlingue', 'Interlingue'].freeze,
|
||||||
|
ig: ['Igbo', 'Asụsụ Igbo'].freeze,
|
||||||
|
ii: ['Nuosu', 'ꆈꌠ꒿ Nuosuhxop'].freeze,
|
||||||
|
ik: ['Inupiaq', 'Iñupiaq'].freeze,
|
||||||
|
io: ['Ido', 'Ido'].freeze,
|
||||||
|
is: ['Icelandic', 'Íslenska'].freeze,
|
||||||
|
it: ['Italian', 'Italiano'].freeze,
|
||||||
|
iu: ['Inuktitut', 'ᐃᓄᒃᑎᑐᑦ'].freeze,
|
||||||
|
ja: ['Japanese', '日本語'].freeze,
|
||||||
|
jv: ['Javanese', 'basa Jawa'].freeze,
|
||||||
|
ka: ['Georgian', 'ქართული'].freeze,
|
||||||
|
kg: ['Kongo', 'Kikongo'].freeze,
|
||||||
|
ki: ['Kikuyu', 'Gĩkũyũ'].freeze,
|
||||||
|
kj: ['Kwanyama', 'Kuanyama'].freeze,
|
||||||
|
kk: ['Kazakh', 'қазақ тілі'].freeze,
|
||||||
|
kl: ['Kalaallisut', 'kalaallisut'].freeze,
|
||||||
|
km: ['Khmer', 'ខេមរភាសា'].freeze,
|
||||||
|
kn: ['Kannada', 'ಕನ್ನಡ'].freeze,
|
||||||
|
ko: ['Korean', '한국어'].freeze,
|
||||||
|
kr: ['Kanuri', 'Kanuri'].freeze,
|
||||||
|
ks: ['Kashmiri', 'कश्मीरी'].freeze,
|
||||||
|
ku: ['Kurmanji (Kurdish)', 'Kurmancî'].freeze,
|
||||||
|
kv: ['Komi', 'коми кыв'].freeze,
|
||||||
|
kw: ['Cornish', 'Kernewek'].freeze,
|
||||||
|
ky: ['Kyrgyz', 'Кыргызча'].freeze,
|
||||||
|
la: ['Latin', 'latine'].freeze,
|
||||||
|
lb: ['Luxembourgish', 'Lëtzebuergesch'].freeze,
|
||||||
|
lg: ['Ganda', 'Luganda'].freeze,
|
||||||
|
li: ['Limburgish', 'Limburgs'].freeze,
|
||||||
|
ln: ['Lingala', 'Lingála'].freeze,
|
||||||
|
lo: ['Lao', 'ພາສາ'].freeze,
|
||||||
|
lt: ['Lithuanian', 'lietuvių kalba'].freeze,
|
||||||
|
lu: ['Luba-Katanga', 'Tshiluba'].freeze,
|
||||||
|
lv: ['Latvian', 'latviešu valoda'].freeze,
|
||||||
|
mg: ['Malagasy', 'fiteny malagasy'].freeze,
|
||||||
|
mh: ['Marshallese', 'Kajin M̧ajeļ'].freeze,
|
||||||
|
mi: ['Māori', 'te reo Māori'].freeze,
|
||||||
|
mk: ['Macedonian', 'македонски јазик'].freeze,
|
||||||
|
ml: ['Malayalam', 'മലയാളം'].freeze,
|
||||||
|
mn: ['Mongolian', 'Монгол хэл'].freeze,
|
||||||
|
mr: ['Marathi', 'मराठी'].freeze,
|
||||||
|
ms: ['Malay', 'Bahasa Melayu'].freeze,
|
||||||
|
mt: ['Maltese', 'Malti'].freeze,
|
||||||
|
my: ['Burmese', 'ဗမာစာ'].freeze,
|
||||||
|
na: ['Nauru', 'Ekakairũ Naoero'].freeze,
|
||||||
|
nb: ['Norwegian Bokmål', 'Norsk bokmål'].freeze,
|
||||||
|
nd: ['Northern Ndebele', 'isiNdebele'].freeze,
|
||||||
|
ne: ['Nepali', 'नेपाली'].freeze,
|
||||||
|
ng: ['Ndonga', 'Owambo'].freeze,
|
||||||
|
nl: ['Dutch', 'Nederlands'].freeze,
|
||||||
|
nn: ['Norwegian Nynorsk', 'Norsk Nynorsk'].freeze,
|
||||||
|
no: ['Norwegian', 'Norsk'].freeze,
|
||||||
|
nr: ['Southern Ndebele', 'isiNdebele'].freeze,
|
||||||
|
nv: ['Navajo', 'Diné bizaad'].freeze,
|
||||||
|
ny: ['Chichewa', 'chiCheŵa'].freeze,
|
||||||
|
oc: ['Occitan', 'occitan'].freeze,
|
||||||
|
oj: ['Ojibwe', 'ᐊᓂᔑᓈᐯᒧᐎᓐ'].freeze,
|
||||||
|
om: ['Oromo', 'Afaan Oromoo'].freeze,
|
||||||
|
or: ['Oriya', 'ଓଡ଼ିଆ'].freeze,
|
||||||
|
os: ['Ossetian', 'ирон æвзаг'].freeze,
|
||||||
|
pa: ['Panjabi', 'ਪੰਜਾਬੀ'].freeze,
|
||||||
|
pi: ['Pāli', 'पाऴि'].freeze,
|
||||||
|
pl: ['Polish', 'Polski'].freeze,
|
||||||
|
ps: ['Pashto', 'پښتو'].freeze,
|
||||||
|
pt: ['Portuguese', 'Português'].freeze,
|
||||||
|
qu: ['Quechua', 'Runa Simi'].freeze,
|
||||||
|
rm: ['Romansh', 'rumantsch grischun'].freeze,
|
||||||
|
rn: ['Kirundi', 'Ikirundi'].freeze,
|
||||||
|
ro: ['Romanian', 'Română'].freeze,
|
||||||
|
ru: ['Russian', 'Русский'].freeze,
|
||||||
|
rw: ['Kinyarwanda', 'Ikinyarwanda'].freeze,
|
||||||
|
sa: ['Sanskrit', 'संस्कृतम्'].freeze,
|
||||||
|
sc: ['Sardinian', 'sardu'].freeze,
|
||||||
|
sd: ['Sindhi', 'सिन्धी'].freeze,
|
||||||
|
se: ['Northern Sami', 'Davvisámegiella'].freeze,
|
||||||
|
sg: ['Sango', 'yângâ tî sängö'].freeze,
|
||||||
|
si: ['Sinhala', 'සිංහල'].freeze,
|
||||||
|
sk: ['Slovak', 'slovenčina'].freeze,
|
||||||
|
sl: ['Slovenian', 'slovenščina'].freeze,
|
||||||
|
sn: ['Shona', 'chiShona'].freeze,
|
||||||
|
so: ['Somali', 'Soomaaliga'].freeze,
|
||||||
|
sq: ['Albanian', 'Shqip'].freeze,
|
||||||
|
sr: ['Serbian', 'српски језик'].freeze,
|
||||||
|
ss: ['Swati', 'SiSwati'].freeze,
|
||||||
|
st: ['Southern Sotho', 'Sesotho'].freeze,
|
||||||
|
su: ['Sundanese', 'Basa Sunda'].freeze,
|
||||||
|
sv: ['Swedish', 'Svenska'].freeze,
|
||||||
|
sw: ['Swahili', 'Kiswahili'].freeze,
|
||||||
|
ta: ['Tamil', 'தமிழ்'].freeze,
|
||||||
|
te: ['Telugu', 'తెలుగు'].freeze,
|
||||||
|
tg: ['Tajik', 'тоҷикӣ'].freeze,
|
||||||
|
th: ['Thai', 'ไทย'].freeze,
|
||||||
|
ti: ['Tigrinya', 'ትግርኛ'].freeze,
|
||||||
|
tk: ['Turkmen', 'Türkmen'].freeze,
|
||||||
|
tl: ['Tagalog', 'Wikang Tagalog'].freeze,
|
||||||
|
tn: ['Tswana', 'Setswana'].freeze,
|
||||||
|
to: ['Tonga', 'faka Tonga'].freeze,
|
||||||
|
tr: ['Turkish', 'Türkçe'].freeze,
|
||||||
|
ts: ['Tsonga', 'Xitsonga'].freeze,
|
||||||
|
tt: ['Tatar', 'татар теле'].freeze,
|
||||||
|
tw: ['Twi', 'Twi'].freeze,
|
||||||
|
ty: ['Tahitian', 'Reo Tahiti'].freeze,
|
||||||
|
ug: ['Uyghur', 'ئۇيغۇرچە'].freeze,
|
||||||
|
uk: ['Ukrainian', 'Українська'].freeze,
|
||||||
|
ur: ['Urdu', 'اردو'].freeze,
|
||||||
|
uz: ['Uzbek', 'Ўзбек'].freeze,
|
||||||
|
ve: ['Venda', 'Tshivenḓa'].freeze,
|
||||||
|
vi: ['Vietnamese', 'Tiếng Việt'].freeze,
|
||||||
|
vo: ['Volapük', 'Volapük'].freeze,
|
||||||
|
wa: ['Walloon', 'walon'].freeze,
|
||||||
|
wo: ['Wolof', 'Wollof'].freeze,
|
||||||
|
xh: ['Xhosa', 'isiXhosa'].freeze,
|
||||||
|
yi: ['Yiddish', 'ייִדיש'].freeze,
|
||||||
|
yo: ['Yoruba', 'Yorùbá'].freeze,
|
||||||
|
za: ['Zhuang', 'Saɯ cueŋƅ'].freeze,
|
||||||
|
zh: ['Chinese', '中文'].freeze,
|
||||||
|
zu: ['Zulu', 'isiZulu'].freeze,
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
ISO_639_3 = {
|
||||||
|
ast: ['Asturian', 'Asturianu'].freeze,
|
||||||
|
ckb: ['Sorani (Kurdish)', 'سۆرانی'].freeze,
|
||||||
|
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
||||||
|
kmr: ['Kurmanji (Kurdish)', 'Kurmancî'].freeze,
|
||||||
|
zgh: ['Standard Moroccan Tamazight', 'ⵜⴰⵎⴰⵣⵉⵖⵜ'].freeze,
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
SUPPORTED_LOCALES = {}.merge(ISO_639_1).merge(ISO_639_3).freeze
|
||||||
|
|
||||||
|
# For ISO-639-1 and ISO-639-3 language codes, we have their official
|
||||||
|
# names, but for some translations, we need the names of the
|
||||||
|
# regional variants specifically
|
||||||
|
REGIONAL_LOCALE_NAMES = {
|
||||||
'es-AR': 'Español (Argentina)',
|
'es-AR': 'Español (Argentina)',
|
||||||
'es-MX': 'Español (México)',
|
'es-MX': 'Español (México)',
|
||||||
es: 'Español',
|
|
||||||
et: 'Eesti',
|
|
||||||
eu: 'Euskara',
|
|
||||||
fa: 'فارسی',
|
|
||||||
fi: 'Suomi',
|
|
||||||
fr: 'Français',
|
|
||||||
ga: 'Gaeilge',
|
|
||||||
gd: 'Gàidhlig',
|
|
||||||
gl: 'Galego',
|
|
||||||
he: 'עברית',
|
|
||||||
hi: 'हिन्दी',
|
|
||||||
hr: 'Hrvatski',
|
|
||||||
hu: 'Magyar',
|
|
||||||
hy: 'Հայերեն',
|
|
||||||
id: 'Bahasa Indonesia',
|
|
||||||
io: 'Ido',
|
|
||||||
is: 'Íslenska',
|
|
||||||
it: 'Italiano',
|
|
||||||
ja: '日本語',
|
|
||||||
ka: 'ქართული',
|
|
||||||
kab: 'Taqbaylit',
|
|
||||||
kk: 'Қазақша',
|
|
||||||
kmr: 'Kurmancî',
|
|
||||||
kn: 'ಕನ್ನಡ',
|
|
||||||
ko: '한국어',
|
|
||||||
ku: 'سۆرانی',
|
|
||||||
lt: 'Lietuvių',
|
|
||||||
lv: 'Latviešu',
|
|
||||||
mk: 'Македонски',
|
|
||||||
ml: 'മലയാളം',
|
|
||||||
mr: 'मराठी',
|
|
||||||
ms: 'Bahasa Melayu',
|
|
||||||
nl: 'Nederlands',
|
|
||||||
nn: 'Nynorsk',
|
|
||||||
no: 'Norsk',
|
|
||||||
oc: 'Occitan',
|
|
||||||
pl: 'Polski',
|
|
||||||
'pt-BR': 'Português (Brasil)',
|
'pt-BR': 'Português (Brasil)',
|
||||||
'pt-PT': 'Português (Portugal)',
|
'pt-PT': 'Português (Portugal)',
|
||||||
pt: 'Português',
|
|
||||||
ro: 'Română',
|
|
||||||
ru: 'Русский',
|
|
||||||
sa: 'संस्कृतम्',
|
|
||||||
sc: 'Sardu',
|
|
||||||
si: 'සිංහල',
|
|
||||||
sk: 'Slovenčina',
|
|
||||||
sl: 'Slovenščina',
|
|
||||||
sq: 'Shqip',
|
|
||||||
'sr-Latn': 'Srpski (latinica)',
|
'sr-Latn': 'Srpski (latinica)',
|
||||||
sr: 'Српски',
|
|
||||||
sv: 'Svenska',
|
|
||||||
ta: 'தமிழ்',
|
|
||||||
te: 'తెలుగు',
|
|
||||||
th: 'ไทย',
|
|
||||||
tr: 'Türkçe',
|
|
||||||
uk: 'Українська',
|
|
||||||
ur: 'اُردُو',
|
|
||||||
vi: 'Tiếng Việt',
|
|
||||||
zgh: 'ⵜⴰⵎⴰⵣⵉⵖⵜ',
|
|
||||||
'zh-CN': '简体中文',
|
'zh-CN': '简体中文',
|
||||||
'zh-HK': '繁體中文(香港)',
|
'zh-HK': '繁體中文(香港)',
|
||||||
'zh-TW': '繁體中文(臺灣)',
|
'zh-TW': '繁體中文(臺灣)',
|
||||||
zh: '中文',
|
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
def human_locale(locale)
|
def native_locale_name(locale)
|
||||||
if locale == 'und'
|
if locale.blank? || locale == 'und'
|
||||||
I18n.t('generic.none')
|
I18n.t('generic.none')
|
||||||
|
elsif (supported_locale = SUPPORTED_LOCALES[locale.to_sym])
|
||||||
|
supported_locale[1]
|
||||||
|
elsif (regional_locale = REGIONAL_LOCALE_NAMES[locale.to_sym])
|
||||||
|
regional_locale
|
||||||
else
|
else
|
||||||
HUMAN_LOCALES[locale.to_sym] || locale
|
locale
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def standard_locale_name(locale)
|
||||||
|
if locale.blank?
|
||||||
|
I18n.t('generic.none')
|
||||||
|
elsif (supported_locale = SUPPORTED_LOCALES[locale.to_sym])
|
||||||
|
supported_locale[0]
|
||||||
|
else
|
||||||
|
locale
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_locale_or_nil(str)
|
||||||
|
return if str.blank?
|
||||||
|
|
||||||
|
code, = str.to_s.split(/[_-]/) # Strip out the region from e.g. en_US or ja-JP
|
||||||
|
|
||||||
|
return unless valid_locale?(code)
|
||||||
|
|
||||||
|
code
|
||||||
|
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)
|
||||||
|
locale.present? && SUPPORTED_LOCALES.key?(locale.to_sym)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module SettingsHelper
|
module SettingsHelper
|
||||||
def filterable_languages
|
def filterable_languages
|
||||||
LanguageDetector.instance.language_names.select(&LanguagesHelper::HUMAN_LOCALES.method(:key?))
|
LanguagesHelper::SUPPORTED_LOCALES.keys
|
||||||
end
|
end
|
||||||
|
|
||||||
def hash_to_object(hash)
|
def hash_to_object(hash)
|
||||||
|
@ -132,7 +132,7 @@ module StatusesHelper
|
|||||||
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 +150,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 +170,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 +178,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
|
||||||
|
|
||||||
|
@ -75,6 +75,8 @@ export const INIT_MEDIA_EDIT_MODAL = 'INIT_MEDIA_EDIT_MODAL';
|
|||||||
export const COMPOSE_CHANGE_MEDIA_DESCRIPTION = 'COMPOSE_CHANGE_MEDIA_DESCRIPTION';
|
export const COMPOSE_CHANGE_MEDIA_DESCRIPTION = 'COMPOSE_CHANGE_MEDIA_DESCRIPTION';
|
||||||
export const COMPOSE_CHANGE_MEDIA_FOCUS = 'COMPOSE_CHANGE_MEDIA_FOCUS';
|
export const COMPOSE_CHANGE_MEDIA_FOCUS = 'COMPOSE_CHANGE_MEDIA_FOCUS';
|
||||||
|
|
||||||
|
export const COMPOSE_SET_STATUS = 'COMPOSE_SET_STATUS';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
|
uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
|
||||||
uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },
|
uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },
|
||||||
@ -88,6 +90,15 @@ export const ensureComposeIsVisible = (getState, routerHistory) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function setComposeToStatus(status, text, spoiler_text) {
|
||||||
|
return{
|
||||||
|
type: COMPOSE_SET_STATUS,
|
||||||
|
status,
|
||||||
|
text,
|
||||||
|
spoiler_text,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export function changeCompose(text) {
|
export function changeCompose(text) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_CHANGE,
|
type: COMPOSE_CHANGE,
|
||||||
@ -151,7 +162,8 @@ export function directCompose(account, routerHistory) {
|
|||||||
export function submitCompose(routerHistory) {
|
export function submitCompose(routerHistory) {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
let status = getState().getIn(['compose', 'text'], '');
|
let status = getState().getIn(['compose', 'text'], '');
|
||||||
let media = getState().getIn(['compose', 'media_attachments']);
|
const media = getState().getIn(['compose', 'media_attachments']);
|
||||||
|
const statusId = getState().getIn(['compose', 'id'], null);
|
||||||
const spoilers = getState().getIn(['compose', 'spoiler']) || getState().getIn(['local_settings', 'always_show_spoilers_field']);
|
const spoilers = getState().getIn(['compose', 'spoiler']) || getState().getIn(['local_settings', 'always_show_spoilers_field']);
|
||||||
let spoilerText = spoilers ? getState().getIn(['compose', 'spoiler_text'], '') : '';
|
let spoilerText = spoilers ? getState().getIn(['compose', 'spoiler_text'], '') : '';
|
||||||
|
|
||||||
@ -159,11 +171,16 @@ export function submitCompose(routerHistory) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(submitComposeRequest());
|
|
||||||
if (getState().getIn(['compose', 'advanced_options', 'do_not_federate'])) {
|
if (getState().getIn(['compose', 'advanced_options', 'do_not_federate'])) {
|
||||||
status = status + ' 👁️';
|
status = status + ' 👁️';
|
||||||
}
|
}
|
||||||
api(getState).post('/api/v1/statuses', {
|
|
||||||
|
dispatch(submitComposeRequest());
|
||||||
|
|
||||||
|
api(getState).request({
|
||||||
|
url: statusId === null ? '/api/v1/statuses' : `/api/v1/statuses/${statusId}`,
|
||||||
|
method: statusId === null ? 'post' : 'put',
|
||||||
|
data: {
|
||||||
status,
|
status,
|
||||||
content_type: getState().getIn(['compose', 'content_type']),
|
content_type: getState().getIn(['compose', 'content_type']),
|
||||||
in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
|
in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
|
||||||
@ -172,7 +189,7 @@ export function submitCompose(routerHistory) {
|
|||||||
spoiler_text: spoilerText,
|
spoiler_text: spoilerText,
|
||||||
visibility: getState().getIn(['compose', 'privacy']),
|
visibility: getState().getIn(['compose', 'privacy']),
|
||||||
poll: getState().getIn(['compose', 'poll'], null),
|
poll: getState().getIn(['compose', 'poll'], null),
|
||||||
}, {
|
},
|
||||||
headers: {
|
headers: {
|
||||||
'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']),
|
'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']),
|
||||||
},
|
},
|
||||||
@ -202,14 +219,16 @@ export function submitCompose(routerHistory) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (statusId === null) {
|
||||||
insertIfOnline('home');
|
insertIfOnline('home');
|
||||||
|
}
|
||||||
|
|
||||||
if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
|
if (statusId === null && response.data.in_reply_to_id === null && response.data.visibility === 'public') {
|
||||||
insertIfOnline('community');
|
insertIfOnline('community');
|
||||||
if (!response.data.local_only) {
|
if (!response.data.local_only) {
|
||||||
insertIfOnline('public');
|
insertIfOnline('public');
|
||||||
}
|
}
|
||||||
} else if (response.data.visibility === 'direct') {
|
} else if (statusId === null && response.data.visibility === 'direct') {
|
||||||
insertIfOnline('direct');
|
insertIfOnline('direct');
|
||||||
}
|
}
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
|
37
app/javascript/flavours/glitch/actions/history.js
Normal file
37
app/javascript/flavours/glitch/actions/history.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import api from 'flavours/glitch/util/api';
|
||||||
|
import { importFetchedAccounts } from './importer';
|
||||||
|
|
||||||
|
export const HISTORY_FETCH_REQUEST = 'HISTORY_FETCH_REQUEST';
|
||||||
|
export const HISTORY_FETCH_SUCCESS = 'HISTORY_FETCH_SUCCESS';
|
||||||
|
export const HISTORY_FETCH_FAIL = 'HISTORY_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const fetchHistory = statusId => (dispatch, getState) => {
|
||||||
|
const loading = getState().getIn(['history', statusId, 'loading']);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchHistoryRequest(statusId));
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/statuses/${statusId}/history`).then(({ data }) => {
|
||||||
|
dispatch(importFetchedAccounts(data.map(x => x.account)));
|
||||||
|
dispatch(fetchHistorySuccess(statusId, data));
|
||||||
|
}).catch(error => dispatch(fetchHistoryFail(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchHistoryRequest = statusId => ({
|
||||||
|
type: HISTORY_FETCH_REQUEST,
|
||||||
|
statusId,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchHistorySuccess = (statusId, history) => ({
|
||||||
|
type: HISTORY_FETCH_SUCCESS,
|
||||||
|
statusId,
|
||||||
|
history,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchHistoryFail = error => ({
|
||||||
|
type: HISTORY_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
@ -9,9 +9,10 @@ export function openModal(type, props) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function closeModal(type) {
|
export function closeModal(type, options = { ignoreFocus: false }) {
|
||||||
return {
|
return {
|
||||||
type: MODAL_CLOSE,
|
type: MODAL_CLOSE,
|
||||||
modalType: type,
|
modalType: type,
|
||||||
|
ignoreFocus: options.ignoreFocus,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -47,7 +47,6 @@ export const NOTIFICATIONS_UNMOUNT = 'NOTIFICATIONS_UNMOUNT';
|
|||||||
|
|
||||||
export const NOTIFICATIONS_SET_VISIBILITY = 'NOTIFICATIONS_SET_VISIBILITY';
|
export const NOTIFICATIONS_SET_VISIBILITY = 'NOTIFICATIONS_SET_VISIBILITY';
|
||||||
|
|
||||||
|
|
||||||
export const NOTIFICATIONS_MARK_AS_READ = 'NOTIFICATIONS_MARK_AS_READ';
|
export const NOTIFICATIONS_MARK_AS_READ = 'NOTIFICATIONS_MARK_AS_READ';
|
||||||
|
|
||||||
export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT';
|
||||||
@ -58,7 +57,7 @@ defineMessages({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const fetchRelatedRelationships = (dispatch, notifications) => {
|
const fetchRelatedRelationships = (dispatch, notifications) => {
|
||||||
const accountIds = notifications.filter(item => item.type === 'follow').map(item => item.account.id);
|
const accountIds = notifications.filter(item => ['follow', 'follow_request', 'admin.sign_up'].indexOf(item.type) !== -1).map(item => item.account.id);
|
||||||
|
|
||||||
if (accountIds > 0) {
|
if (accountIds > 0) {
|
||||||
dispatch(fetchRelationships(accountIds));
|
dispatch(fetchRelationships(accountIds));
|
||||||
@ -136,7 +135,18 @@ const excludeTypesFromSettings = state => state.getIn(['settings', 'notification
|
|||||||
|
|
||||||
|
|
||||||
const excludeTypesFromFilter = filter => {
|
const excludeTypesFromFilter = filter => {
|
||||||
const allTypes = ImmutableList(['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll']);
|
const allTypes = ImmutableList([
|
||||||
|
'follow',
|
||||||
|
'follow_request',
|
||||||
|
'favourite',
|
||||||
|
'reblog',
|
||||||
|
'mention',
|
||||||
|
'poll',
|
||||||
|
'status',
|
||||||
|
'update',
|
||||||
|
'admin.sign_up',
|
||||||
|
]);
|
||||||
|
|
||||||
return allTypes.filterNot(item => item === filter).toJS();
|
return allTypes.filterNot(item => item === filter).toJS();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,89 +1,38 @@
|
|||||||
import api from 'flavours/glitch/util/api';
|
import api from 'flavours/glitch/util/api';
|
||||||
import { openModal, closeModal } from './modal';
|
import { openModal } from './modal';
|
||||||
|
|
||||||
export const REPORT_INIT = 'REPORT_INIT';
|
|
||||||
export const REPORT_CANCEL = 'REPORT_CANCEL';
|
|
||||||
|
|
||||||
export const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST';
|
export const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST';
|
||||||
export const REPORT_SUBMIT_SUCCESS = 'REPORT_SUBMIT_SUCCESS';
|
export const REPORT_SUBMIT_SUCCESS = 'REPORT_SUBMIT_SUCCESS';
|
||||||
export const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL';
|
export const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL';
|
||||||
|
|
||||||
export const REPORT_STATUS_TOGGLE = 'REPORT_STATUS_TOGGLE';
|
export const initReport = (account, status) => dispatch =>
|
||||||
export const REPORT_COMMENT_CHANGE = 'REPORT_COMMENT_CHANGE';
|
dispatch(openModal('REPORT', {
|
||||||
export const REPORT_FORWARD_CHANGE = 'REPORT_FORWARD_CHANGE';
|
accountId: account.get('id'),
|
||||||
|
statusId: status?.get('id'),
|
||||||
|
}));
|
||||||
|
|
||||||
export function initReport(account, status) {
|
export const submitReport = (params, onSuccess, onFail) => (dispatch, getState) => {
|
||||||
return dispatch => {
|
|
||||||
dispatch({
|
|
||||||
type: REPORT_INIT,
|
|
||||||
account,
|
|
||||||
status,
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(openModal('REPORT'));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export function cancelReport() {
|
|
||||||
return {
|
|
||||||
type: REPORT_CANCEL,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export function toggleStatusReport(statusId, checked) {
|
|
||||||
return {
|
|
||||||
type: REPORT_STATUS_TOGGLE,
|
|
||||||
statusId,
|
|
||||||
checked,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export function submitReport() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
dispatch(submitReportRequest());
|
dispatch(submitReportRequest());
|
||||||
|
|
||||||
api(getState).post('/api/v1/reports', {
|
api(getState).post('/api/v1/reports', params).then(response => {
|
||||||
account_id: getState().getIn(['reports', 'new', 'account_id']),
|
|
||||||
status_ids: getState().getIn(['reports', 'new', 'status_ids']),
|
|
||||||
comment: getState().getIn(['reports', 'new', 'comment']),
|
|
||||||
forward: getState().getIn(['reports', 'new', 'forward']),
|
|
||||||
}).then(response => {
|
|
||||||
dispatch(closeModal());
|
|
||||||
dispatch(submitReportSuccess(response.data));
|
dispatch(submitReportSuccess(response.data));
|
||||||
}).catch(error => dispatch(submitReportFail(error)));
|
if (onSuccess) onSuccess();
|
||||||
};
|
}).catch(error => {
|
||||||
|
dispatch(submitReportFail(error));
|
||||||
|
if (onFail) onFail();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export function submitReportRequest() {
|
export const submitReportRequest = () => ({
|
||||||
return {
|
|
||||||
type: REPORT_SUBMIT_REQUEST,
|
type: REPORT_SUBMIT_REQUEST,
|
||||||
};
|
});
|
||||||
};
|
|
||||||
|
|
||||||
export function submitReportSuccess(report) {
|
export const submitReportSuccess = report => ({
|
||||||
return {
|
|
||||||
type: REPORT_SUBMIT_SUCCESS,
|
type: REPORT_SUBMIT_SUCCESS,
|
||||||
report,
|
report,
|
||||||
};
|
});
|
||||||
};
|
|
||||||
|
|
||||||
export function submitReportFail(error) {
|
export const submitReportFail = error => ({
|
||||||
return {
|
|
||||||
type: REPORT_SUBMIT_FAIL,
|
type: REPORT_SUBMIT_FAIL,
|
||||||
error,
|
error,
|
||||||
};
|
});
|
||||||
};
|
|
||||||
|
|
||||||
export function changeReportComment(comment) {
|
|
||||||
return {
|
|
||||||
type: REPORT_COMMENT_CHANGE,
|
|
||||||
comment,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export function changeReportForward(forward) {
|
|
||||||
return {
|
|
||||||
type: REPORT_FORWARD_CHANGE,
|
|
||||||
forward,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
27
app/javascript/flavours/glitch/actions/rules.js
Normal file
27
app/javascript/flavours/glitch/actions/rules.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import api from 'flavours/glitch/util/api';
|
||||||
|
|
||||||
|
export const RULES_FETCH_REQUEST = 'RULES_FETCH_REQUEST';
|
||||||
|
export const RULES_FETCH_SUCCESS = 'RULES_FETCH_SUCCESS';
|
||||||
|
export const RULES_FETCH_FAIL = 'RULES_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const fetchRules = () => (dispatch, getState) => {
|
||||||
|
dispatch(fetchRulesRequest());
|
||||||
|
|
||||||
|
api(getState)
|
||||||
|
.get('/api/v1/instance').then(({ data }) => dispatch(fetchRulesSuccess(data.rules)))
|
||||||
|
.catch(err => dispatch(fetchRulesFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchRulesRequest = () => ({
|
||||||
|
type: RULES_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchRulesSuccess = rules => ({
|
||||||
|
type: RULES_FETCH_SUCCESS,
|
||||||
|
rules,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchRulesFail = error => ({
|
||||||
|
type: RULES_FETCH_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
@ -2,7 +2,7 @@ import api from 'flavours/glitch/util/api';
|
|||||||
|
|
||||||
import { deleteFromTimelines } from './timelines';
|
import { deleteFromTimelines } from './timelines';
|
||||||
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
||||||
import { ensureComposeIsVisible } from './compose';
|
import { ensureComposeIsVisible, setComposeToStatus } from './compose';
|
||||||
|
|
||||||
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';
|
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';
|
||||||
export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS';
|
export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS';
|
||||||
@ -26,6 +26,10 @@ export const STATUS_UNMUTE_FAIL = 'STATUS_UNMUTE_FAIL';
|
|||||||
|
|
||||||
export const REDRAFT = 'REDRAFT';
|
export const REDRAFT = 'REDRAFT';
|
||||||
|
|
||||||
|
export const STATUS_FETCH_SOURCE_REQUEST = 'STATUS_FETCH_SOURCE_REQUEST';
|
||||||
|
export const STATUS_FETCH_SOURCE_SUCCESS = 'STATUS_FETCH_SOURCE_SUCCESS';
|
||||||
|
export const STATUS_FETCH_SOURCE_FAIL = 'STATUS_FETCH_SOURCE_FAIL';
|
||||||
|
|
||||||
export function fetchStatusRequest(id, skipLoading) {
|
export function fetchStatusRequest(id, skipLoading) {
|
||||||
return {
|
return {
|
||||||
type: STATUS_FETCH_REQUEST,
|
type: STATUS_FETCH_REQUEST,
|
||||||
@ -81,6 +85,37 @@ export function redraft(status, raw_text, content_type) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const editStatus = (id, routerHistory) => (dispatch, getState) => {
|
||||||
|
let status = getState().getIn(['statuses', id]);
|
||||||
|
|
||||||
|
if (status.get('poll')) {
|
||||||
|
status = status.set('poll', getState().getIn(['polls', status.get('poll')]));
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(fetchStatusSourceRequest());
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/statuses/${id}/source`).then(response => {
|
||||||
|
dispatch(fetchStatusSourceSuccess());
|
||||||
|
ensureComposeIsVisible(getState, routerHistory);
|
||||||
|
dispatch(setComposeToStatus(status, response.data.text, response.data.spoiler_text));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchStatusSourceFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchStatusSourceRequest = () => ({
|
||||||
|
type: STATUS_FETCH_SOURCE_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchStatusSourceSuccess = () => ({
|
||||||
|
type: STATUS_FETCH_SOURCE_SUCCESS,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchStatusSourceFail = error => ({
|
||||||
|
type: STATUS_FETCH_SOURCE_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
export function deleteStatus(id, routerHistory, withRedraft = false) {
|
export function deleteStatus(id, routerHistory, withRedraft = false) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
let status = getState().getIn(['statuses', id]);
|
let status = getState().getIn(['statuses', id]);
|
||||||
|
@ -68,12 +68,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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
9
app/javascript/flavours/glitch/components/check.js
Normal file
9
app/javascript/flavours/glitch/components/check.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const Check = () => (
|
||||||
|
<svg width='14' height='11' viewBox='0 0 14 11'>
|
||||||
|
<path d='M11.264 0L5.26 6.004 2.103 2.847 0 4.95l5.26 5.26 8.108-8.107L11.264 0' fill='currentColor' fillRule='evenodd' />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Check;
|
@ -6,6 +6,8 @@ import Overlay from 'react-overlays/lib/Overlay';
|
|||||||
import Motion from 'flavours/glitch/util/optional_motion';
|
import Motion from 'flavours/glitch/util/optional_motion';
|
||||||
import spring from 'react-motion/lib/spring';
|
import spring from 'react-motion/lib/spring';
|
||||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { CircularProgress } from 'mastodon/components/loading_indicator';
|
||||||
|
|
||||||
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
|
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
|
||||||
let id = 0;
|
let id = 0;
|
||||||
@ -17,13 +19,18 @@ class DropdownMenu extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
items: PropTypes.array.isRequired,
|
items: PropTypes.oneOfType([PropTypes.array, ImmutablePropTypes.list]).isRequired,
|
||||||
|
loading: PropTypes.bool,
|
||||||
|
scrollable: PropTypes.bool,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
placement: PropTypes.string,
|
placement: PropTypes.string,
|
||||||
arrowOffsetLeft: PropTypes.string,
|
arrowOffsetLeft: PropTypes.string,
|
||||||
arrowOffsetTop: PropTypes.string,
|
arrowOffsetTop: PropTypes.string,
|
||||||
openedViaKeyboard: PropTypes.bool,
|
openedViaKeyboard: PropTypes.bool,
|
||||||
|
renderItem: PropTypes.func,
|
||||||
|
renderHeader: PropTypes.func,
|
||||||
|
onItemClick: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@ -45,9 +52,11 @@ class DropdownMenu extends React.PureComponent {
|
|||||||
document.addEventListener('click', this.handleDocumentClick, false);
|
document.addEventListener('click', this.handleDocumentClick, false);
|
||||||
document.addEventListener('keydown', this.handleKeyDown, false);
|
document.addEventListener('keydown', this.handleKeyDown, false);
|
||||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||||
|
|
||||||
if (this.focusedItem && this.props.openedViaKeyboard) {
|
if (this.focusedItem && this.props.openedViaKeyboard) {
|
||||||
this.focusedItem.focus({ preventScroll: true });
|
this.focusedItem.focus({ preventScroll: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ mounted: true });
|
this.setState({ mounted: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +75,7 @@ class DropdownMenu extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown = e => {
|
handleKeyDown = e => {
|
||||||
const items = Array.from(this.node.getElementsByTagName('a'));
|
const items = Array.from(this.node.querySelectorAll('a, button'));
|
||||||
const index = items.indexOf(document.activeElement);
|
const index = items.indexOf(document.activeElement);
|
||||||
let element = null;
|
let element = null;
|
||||||
|
|
||||||
@ -109,30 +118,20 @@ class DropdownMenu extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleClick = e => {
|
handleClick = e => {
|
||||||
const i = Number(e.currentTarget.getAttribute('data-index'));
|
const { onItemClick } = this.props;
|
||||||
const { action, to } = this.props.items[i];
|
onItemClick(e);
|
||||||
|
|
||||||
this.props.onClose();
|
|
||||||
|
|
||||||
if (typeof action === 'function') {
|
|
||||||
e.preventDefault();
|
|
||||||
action();
|
|
||||||
} else if (to) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.context.router.history.push(to);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderItem (option, i) {
|
renderItem = (option, i) => {
|
||||||
if (option === null) {
|
if (option === null) {
|
||||||
return <li key={`sep-${i}`} className='dropdown-menu__separator' />;
|
return <li key={`sep-${i}`} className='dropdown-menu__separator' />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { text, href = '#' } = option;
|
const { text, href = '#', target = '_blank', method } = option;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className='dropdown-menu__item' key={`${text}-${i}`}>
|
<li className='dropdown-menu__item' key={`${text}-${i}`}>
|
||||||
<a href={href} target='_blank' rel='noopener noreferrer' role='button' tabIndex='0' ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyPress={this.handleItemKeyPress} data-index={i}>
|
<a href={href} target={target} data-method={method} rel='noopener noreferrer' role='button' tabIndex='0' ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyPress={this.handleItemKeyPress} data-index={i}>
|
||||||
{text}
|
{text}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@ -140,21 +139,37 @@ class DropdownMenu extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { items, style, placement, arrowOffsetLeft, arrowOffsetTop } = this.props;
|
const { items, style, placement, arrowOffsetLeft, arrowOffsetTop, scrollable, renderHeader, loading } = this.props;
|
||||||
const { mounted } = this.state;
|
const { mounted } = this.state;
|
||||||
|
|
||||||
|
let renderItem = this.props.renderItem || this.renderItem;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
|
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
|
||||||
{({ opacity, scaleX, scaleY }) => (
|
{({ opacity, scaleX, scaleY }) => (
|
||||||
// It should not be transformed when mounting because the resulting
|
// It should not be transformed when mounting because the resulting
|
||||||
// size will be used to determine the coordinate of the menu by
|
// size will be used to determine the coordinate of the menu by
|
||||||
// react-overlays
|
// react-overlays
|
||||||
<div className='dropdown-menu' style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} ref={this.setRef}>
|
<div className={`dropdown-menu ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} ref={this.setRef}>
|
||||||
<div className={`dropdown-menu__arrow ${placement}`} style={{ left: arrowOffsetLeft, top: arrowOffsetTop }} />
|
<div className={`dropdown-menu__arrow ${placement}`} style={{ left: arrowOffsetLeft, top: arrowOffsetTop }} />
|
||||||
|
|
||||||
<ul>
|
<div className={classNames('dropdown-menu__container', { 'dropdown-menu__container--loading': loading })}>
|
||||||
{items.map((option, i) => this.renderItem(option, i))}
|
{loading && (
|
||||||
|
<CircularProgress size={30} strokeWidth={3.5} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!loading && renderHeader && (
|
||||||
|
<div className='dropdown-menu__container__header'>
|
||||||
|
{renderHeader(items)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!loading && (
|
||||||
|
<ul className={classNames('dropdown-menu__container__list', { 'dropdown-menu__container__list--scrollable': scrollable })}>
|
||||||
|
{items.map((option, i) => renderItem(option, i, { onClick: this.handleClick, onKeyPress: this.handleItemKeyPress }))}
|
||||||
</ul>
|
</ul>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Motion>
|
</Motion>
|
||||||
@ -170,11 +185,14 @@ export default class Dropdown extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
icon: PropTypes.string.isRequired,
|
children: PropTypes.node,
|
||||||
items: PropTypes.array.isRequired,
|
icon: PropTypes.string,
|
||||||
size: PropTypes.number.isRequired,
|
items: PropTypes.oneOfType([PropTypes.array, ImmutablePropTypes.list]).isRequired,
|
||||||
|
loading: PropTypes.bool,
|
||||||
|
size: PropTypes.number,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
|
scrollable: PropTypes.bool,
|
||||||
status: ImmutablePropTypes.map,
|
status: ImmutablePropTypes.map,
|
||||||
isUserTouching: PropTypes.func,
|
isUserTouching: PropTypes.func,
|
||||||
onOpen: PropTypes.func.isRequired,
|
onOpen: PropTypes.func.isRequired,
|
||||||
@ -182,6 +200,9 @@ export default class Dropdown extends React.PureComponent {
|
|||||||
dropdownPlacement: PropTypes.string,
|
dropdownPlacement: PropTypes.string,
|
||||||
openDropdownId: PropTypes.number,
|
openDropdownId: PropTypes.number,
|
||||||
openedViaKeyboard: PropTypes.bool,
|
openedViaKeyboard: PropTypes.bool,
|
||||||
|
renderItem: PropTypes.func,
|
||||||
|
renderHeader: PropTypes.func,
|
||||||
|
onItemClick: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@ -236,17 +257,22 @@ export default class Dropdown extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleItemClick = (i, e) => {
|
handleItemClick = e => {
|
||||||
const { action, to } = this.props.items[i];
|
const { onItemClick } = this.props;
|
||||||
|
const i = Number(e.currentTarget.getAttribute('data-index'));
|
||||||
|
const item = this.props.items[i];
|
||||||
|
|
||||||
this.handleClose();
|
this.handleClose();
|
||||||
|
|
||||||
if (typeof action === 'function') {
|
if (typeof onItemClick === 'function') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
action();
|
onItemClick(item, i);
|
||||||
} else if (to) {
|
} else if (item && typeof item.action === 'function') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.context.router.history.push(to);
|
item.action();
|
||||||
|
} else if (item && item.to) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.context.router.history.push(item.to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,12 +290,36 @@ export default class Dropdown extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close = () => {
|
||||||
|
this.handleClose();
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { icon, items, size, title, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard } = this.props;
|
const {
|
||||||
|
icon,
|
||||||
|
items,
|
||||||
|
size,
|
||||||
|
title,
|
||||||
|
disabled,
|
||||||
|
loading,
|
||||||
|
scrollable,
|
||||||
|
dropdownPlacement,
|
||||||
|
openDropdownId,
|
||||||
|
openedViaKeyboard,
|
||||||
|
children,
|
||||||
|
renderItem,
|
||||||
|
renderHeader,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
const open = this.state.id === openDropdownId;
|
const open = this.state.id === openDropdownId;
|
||||||
|
|
||||||
return (
|
const button = children ? React.cloneElement(React.Children.only(children), {
|
||||||
<div>
|
ref: this.setTargetRef,
|
||||||
|
onClick: this.handleClick,
|
||||||
|
onMouseDown: this.handleMouseDown,
|
||||||
|
onKeyDown: this.handleButtonKeyDown,
|
||||||
|
onKeyPress: this.handleKeyPress,
|
||||||
|
}) : (
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={icon}
|
icon={icon}
|
||||||
title={title}
|
title={title}
|
||||||
@ -282,11 +332,25 @@ export default class Dropdown extends React.PureComponent {
|
|||||||
onKeyDown={this.handleButtonKeyDown}
|
onKeyDown={this.handleButtonKeyDown}
|
||||||
onKeyPress={this.handleKeyPress}
|
onKeyPress={this.handleKeyPress}
|
||||||
/>
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{button}
|
||||||
|
|
||||||
<Overlay show={open} placement={dropdownPlacement} target={this.findTarget}>
|
<Overlay show={open} placement={dropdownPlacement} target={this.findTarget}>
|
||||||
<DropdownMenu items={items} onClose={this.handleClose} openedViaKeyboard={openedViaKeyboard} />
|
<DropdownMenu
|
||||||
|
items={items}
|
||||||
|
loading={loading}
|
||||||
|
scrollable={scrollable}
|
||||||
|
onClose={this.handleClose}
|
||||||
|
openedViaKeyboard={openedViaKeyboard}
|
||||||
|
renderItem={renderItem}
|
||||||
|
renderHeader={renderHeader}
|
||||||
|
onItemClick={this.handleItemClick}
|
||||||
|
/>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
</div>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user