mirror of
https://git.bsd.gay/fef/nyastodon.git
synced 2024-12-26 07:53:43 +01:00
merge with catstodon/main
This commit is contained in:
parent
60d54db810
commit
df00e5e6cb
1396 changed files with 38723 additions and 25892 deletions
|
@ -1,7 +1,9 @@
|
||||||
[production]
|
[production]
|
||||||
defaults
|
defaults
|
||||||
not IE 11
|
> 0.2%
|
||||||
|
ios >= 15.6
|
||||||
not dead
|
not dead
|
||||||
|
not OperaMini all
|
||||||
|
|
||||||
[development]
|
[development]
|
||||||
supports es6-module
|
supports es6-module
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||||
|
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/sshd:1": {},
|
"ghcr.io/devcontainers/features/sshd:1": {}
|
||||||
},
|
},
|
||||||
|
|
||||||
"runServices": ["app", "db", "redis"],
|
"runServices": ["app", "db", "redis"],
|
||||||
|
@ -15,16 +15,16 @@
|
||||||
"portsAttributes": {
|
"portsAttributes": {
|
||||||
"3000": {
|
"3000": {
|
||||||
"label": "web",
|
"label": "web",
|
||||||
"onAutoForward": "notify",
|
"onAutoForward": "notify"
|
||||||
},
|
},
|
||||||
"4000": {
|
"4000": {
|
||||||
"label": "stream",
|
"label": "stream",
|
||||||
"onAutoForward": "silent",
|
"onAutoForward": "silent"
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"otherPortsAttributes": {
|
"otherPortsAttributes": {
|
||||||
"onAutoForward": "silent",
|
"onAutoForward": "silent"
|
||||||
},
|
},
|
||||||
|
|
||||||
"remoteEnv": {
|
"remoteEnv": {
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
"STREAMING_API_BASE_URL": "https://${localEnv:CODESPACE_NAME}-4000.app.github.dev",
|
"STREAMING_API_BASE_URL": "https://${localEnv:CODESPACE_NAME}-4000.app.github.dev",
|
||||||
"DISABLE_FORGERY_REQUEST_PROTECTION": "true",
|
"DISABLE_FORGERY_REQUEST_PROTECTION": "true",
|
||||||
"ES_ENABLED": "",
|
"ES_ENABLED": "",
|
||||||
"LIBRE_TRANSLATE_ENDPOINT": "",
|
"LIBRE_TRANSLATE_ENDPOINT": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
"onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
|
"onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"settings": {},
|
"settings": {},
|
||||||
"extensions": ["EditorConfig.EditorConfig", "webben.browserslist"],
|
"extensions": ["EditorConfig.EditorConfig", "webben.browserslist"]
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||||
|
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/sshd:1": {},
|
"ghcr.io/devcontainers/features/sshd:1": {}
|
||||||
},
|
},
|
||||||
|
|
||||||
"forwardPorts": [3000, 4000],
|
"forwardPorts": [3000, 4000],
|
||||||
|
@ -14,17 +14,17 @@
|
||||||
"3000": {
|
"3000": {
|
||||||
"label": "web",
|
"label": "web",
|
||||||
"onAutoForward": "notify",
|
"onAutoForward": "notify",
|
||||||
"requireLocalPort": true,
|
"requireLocalPort": true
|
||||||
},
|
},
|
||||||
"4000": {
|
"4000": {
|
||||||
"label": "stream",
|
"label": "stream",
|
||||||
"onAutoForward": "silent",
|
"onAutoForward": "silent",
|
||||||
"requireLocalPort": true,
|
"requireLocalPort": true
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"otherPortsAttributes": {
|
"otherPortsAttributes": {
|
||||||
"onAutoForward": "silent",
|
"onAutoForward": "silent"
|
||||||
},
|
},
|
||||||
|
|
||||||
"onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
|
"onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"settings": {},
|
"settings": {},
|
||||||
"extensions": ["EditorConfig.EditorConfig", "webben.browserslist"],
|
"extensions": ["EditorConfig.EditorConfig", "webben.browserslist"]
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ services:
|
||||||
hard: -1
|
hard: -1
|
||||||
|
|
||||||
libretranslate:
|
libretranslate:
|
||||||
image: libretranslate/libretranslate:v1.5.4
|
image: libretranslate/libretranslate:v1.5.6
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- lt-data:/home/libretranslate/.local
|
- lt-data:/home/libretranslate/.local
|
||||||
|
|
10
.eslintrc.js
10
.eslintrc.js
|
@ -123,7 +123,7 @@ module.exports = defineConfig({
|
||||||
'react/react-in-jsx-scope': 'off', // not needed with new JSX transform
|
'react/react-in-jsx-scope': 'off', // not needed with new JSX transform
|
||||||
'react/self-closing-comp': 'error',
|
'react/self-closing-comp': 'error',
|
||||||
|
|
||||||
// recommended values found in https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/index.js
|
// recommended values found in https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/v6.8.0/src/index.js#L46
|
||||||
'jsx-a11y/accessible-emoji': 'warn',
|
'jsx-a11y/accessible-emoji': 'warn',
|
||||||
'jsx-a11y/click-events-have-key-events': 'off',
|
'jsx-a11y/click-events-have-key-events': 'off',
|
||||||
'jsx-a11y/label-has-associated-control': 'off',
|
'jsx-a11y/label-has-associated-control': 'off',
|
||||||
|
@ -165,7 +165,7 @@ module.exports = defineConfig({
|
||||||
// },
|
// },
|
||||||
// ],
|
// ],
|
||||||
'jsx-a11y/no-noninteractive-tabindex': 'off',
|
'jsx-a11y/no-noninteractive-tabindex': 'off',
|
||||||
'jsx-a11y/no-onchange': 'warn',
|
'jsx-a11y/no-onchange': 'off',
|
||||||
// recommended is full 'error'
|
// recommended is full 'error'
|
||||||
'jsx-a11y/no-static-element-interactions': [
|
'jsx-a11y/no-static-element-interactions': [
|
||||||
'warn',
|
'warn',
|
||||||
|
@ -176,7 +176,7 @@ module.exports = defineConfig({
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
// See https://github.com/import-js/eslint-plugin-import/blob/main/config/recommended.js
|
// See https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/config/recommended.js
|
||||||
'import/extensions': [
|
'import/extensions': [
|
||||||
'error',
|
'error',
|
||||||
'always',
|
'always',
|
||||||
|
@ -355,7 +355,6 @@ module.exports = defineConfig({
|
||||||
'plugin:import/typescript',
|
'plugin:import/typescript',
|
||||||
'plugin:promise/recommended',
|
'plugin:promise/recommended',
|
||||||
'plugin:jsdoc/recommended-typescript',
|
'plugin:jsdoc/recommended-typescript',
|
||||||
'plugin:prettier/recommended',
|
|
||||||
],
|
],
|
||||||
|
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
|
@ -364,6 +363,9 @@ module.exports = defineConfig({
|
||||||
},
|
},
|
||||||
|
|
||||||
rules: {
|
rules: {
|
||||||
|
// Disable formatting rules that have been enabled in the base config
|
||||||
|
'indent': 'off',
|
||||||
|
|
||||||
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
||||||
|
|
||||||
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
|
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
|
||||||
|
|
2
.github/actions/setup-javascript/action.yml
vendored
2
.github/actions/setup-javascript/action.yml
vendored
|
@ -23,7 +23,7 @@ runs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
|
4
.github/codecov.yml
vendored
4
.github/codecov.yml
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
comment: false # Do not leave PR comments
|
||||||
coverage:
|
coverage:
|
||||||
status:
|
status:
|
||||||
project:
|
project:
|
||||||
|
@ -8,6 +9,3 @@ coverage:
|
||||||
default:
|
default:
|
||||||
# Github status check is not blocking
|
# Github status check is not blocking
|
||||||
informational: true
|
informational: true
|
||||||
comment:
|
|
||||||
# Only write a comment in PR if there are changes
|
|
||||||
require_changes: true
|
|
||||||
|
|
16
.github/renovate.json5
vendored
16
.github/renovate.json5
vendored
|
@ -125,6 +125,22 @@
|
||||||
],
|
],
|
||||||
groupName: null, // We dont want them to belong to any group
|
groupName: null, // We dont want them to belong to any group
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Group all RuboCop packages with `rubocop` in the same PR
|
||||||
|
matchManagers: ['bundler'],
|
||||||
|
matchPackageNames: ['rubocop'],
|
||||||
|
matchPackagePrefixes: ['rubocop-'],
|
||||||
|
matchUpdateTypes: ['patch', 'minor'],
|
||||||
|
groupName: 'RuboCop (non-major)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Group all RSpec packages with `rspec` in the same PR
|
||||||
|
matchManagers: ['bundler'],
|
||||||
|
matchPackageNames: ['rspec'],
|
||||||
|
matchPackagePrefixes: ['rspec-'],
|
||||||
|
matchUpdateTypes: ['patch', 'minor'],
|
||||||
|
groupName: 'RSpec (non-major)',
|
||||||
|
},
|
||||||
// Add labels depending on package manager
|
// Add labels depending on package manager
|
||||||
{ matchManagers: ['npm', 'nvm'], addLabels: ['javascript'] },
|
{ matchManagers: ['npm', 'nvm'], addLabels: ['javascript'] },
|
||||||
{ matchManagers: ['bundler', 'ruby-version'], addLabels: ['ruby'] },
|
{ matchManagers: ['bundler', 'ruby-version'], addLabels: ['ruby'] },
|
||||||
|
|
2
.github/workflows/crowdin-download.yml
vendored
2
.github/workflows/crowdin-download.yml
vendored
|
@ -53,7 +53,7 @@ jobs:
|
||||||
|
|
||||||
# Create or update the pull request
|
# Create or update the pull request
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v5.0.2
|
uses: peter-evans/create-pull-request@v6.0.2
|
||||||
with:
|
with:
|
||||||
commit-message: 'New Crowdin translations'
|
commit-message: 'New Crowdin translations'
|
||||||
title: 'New Crowdin Translations (automated)'
|
title: 'New Crowdin Translations (automated)'
|
||||||
|
|
18
.github/workflows/format-check.yml
vendored
Normal file
18
.github/workflows/format-check.yml
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
name: Check formatting
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Javascript environment
|
||||||
|
uses: ./.github/actions/setup-javascript
|
||||||
|
|
||||||
|
- name: Check formatting with Prettier
|
||||||
|
run: yarn format:check
|
2
.github/workflows/lint-css.yml
vendored
2
.github/workflows/lint-css.yml
vendored
|
@ -43,4 +43,4 @@ jobs:
|
||||||
- run: echo "::add-matcher::.github/stylelint-matcher.json"
|
- run: echo "::add-matcher::.github/stylelint-matcher.json"
|
||||||
|
|
||||||
- name: Stylelint
|
- name: Stylelint
|
||||||
run: yarn lint:sass
|
run: yarn lint:css
|
||||||
|
|
2
.github/workflows/lint-haml.yml
vendored
2
.github/workflows/lint-haml.yml
vendored
|
@ -36,4 +36,4 @@ jobs:
|
||||||
- name: Run haml-lint
|
- name: Run haml-lint
|
||||||
run: |
|
run: |
|
||||||
echo "::add-matcher::.github/workflows/haml-lint-problem-matcher.json"
|
echo "::add-matcher::.github/workflows/haml-lint-problem-matcher.json"
|
||||||
bundle exec haml-lint
|
bundle exec haml-lint --reporter github
|
||||||
|
|
38
.github/workflows/lint-json.yml
vendored
38
.github/workflows/lint-json.yml
vendored
|
@ -1,38 +0,0 @@
|
||||||
name: JSON Linting
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'dependabot/**'
|
|
||||||
- 'renovate/**'
|
|
||||||
paths:
|
|
||||||
- 'package.json'
|
|
||||||
- 'yarn.lock'
|
|
||||||
- '.nvmrc'
|
|
||||||
- '.prettier*'
|
|
||||||
- '**/*.json'
|
|
||||||
- '.github/workflows/lint-json.yml'
|
|
||||||
- '!app/javascript/mastodon/locales/*.json'
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'package.json'
|
|
||||||
- 'yarn.lock'
|
|
||||||
- '.nvmrc'
|
|
||||||
- '.prettier*'
|
|
||||||
- '**/*.json'
|
|
||||||
- '.github/workflows/lint-json.yml'
|
|
||||||
- '!app/javascript/mastodon/locales/*.json'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Clone repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Javascript environment
|
|
||||||
uses: ./.github/actions/setup-javascript
|
|
||||||
|
|
||||||
- name: Prettier
|
|
||||||
run: yarn lint:json
|
|
38
.github/workflows/lint-md.yml
vendored
38
.github/workflows/lint-md.yml
vendored
|
@ -1,38 +0,0 @@
|
||||||
name: Markdown Linting
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'dependabot/**'
|
|
||||||
- 'renovate/**'
|
|
||||||
paths:
|
|
||||||
- '.github/workflows/lint-md.yml'
|
|
||||||
- '.nvmrc'
|
|
||||||
- '.prettier*'
|
|
||||||
- '**/*.md'
|
|
||||||
- '!AUTHORS.md'
|
|
||||||
- 'package.json'
|
|
||||||
- 'yarn.lock'
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- '.github/workflows/lint-md.yml'
|
|
||||||
- '.nvmrc'
|
|
||||||
- '.prettier*'
|
|
||||||
- '**/*.md'
|
|
||||||
- '!AUTHORS.md'
|
|
||||||
- 'package.json'
|
|
||||||
- 'yarn.lock'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Clone repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Javascript environment
|
|
||||||
uses: ./.github/actions/setup-javascript
|
|
||||||
|
|
||||||
- name: Prettier
|
|
||||||
run: yarn lint:md
|
|
40
.github/workflows/lint-yml.yml
vendored
40
.github/workflows/lint-yml.yml
vendored
|
@ -1,40 +0,0 @@
|
||||||
name: YML Linting
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- 'dependabot/**'
|
|
||||||
- 'renovate/**'
|
|
||||||
paths:
|
|
||||||
- 'package.json'
|
|
||||||
- 'yarn.lock'
|
|
||||||
- '.nvmrc'
|
|
||||||
- '.prettier*'
|
|
||||||
- '**/*.yaml'
|
|
||||||
- '**/*.yml'
|
|
||||||
- '.github/workflows/lint-yml.yml'
|
|
||||||
- '!config/locales/*.yml'
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'package.json'
|
|
||||||
- 'yarn.lock'
|
|
||||||
- '.nvmrc'
|
|
||||||
- '.prettier*'
|
|
||||||
- '**/*.yaml'
|
|
||||||
- '**/*.yml'
|
|
||||||
- '.github/workflows/lint-yml.yml'
|
|
||||||
- '!config/locales/*.yml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Clone repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Javascript environment
|
|
||||||
uses: ./.github/actions/setup-javascript
|
|
||||||
|
|
||||||
- name: Prettier
|
|
||||||
run: yarn lint:yml
|
|
9
.github/workflows/test-ruby.yml
vendored
9
.github/workflows/test-ruby.yml
vendored
|
@ -114,6 +114,7 @@ jobs:
|
||||||
- '3.0'
|
- '3.0'
|
||||||
- '3.1'
|
- '3.1'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
|
- '3.3'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
@ -139,7 +140,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
if: matrix.ruby-version == '.ruby-version'
|
if: matrix.ruby-version == '.ruby-version'
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
files: coverage/lcov/mastodon.lcov
|
files: coverage/lcov/mastodon.lcov
|
||||||
|
|
||||||
|
@ -189,6 +190,7 @@ jobs:
|
||||||
- '3.0'
|
- '3.0'
|
||||||
- '3.1'
|
- '3.1'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
|
- '3.3'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -224,7 +226,7 @@ jobs:
|
||||||
if: failure()
|
if: failure()
|
||||||
with:
|
with:
|
||||||
name: e2e-screenshots
|
name: e2e-screenshots
|
||||||
path: tmp/screenshots/
|
path: tmp/capybara/
|
||||||
|
|
||||||
test-search:
|
test-search:
|
||||||
name: Elastic Search integration testing
|
name: Elastic Search integration testing
|
||||||
|
@ -288,6 +290,7 @@ jobs:
|
||||||
- '3.0'
|
- '3.0'
|
||||||
- '3.1'
|
- '3.1'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
|
- '3.3'
|
||||||
search-image:
|
search-image:
|
||||||
- docker.elastic.co/elasticsearch/elasticsearch:7.17.13
|
- docker.elastic.co/elasticsearch/elasticsearch:7.17.13
|
||||||
include:
|
include:
|
||||||
|
@ -328,4 +331,4 @@ jobs:
|
||||||
if: failure()
|
if: failure()
|
||||||
with:
|
with:
|
||||||
name: test-search-screenshots
|
name: test-search-screenshots
|
||||||
path: tmp/screenshots/
|
path: tmp/capybara/
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
inherits_from: .haml-lint_todo.yml
|
|
||||||
|
|
||||||
exclude:
|
exclude:
|
||||||
- 'vendor/**/*'
|
- 'vendor/**/*'
|
||||||
- lib/templates/haml/scaffold/_form.html.haml
|
- lib/templates/haml/scaffold/_form.html.haml
|
||||||
|
@ -14,3 +12,5 @@ linters:
|
||||||
enabled: true
|
enabled: true
|
||||||
LineLength:
|
LineLength:
|
||||||
max: 320
|
max: 320
|
||||||
|
ViewLength:
|
||||||
|
max: 200 # Override default value of 100 inherited from rubocop
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
# This configuration was generated by
|
|
||||||
# `haml-lint --auto-gen-config`
|
|
||||||
# on 2024-01-09 11:30:07 -0500 using Haml-Lint version 0.53.0.
|
|
||||||
# The point is for the user to remove these configuration records
|
|
||||||
# one by one as the lints are removed from the code base.
|
|
||||||
# Note that changes in the inspected code, or installation of new
|
|
||||||
# versions of Haml-Lint, may require this file to be generated again.
|
|
||||||
|
|
||||||
linters:
|
|
||||||
# Offense count: 1
|
|
||||||
LineLength:
|
|
||||||
exclude:
|
|
||||||
- 'app/views/admin/roles/_form.html.haml'
|
|
|
@ -1,4 +1 @@
|
||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
yarn lint-staged
|
yarn lint-staged
|
||||||
|
|
|
@ -54,6 +54,13 @@
|
||||||
# Ignore Docker option files
|
# Ignore Docker option files
|
||||||
docker-compose.override.yml
|
docker-compose.override.yml
|
||||||
|
|
||||||
|
# Ignore public
|
||||||
|
/public/assets
|
||||||
|
/public/emoji
|
||||||
|
/public/packs
|
||||||
|
/public/packs-test
|
||||||
|
/public/system
|
||||||
|
|
||||||
# Ignore emoji map file
|
# Ignore emoji map file
|
||||||
/app/javascript/mastodon/features/emoji/emoji_map.json
|
/app/javascript/mastodon/features/emoji/emoji_map.json
|
||||||
|
|
||||||
|
@ -74,6 +81,7 @@ app/javascript/styles/mastodon/reset.scss
|
||||||
# Ignore the generated AUTHORS.md
|
# Ignore the generated AUTHORS.md
|
||||||
AUTHORS.md
|
AUTHORS.md
|
||||||
|
|
||||||
|
# Process a few selected JS files
|
||||||
!lint-staged.config.js
|
!lint-staged.config.js
|
||||||
|
|
||||||
# Ignore glitch-soc emoji map file
|
# Ignore glitch-soc emoji map file
|
||||||
|
|
26
.rubocop.yml
26
.rubocop.yml
|
@ -96,13 +96,6 @@ Rails/FilePath:
|
||||||
Rails/HttpStatus:
|
Rails/HttpStatus:
|
||||||
EnforcedStyle: numeric
|
EnforcedStyle: numeric
|
||||||
|
|
||||||
# Reason: Allowed in `tootctl` CLI code and in boot ENV checker
|
|
||||||
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsexit
|
|
||||||
Rails/Exit:
|
|
||||||
Exclude:
|
|
||||||
- 'config/boot.rb'
|
|
||||||
- 'lib/mastodon/cli/*.rb'
|
|
||||||
|
|
||||||
# Reason: Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions
|
# Reason: Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions
|
||||||
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter
|
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter
|
||||||
Rails/LexicallyScopedActionFilter:
|
Rails/LexicallyScopedActionFilter:
|
||||||
|
@ -135,6 +128,11 @@ Rails/UnusedIgnoredColumns:
|
||||||
Rails/NegateInclude:
|
Rails/NegateInclude:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
# Reason: Enforce default limit, but allow some elements to span lines
|
||||||
|
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecexamplelength
|
||||||
|
RSpec/ExampleLength:
|
||||||
|
CountAsOne: ['array', 'heredoc', 'method_call']
|
||||||
|
|
||||||
# Reason: Deprecated cop, will be removed in 3.0, replaced by SpecFilePathFormat
|
# Reason: Deprecated cop, will be removed in 3.0, replaced by SpecFilePathFormat
|
||||||
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecfilepath
|
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecfilepath
|
||||||
RSpec/FilePath:
|
RSpec/FilePath:
|
||||||
|
@ -175,6 +173,15 @@ Style/ClassAndModuleChildren:
|
||||||
Style/Documentation:
|
Style/Documentation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
# Reason: Route redirects are not token-formatted and must be skipped
|
||||||
|
# https://docs.rubocop.org/rubocop/cops_style.html#styleformatstringtoken
|
||||||
|
Style/FormatStringToken:
|
||||||
|
inherit_mode:
|
||||||
|
merge:
|
||||||
|
- AllowedMethods # The rubocop-rails config adds `redirect`
|
||||||
|
AllowedMethods:
|
||||||
|
- redirect_with_vary
|
||||||
|
|
||||||
# Reason: Enforce modern Ruby style
|
# Reason: Enforce modern Ruby style
|
||||||
# https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax
|
# https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax
|
||||||
Style/HashSyntax:
|
Style/HashSyntax:
|
||||||
|
@ -203,11 +210,6 @@ Style/RedundantBegin:
|
||||||
Style/RescueStandardError:
|
Style/RescueStandardError:
|
||||||
EnforcedStyle: implicit
|
EnforcedStyle: implicit
|
||||||
|
|
||||||
# Reason: Simplify some spec layouts
|
|
||||||
# https://docs.rubocop.org/rubocop/cops_style.html#stylesemicolon
|
|
||||||
Style/Semicolon:
|
|
||||||
AllowAsExpressionSeparator: true
|
|
||||||
|
|
||||||
# Reason: Originally disabled for CodeClimate, and no config consensus has been found
|
# Reason: Originally disabled for CodeClimate, and no config consensus has been found
|
||||||
# https://docs.rubocop.org/rubocop/cops_style.html#stylesymbolarray
|
# https://docs.rubocop.org/rubocop/cops_style.html#stylesymbolarray
|
||||||
Style/SymbolArray:
|
Style/SymbolArray:
|
||||||
|
|
|
@ -36,10 +36,10 @@ Metrics/PerceivedComplexity:
|
||||||
|
|
||||||
# Configuration parameters: CountAsOne.
|
# Configuration parameters: CountAsOne.
|
||||||
RSpec/ExampleLength:
|
RSpec/ExampleLength:
|
||||||
Max: 22
|
Max: 20 # Override default of 5
|
||||||
|
|
||||||
RSpec/MultipleExpectations:
|
RSpec/MultipleExpectations:
|
||||||
Max: 8
|
Max: 7
|
||||||
|
|
||||||
# Configuration parameters: AllowSubject.
|
# Configuration parameters: AllowSubject.
|
||||||
RSpec/MultipleMemoizedHelpers:
|
RSpec/MultipleMemoizedHelpers:
|
||||||
|
|
1037
CHANGELOG.md
1037
CHANGELOG.md
File diff suppressed because it is too large
Load diff
1036
CHANGELOG_glitch.md
Normal file
1036
CHANGELOG_glitch.md
Normal file
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,7 @@ FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby
|
||||||
|
|
||||||
# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
|
# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
|
||||||
# Example: v4.2.0-nightly.2023.11.09+something
|
# Example: v4.2.0-nightly.2023.11.09+something
|
||||||
# Overwrite existance of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"]
|
# Overwrite existence of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"]
|
||||||
ARG MASTODON_VERSION_PRERELEASE=""
|
ARG MASTODON_VERSION_PRERELEASE=""
|
||||||
# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"]
|
# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"]
|
||||||
ARG MASTODON_VERSION_METADATA=""
|
ARG MASTODON_VERSION_METADATA=""
|
||||||
|
@ -29,7 +29,7 @@ ARG MASTODON_VERSION_METADATA=""
|
||||||
# See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files
|
# See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files
|
||||||
ARG RAILS_SERVE_STATIC_FILES="true"
|
ARG RAILS_SERVE_STATIC_FILES="true"
|
||||||
# Allow to use YJIT compiler
|
# Allow to use YJIT compiler
|
||||||
# See: https://github.com/ruby/ruby/blob/master/doc/yjit/yjit.md
|
# See: https://github.com/ruby/ruby/blob/v3_2_3/doc/yjit/yjit.md
|
||||||
ARG RUBY_YJIT_ENABLE="1"
|
ARG RUBY_YJIT_ENABLE="1"
|
||||||
# Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin]
|
# Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin]
|
||||||
ARG TZ="Etc/UTC"
|
ARG TZ="Etc/UTC"
|
||||||
|
|
18
Gemfile
18
Gemfile
|
@ -58,7 +58,9 @@ gem 'htmlentities', '~> 4.3'
|
||||||
gem 'http', '~> 5.1'
|
gem 'http', '~> 5.1'
|
||||||
gem 'http_accept_language', '~> 2.1'
|
gem 'http_accept_language', '~> 2.1'
|
||||||
gem 'httplog', '~> 1.6.2'
|
gem 'httplog', '~> 1.6.2'
|
||||||
|
gem 'i18n', '1.14.1' # TODO: Remove version when resolved: https://github.com/glebm/i18n-tasks/issues/552 / https://github.com/ruby-i18n/i18n/pull/688
|
||||||
gem 'idn-ruby', require: 'idn'
|
gem 'idn-ruby', require: 'idn'
|
||||||
|
gem 'inline_svg'
|
||||||
gem 'kaminari', '~> 1.2'
|
gem 'kaminari', '~> 1.2'
|
||||||
gem 'link_header', '~> 0.0'
|
gem 'link_header', '~> 0.0'
|
||||||
gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
|
gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
|
||||||
|
@ -88,7 +90,7 @@ gem 'sidekiq-bulk', '~> 0.2.0'
|
||||||
gem 'simple-navigation', '~> 4.4'
|
gem 'simple-navigation', '~> 4.4'
|
||||||
gem 'simple_form', '~> 5.2'
|
gem 'simple_form', '~> 5.2'
|
||||||
gem 'stoplight', '~> 3.0.1'
|
gem 'stoplight', '~> 3.0.1'
|
||||||
gem 'strong_migrations', '1.7.0'
|
gem 'strong_migrations', '1.8.0'
|
||||||
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.2023'
|
gem 'tzinfo-data', '~> 1.2023'
|
||||||
|
@ -112,7 +114,7 @@ group :test do
|
||||||
# RSpec helpers for email specs
|
# RSpec helpers for email specs
|
||||||
gem 'email_spec'
|
gem 'email_spec'
|
||||||
|
|
||||||
# Extra RSpec extenion methods and helpers for sidekiq
|
# Extra RSpec extension methods and helpers for sidekiq
|
||||||
gem 'rspec-sidekiq', '~> 4.0'
|
gem 'rspec-sidekiq', '~> 4.0'
|
||||||
|
|
||||||
# Browser integration testing
|
# Browser integration testing
|
||||||
|
@ -125,12 +127,6 @@ group :test do
|
||||||
# Used to mock environment variables
|
# Used to mock environment variables
|
||||||
gem 'climate_control'
|
gem 'climate_control'
|
||||||
|
|
||||||
# Generating fake data for specs
|
|
||||||
gem 'faker', '~> 3.2'
|
|
||||||
|
|
||||||
# Generate test objects for specs
|
|
||||||
gem 'fabrication', '~> 2.30'
|
|
||||||
|
|
||||||
# Add back helpers functions removed in Rails 5.1
|
# Add back helpers functions removed in Rails 5.1
|
||||||
gem 'rails-controller-testing', '~> 1.0'
|
gem 'rails-controller-testing', '~> 1.0'
|
||||||
|
|
||||||
|
@ -182,6 +178,12 @@ group :development, :test do
|
||||||
# Interactive Debugging tools
|
# Interactive Debugging tools
|
||||||
gem 'debug', '~> 1.8'
|
gem 'debug', '~> 1.8'
|
||||||
|
|
||||||
|
# Generate fake data values
|
||||||
|
gem 'faker', '~> 3.2'
|
||||||
|
|
||||||
|
# Generate factory objects
|
||||||
|
gem 'fabrication', '~> 2.30'
|
||||||
|
|
||||||
# Profiling tools
|
# Profiling tools
|
||||||
gem 'memory_profiler', require: false
|
gem 'memory_profiler', require: false
|
||||||
gem 'ruby-prof', require: false
|
gem 'ruby-prof', require: false
|
||||||
|
|
215
Gemfile.lock
215
Gemfile.lock
|
@ -10,35 +10,35 @@ GIT
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (7.1.3)
|
actioncable (7.1.3.2)
|
||||||
actionpack (= 7.1.3)
|
actionpack (= 7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
actionmailbox (7.1.3)
|
actionmailbox (7.1.3.2)
|
||||||
actionpack (= 7.1.3)
|
actionpack (= 7.1.3.2)
|
||||||
activejob (= 7.1.3)
|
activejob (= 7.1.3.2)
|
||||||
activerecord (= 7.1.3)
|
activerecord (= 7.1.3.2)
|
||||||
activestorage (= 7.1.3)
|
activestorage (= 7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
net-imap
|
net-imap
|
||||||
net-pop
|
net-pop
|
||||||
net-smtp
|
net-smtp
|
||||||
actionmailer (7.1.3)
|
actionmailer (7.1.3.2)
|
||||||
actionpack (= 7.1.3)
|
actionpack (= 7.1.3.2)
|
||||||
actionview (= 7.1.3)
|
actionview (= 7.1.3.2)
|
||||||
activejob (= 7.1.3)
|
activejob (= 7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
net-imap
|
net-imap
|
||||||
net-pop
|
net-pop
|
||||||
net-smtp
|
net-smtp
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
actionpack (7.1.3)
|
actionpack (7.1.3.2)
|
||||||
actionview (= 7.1.3)
|
actionview (= 7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
racc
|
racc
|
||||||
rack (>= 2.2.4)
|
rack (>= 2.2.4)
|
||||||
|
@ -46,15 +46,15 @@ GEM
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
actiontext (7.1.3)
|
actiontext (7.1.3.2)
|
||||||
actionpack (= 7.1.3)
|
actionpack (= 7.1.3.2)
|
||||||
activerecord (= 7.1.3)
|
activerecord (= 7.1.3.2)
|
||||||
activestorage (= 7.1.3)
|
activestorage (= 7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
globalid (>= 0.6.0)
|
globalid (>= 0.6.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (7.1.3)
|
actionview (7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.11)
|
erubi (~> 1.11)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
|
@ -64,22 +64,22 @@ GEM
|
||||||
activemodel (>= 4.1)
|
activemodel (>= 4.1)
|
||||||
case_transform (>= 0.2)
|
case_transform (>= 0.2)
|
||||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||||
activejob (7.1.3)
|
activejob (7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (7.1.3)
|
activemodel (7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
activerecord (7.1.3)
|
activerecord (7.1.3.2)
|
||||||
activemodel (= 7.1.3)
|
activemodel (= 7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activestorage (7.1.3)
|
activestorage (7.1.3.2)
|
||||||
actionpack (= 7.1.3)
|
actionpack (= 7.1.3.2)
|
||||||
activejob (= 7.1.3)
|
activejob (= 7.1.3.2)
|
||||||
activerecord (= 7.1.3)
|
activerecord (= 7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
activesupport (7.1.3)
|
activesupport (7.1.3.2)
|
||||||
base64
|
base64
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
|
@ -139,7 +139,7 @@ GEM
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
parser (>= 2.4)
|
parser (>= 2.4)
|
||||||
smart_properties
|
smart_properties
|
||||||
bigdecimal (3.1.6)
|
bigdecimal (3.1.7)
|
||||||
bindata (2.4.15)
|
bindata (2.4.15)
|
||||||
binding_of_caller (1.0.0)
|
binding_of_caller (1.0.0)
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
|
@ -213,20 +213,19 @@ 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.5.0)
|
diff-lcs (1.5.1)
|
||||||
discard (1.3.0)
|
discard (1.3.0)
|
||||||
activerecord (>= 4.2, < 8)
|
activerecord (>= 4.2, < 8)
|
||||||
docile (1.4.0)
|
docile (1.4.0)
|
||||||
domain_name (0.5.20190701)
|
domain_name (0.5.20190701)
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
doorkeeper (5.6.8)
|
doorkeeper (5.6.9)
|
||||||
railties (>= 5)
|
railties (>= 5)
|
||||||
dotenv (2.8.1)
|
dotenv (2.8.1)
|
||||||
dotenv-rails (2.8.1)
|
dotenv-rails (2.8.1)
|
||||||
dotenv (= 2.8.1)
|
dotenv (= 2.8.1)
|
||||||
railties (>= 3.2)
|
railties (>= 3.2)
|
||||||
drb (2.2.0)
|
drb (2.2.1)
|
||||||
ruby2_keywords
|
|
||||||
ed25519 (1.3.0)
|
ed25519 (1.3.0)
|
||||||
elasticsearch (7.13.3)
|
elasticsearch (7.13.3)
|
||||||
elasticsearch-api (= 7.13.3)
|
elasticsearch-api (= 7.13.3)
|
||||||
|
@ -309,7 +308,7 @@ GEM
|
||||||
activesupport (>= 5.1)
|
activesupport (>= 5.1)
|
||||||
haml (>= 4.0.6)
|
haml (>= 4.0.6)
|
||||||
railties (>= 5.1)
|
railties (>= 5.1)
|
||||||
haml_lint (0.56.0)
|
haml_lint (0.57.0)
|
||||||
haml (>= 5.0)
|
haml (>= 5.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
rainbow
|
rainbow
|
||||||
|
@ -333,7 +332,7 @@ GEM
|
||||||
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)
|
httpclient (2.8.3)
|
||||||
httplog (1.6.2)
|
httplog (1.6.3)
|
||||||
rack (>= 2.0)
|
rack (>= 2.0)
|
||||||
rainbow (>= 2.0.0)
|
rainbow (>= 2.0.0)
|
||||||
i18n (1.14.1)
|
i18n (1.14.1)
|
||||||
|
@ -350,14 +349,17 @@ GEM
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
terminal-table (>= 1.5.1)
|
terminal-table (>= 1.5.1)
|
||||||
idn-ruby (0.1.5)
|
idn-ruby (0.1.5)
|
||||||
|
inline_svg (1.9.0)
|
||||||
|
activesupport (>= 3.0)
|
||||||
|
nokogiri (>= 1.6)
|
||||||
io-console (0.7.2)
|
io-console (0.7.2)
|
||||||
irb (1.11.2)
|
irb (1.12.0)
|
||||||
rdoc
|
rdoc
|
||||||
reline (>= 0.4.2)
|
reline (>= 0.4.2)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.7.1)
|
json (2.7.1)
|
||||||
json-canonicalization (1.0.0)
|
json-canonicalization (1.0.0)
|
||||||
json-jwt (1.15.3)
|
json-jwt (1.15.3.1)
|
||||||
activesupport (>= 4.2)
|
activesupport (>= 4.2)
|
||||||
aes_key_wrap
|
aes_key_wrap
|
||||||
bindata
|
bindata
|
||||||
|
@ -372,7 +374,7 @@ GEM
|
||||||
json-ld-preloaded (3.3.0)
|
json-ld-preloaded (3.3.0)
|
||||||
json-ld (~> 3.3)
|
json-ld (~> 3.3)
|
||||||
rdf (~> 3.3)
|
rdf (~> 3.3)
|
||||||
json-schema (4.1.1)
|
json-schema (4.2.0)
|
||||||
addressable (>= 2.8)
|
addressable (>= 2.8)
|
||||||
jsonapi-renderer (0.2.2)
|
jsonapi-renderer (0.2.2)
|
||||||
jwt (2.7.1)
|
jwt (2.7.1)
|
||||||
|
@ -435,7 +437,7 @@ GEM
|
||||||
mime-types-data (3.2023.1205)
|
mime-types-data (3.2023.1205)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.5)
|
mini_portile2 (2.8.5)
|
||||||
minitest (5.21.2)
|
minitest (5.22.3)
|
||||||
msgpack (1.7.2)
|
msgpack (1.7.2)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
multipart-post (2.3.0)
|
multipart-post (2.3.0)
|
||||||
|
@ -444,7 +446,7 @@ GEM
|
||||||
uri
|
uri
|
||||||
net-http-persistent (4.0.2)
|
net-http-persistent (4.0.2)
|
||||||
connection_pool (~> 2.2)
|
connection_pool (~> 2.2)
|
||||||
net-imap (0.4.9.1)
|
net-imap (0.4.10)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-ldap (0.19.0)
|
net-ldap (0.19.0)
|
||||||
|
@ -455,7 +457,7 @@ GEM
|
||||||
net-smtp (0.4.0.1)
|
net-smtp (0.4.0.1)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.5.9)
|
nio4r (2.5.9)
|
||||||
nokogiri (1.16.2)
|
nokogiri (1.16.3)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nsa (0.3.0)
|
nsa (0.3.0)
|
||||||
|
@ -465,11 +467,11 @@ GEM
|
||||||
statsd-ruby (~> 1.4, >= 1.4.0)
|
statsd-ruby (~> 1.4, >= 1.4.0)
|
||||||
oj (3.16.3)
|
oj (3.16.3)
|
||||||
bigdecimal (>= 3.0)
|
bigdecimal (>= 3.0)
|
||||||
omniauth (2.1.1)
|
omniauth (2.1.2)
|
||||||
hashie (>= 3.4.6)
|
hashie (>= 3.4.6)
|
||||||
rack (>= 2.2.3)
|
rack (>= 2.2.3)
|
||||||
rack-protection
|
rack-protection
|
||||||
omniauth-cas (3.0.0.beta.1)
|
omniauth-cas (3.0.0)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
nokogiri (~> 1.12)
|
nokogiri (~> 1.12)
|
||||||
omniauth (~> 2.1)
|
omniauth (~> 2.1)
|
||||||
|
@ -497,7 +499,7 @@ GEM
|
||||||
openssl-signature_algorithm (1.3.0)
|
openssl-signature_algorithm (1.3.0)
|
||||||
openssl (> 2.0)
|
openssl (> 2.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
ox (2.14.17)
|
ox (2.14.18)
|
||||||
parallel (1.24.0)
|
parallel (1.24.0)
|
||||||
parser (3.3.0.5)
|
parser (3.3.0.5)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
|
@ -505,7 +507,7 @@ GEM
|
||||||
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.5.5)
|
pg (1.5.6)
|
||||||
pghero (3.4.1)
|
pghero (3.4.1)
|
||||||
activerecord (>= 6)
|
activerecord (>= 6)
|
||||||
posix-spawn (0.3.15)
|
posix-spawn (0.3.15)
|
||||||
|
@ -532,10 +534,10 @@ GEM
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
raabro (1.4.0)
|
raabro (1.4.0)
|
||||||
racc (1.7.3)
|
racc (1.7.3)
|
||||||
rack (2.2.8)
|
rack (2.2.9)
|
||||||
rack-attack (6.7.0)
|
rack-attack (6.7.0)
|
||||||
rack (>= 1.0, < 4)
|
rack (>= 1.0, < 4)
|
||||||
rack-cors (2.0.1)
|
rack-cors (2.0.2)
|
||||||
rack (>= 2.0.0)
|
rack (>= 2.0.0)
|
||||||
rack-oauth2 (1.21.3)
|
rack-oauth2 (1.21.3)
|
||||||
activesupport
|
activesupport
|
||||||
|
@ -543,8 +545,9 @@ GEM
|
||||||
httpclient
|
httpclient
|
||||||
json-jwt (>= 1.11.0)
|
json-jwt (>= 1.11.0)
|
||||||
rack (>= 2.1.0)
|
rack (>= 2.1.0)
|
||||||
rack-protection (3.0.5)
|
rack-protection (3.2.0)
|
||||||
rack
|
base64 (>= 0.1.0)
|
||||||
|
rack (~> 2.2, >= 2.2.4)
|
||||||
rack-proxy (0.7.6)
|
rack-proxy (0.7.6)
|
||||||
rack
|
rack
|
||||||
rack-session (1.0.2)
|
rack-session (1.0.2)
|
||||||
|
@ -554,20 +557,20 @@ GEM
|
||||||
rackup (1.0.0)
|
rackup (1.0.0)
|
||||||
rack (< 3)
|
rack (< 3)
|
||||||
webrick
|
webrick
|
||||||
rails (7.1.3)
|
rails (7.1.3.2)
|
||||||
actioncable (= 7.1.3)
|
actioncable (= 7.1.3.2)
|
||||||
actionmailbox (= 7.1.3)
|
actionmailbox (= 7.1.3.2)
|
||||||
actionmailer (= 7.1.3)
|
actionmailer (= 7.1.3.2)
|
||||||
actionpack (= 7.1.3)
|
actionpack (= 7.1.3.2)
|
||||||
actiontext (= 7.1.3)
|
actiontext (= 7.1.3.2)
|
||||||
actionview (= 7.1.3)
|
actionview (= 7.1.3.2)
|
||||||
activejob (= 7.1.3)
|
activejob (= 7.1.3.2)
|
||||||
activemodel (= 7.1.3)
|
activemodel (= 7.1.3.2)
|
||||||
activerecord (= 7.1.3)
|
activerecord (= 7.1.3.2)
|
||||||
activestorage (= 7.1.3)
|
activestorage (= 7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 7.1.3)
|
railties (= 7.1.3.2)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
actionview (>= 5.0.1.rc1)
|
actionview (>= 5.0.1.rc1)
|
||||||
|
@ -579,12 +582,12 @@ GEM
|
||||||
rails-html-sanitizer (1.6.0)
|
rails-html-sanitizer (1.6.0)
|
||||||
loofah (~> 2.21)
|
loofah (~> 2.21)
|
||||||
nokogiri (~> 1.14)
|
nokogiri (~> 1.14)
|
||||||
rails-i18n (7.0.8)
|
rails-i18n (7.0.9)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
railties (>= 6.0.0, < 8)
|
railties (>= 6.0.0, < 8)
|
||||||
railties (7.1.3)
|
railties (7.1.3.2)
|
||||||
actionpack (= 7.1.3)
|
actionpack (= 7.1.3.2)
|
||||||
activesupport (= 7.1.3)
|
activesupport (= 7.1.3.2)
|
||||||
irb
|
irb
|
||||||
rackup (>= 1.0.0)
|
rackup (>= 1.0.0)
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
|
@ -597,7 +600,7 @@ GEM
|
||||||
link_header (~> 0.0, >= 0.0.8)
|
link_header (~> 0.0, >= 0.0.8)
|
||||||
rdf-normalize (0.7.0)
|
rdf-normalize (0.7.0)
|
||||||
rdf (~> 3.3)
|
rdf (~> 3.3)
|
||||||
rdoc (6.6.2)
|
rdoc (6.6.3.1)
|
||||||
psych (>= 4.0.0)
|
psych (>= 4.0.0)
|
||||||
redcarpet (3.6.0)
|
redcarpet (3.6.0)
|
||||||
redis (4.8.1)
|
redis (4.8.1)
|
||||||
|
@ -606,7 +609,7 @@ GEM
|
||||||
redlock (1.3.2)
|
redlock (1.3.2)
|
||||||
redis (>= 3.0.0, < 6.0)
|
redis (>= 3.0.0, < 6.0)
|
||||||
regexp_parser (2.9.0)
|
regexp_parser (2.9.0)
|
||||||
reline (0.4.2)
|
reline (0.4.3)
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
request_store (1.5.1)
|
request_store (1.5.1)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
|
@ -621,31 +624,31 @@ GEM
|
||||||
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.12.2)
|
rspec-core (3.13.0)
|
||||||
rspec-support (~> 3.12.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-expectations (3.12.3)
|
rspec-expectations (3.13.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.12.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-github (2.4.0)
|
rspec-github (2.4.0)
|
||||||
rspec-core (~> 3.0)
|
rspec-core (~> 3.0)
|
||||||
rspec-mocks (3.12.6)
|
rspec-mocks (3.13.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.12.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-rails (6.1.1)
|
rspec-rails (6.1.2)
|
||||||
actionpack (>= 6.1)
|
actionpack (>= 6.1)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 6.1)
|
||||||
railties (>= 6.1)
|
railties (>= 6.1)
|
||||||
rspec-core (~> 3.12)
|
rspec-core (~> 3.13)
|
||||||
rspec-expectations (~> 3.12)
|
rspec-expectations (~> 3.13)
|
||||||
rspec-mocks (~> 3.12)
|
rspec-mocks (~> 3.13)
|
||||||
rspec-support (~> 3.12)
|
rspec-support (~> 3.13)
|
||||||
rspec-sidekiq (4.1.0)
|
rspec-sidekiq (4.1.0)
|
||||||
rspec-core (~> 3.0)
|
rspec-core (~> 3.0)
|
||||||
rspec-expectations (~> 3.0)
|
rspec-expectations (~> 3.0)
|
||||||
rspec-mocks (~> 3.0)
|
rspec-mocks (~> 3.0)
|
||||||
sidekiq (>= 5, < 8)
|
sidekiq (>= 5, < 8)
|
||||||
rspec-support (3.12.1)
|
rspec-support (3.13.1)
|
||||||
rubocop (1.60.2)
|
rubocop (1.62.1)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (>= 3.17.0)
|
language_server-protocol (>= 3.17.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
|
@ -653,24 +656,24 @@ GEM
|
||||||
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 (>= 3.2.5, < 4.0)
|
rexml (>= 3.2.5, < 4.0)
|
||||||
rubocop-ast (>= 1.30.0, < 2.0)
|
rubocop-ast (>= 1.31.1, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 3.0)
|
unicode-display_width (>= 2.4.0, < 3.0)
|
||||||
rubocop-ast (1.30.0)
|
rubocop-ast (1.31.2)
|
||||||
parser (>= 3.2.1.0)
|
parser (>= 3.3.0.4)
|
||||||
rubocop-capybara (2.20.0)
|
rubocop-capybara (2.20.0)
|
||||||
rubocop (~> 1.41)
|
rubocop (~> 1.41)
|
||||||
rubocop-factory_bot (2.25.0)
|
rubocop-factory_bot (2.25.1)
|
||||||
rubocop (~> 1.33)
|
rubocop (~> 1.41)
|
||||||
rubocop-performance (1.20.2)
|
rubocop-performance (1.20.2)
|
||||||
rubocop (>= 1.48.1, < 2.0)
|
rubocop (>= 1.48.1, < 2.0)
|
||||||
rubocop-ast (>= 1.30.0, < 2.0)
|
rubocop-ast (>= 1.30.0, < 2.0)
|
||||||
rubocop-rails (2.23.1)
|
rubocop-rails (2.24.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.33.0, < 2.0)
|
rubocop (>= 1.33.0, < 2.0)
|
||||||
rubocop-ast (>= 1.30.0, < 2.0)
|
rubocop-ast (>= 1.31.1, < 2.0)
|
||||||
rubocop-rspec (2.26.1)
|
rubocop-rspec (2.27.1)
|
||||||
rubocop (~> 1.40)
|
rubocop (~> 1.40)
|
||||||
rubocop-capybara (~> 2.17)
|
rubocop-capybara (~> 2.17)
|
||||||
rubocop-factory_bot (~> 2.22)
|
rubocop-factory_bot (~> 2.22)
|
||||||
|
@ -691,7 +694,7 @@ GEM
|
||||||
scenic (1.7.0)
|
scenic (1.7.0)
|
||||||
activerecord (>= 4.0.0)
|
activerecord (>= 4.0.0)
|
||||||
railties (>= 4.0.0)
|
railties (>= 4.0.0)
|
||||||
selenium-webdriver (4.17.0)
|
selenium-webdriver (4.18.1)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
rexml (~> 3.2, >= 3.2.5)
|
rexml (~> 3.2, >= 3.2.5)
|
||||||
rubyzip (>= 1.2.2, < 3.0)
|
rubyzip (>= 1.2.2, < 3.0)
|
||||||
|
@ -731,7 +734,7 @@ GEM
|
||||||
stoplight (3.0.2)
|
stoplight (3.0.2)
|
||||||
redlock (~> 1.0)
|
redlock (~> 1.0)
|
||||||
stringio (3.1.0)
|
stringio (3.1.0)
|
||||||
strong_migrations (1.7.0)
|
strong_migrations (1.8.0)
|
||||||
activerecord (>= 5.2)
|
activerecord (>= 5.2)
|
||||||
swd (1.3.0)
|
swd (1.3.0)
|
||||||
activesupport (>= 3)
|
activesupport (>= 3)
|
||||||
|
@ -743,8 +746,8 @@ GEM
|
||||||
unicode-display_width (>= 1.1.1, < 3)
|
unicode-display_width (>= 1.1.1, < 3)
|
||||||
terrapin (1.0.1)
|
terrapin (1.0.1)
|
||||||
climate_control
|
climate_control
|
||||||
test-prof (1.3.1)
|
test-prof (1.3.2)
|
||||||
thor (1.3.0)
|
thor (1.3.1)
|
||||||
tilt (2.3.0)
|
tilt (2.3.0)
|
||||||
timeout (0.4.1)
|
timeout (0.4.1)
|
||||||
tpm-key_attestation (0.12.0)
|
tpm-key_attestation (0.12.0)
|
||||||
|
@ -793,7 +796,7 @@ GEM
|
||||||
webfinger (1.2.0)
|
webfinger (1.2.0)
|
||||||
activesupport
|
activesupport
|
||||||
httpclient (>= 2.4)
|
httpclient (>= 2.4)
|
||||||
webmock (3.20.0)
|
webmock (3.22.0)
|
||||||
addressable (>= 2.8.0)
|
addressable (>= 2.8.0)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff (>= 0.4.0, < 2.0.0)
|
hashdiff (>= 0.4.0, < 2.0.0)
|
||||||
|
@ -811,7 +814,7 @@ GEM
|
||||||
xorcist (1.1.3)
|
xorcist (1.1.3)
|
||||||
xpath (3.2.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
zeitwerk (2.6.12)
|
zeitwerk (2.6.13)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
@ -862,8 +865,10 @@ DEPENDENCIES
|
||||||
http (~> 5.1)
|
http (~> 5.1)
|
||||||
http_accept_language (~> 2.1)
|
http_accept_language (~> 2.1)
|
||||||
httplog (~> 1.6.2)
|
httplog (~> 1.6.2)
|
||||||
|
i18n (= 1.14.1)
|
||||||
i18n-tasks (~> 1.0)
|
i18n-tasks (~> 1.0)
|
||||||
idn-ruby
|
idn-ruby
|
||||||
|
inline_svg
|
||||||
irb (~> 1.8)
|
irb (~> 1.8)
|
||||||
json-ld
|
json-ld
|
||||||
json-ld-preloaded (~> 3.2)
|
json-ld-preloaded (~> 3.2)
|
||||||
|
@ -935,7 +940,7 @@ DEPENDENCIES
|
||||||
simplecov-lcov (~> 0.8)
|
simplecov-lcov (~> 0.8)
|
||||||
stackprof
|
stackprof
|
||||||
stoplight (~> 3.0.1)
|
stoplight (~> 3.0.1)
|
||||||
strong_migrations (= 1.7.0)
|
strong_migrations (= 1.8.0)
|
||||||
test-prof
|
test-prof
|
||||||
thor (~> 1.2)
|
thor (~> 1.2)
|
||||||
tty-prompt (~> 0.23)
|
tty-prompt (~> 0.23)
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
This Mastodon fork is based on the [glitch-soc Fork of Mastodon](https://github.com/glitch-soc/mastodon), with changes made to suit [CatCatNya~](https://catcatnya.com).
|
This Mastodon fork is based on the [glitch-soc Fork of Mastodon](https://github.com/glitch-soc/mastodon), with changes made to suit [CatCatNya~](https://catcatnya.com).
|
||||||
The aforementioned instance is running the `develop` branch.
|
|
||||||
I intend to contribute some useful differences back to [glitch-soc](https://github.com/glitch-soc/mastodon) and [vanilla Mastodon](https://github.com/mastodon/mastodon).
|
I intend to contribute some useful differences back to [glitch-soc](https://github.com/glitch-soc/mastodon) and [vanilla Mastodon](https://github.com/mastodon/mastodon).
|
||||||
|
|
||||||
To install, take a look at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/). The instructions and features are the same, except for the differences outlined below.
|
To install, take a look at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/). The instructions and features are the same, except for the differences outlined below.
|
||||||
|
@ -22,15 +21,15 @@ instead, use merge (fast-forward, if possible, with merge commit otherwise).
|
||||||
- sounds/boop.mp3
|
- sounds/boop.mp3
|
||||||
- sounds/boop.ogg
|
- sounds/boop.ogg
|
||||||
<br>You might want to revert these to the upstream files (or your own versions!) if you decide to use this fork for your own instance.
|
<br>You might want to revert these to the upstream files (or your own versions!) if you decide to use this fork for your own instance.
|
||||||
- The web frontend emoji picker is a blobcat instead of the joy emoji.
|
|
||||||
- The rate limits for authenticated users have been relaxed a bit.
|
- The rate limits for authenticated users have been relaxed a bit.
|
||||||
- The API endpoint `/api/v1/custom_emojis` is no longer affected by AUTHORIZED_FETCH, allowing anyone to copy custom emojis.
|
- The API endpoint `/api/v1/custom_emojis` is no longer affected by AUTHORIZED_FETCH, allowing anyone to copy custom emojis.
|
||||||
- Allow higher resolution images. (4096x4096 instead of the previous limit of 1920x1080)
|
- Allow higher resolution images. (4096x4096 instead of the previous limit of 3840x2160)
|
||||||
- Allow posting polls with only one poll option (if `MIN_POLL_OPTIONS` is set to 1 on your instance).
|
- Allow posting polls with only one poll option (if `MIN_POLL_OPTIONS` is set to 1 on your instance).
|
||||||
- Added oatstodon flavour (taken from [types.pl fork](https://github.com/ralsei/types.pl), by [@oat@hellsite.site](https://hellsite.site/@oat))
|
- Added oatstodon flavour (taken from [types.pl fork](https://github.com/ralsei/types.pl), by [@oat@hellsite.site](https://hellsite.site/@oat)), with slight adjustments since.
|
||||||
- Emoji reactions on statuses (with both Unicode and custom emojis, same as for announcements), a feature originally developed for [Nyastodon](https://git.bsd.gay/fef/nyastodon).
|
- Emoji reactions on statuses (with both Unicode and custom emojis, same as for announcements), a feature originally developed for [Nyastodon](https://git.bsd.gay/fef/nyastodon).
|
||||||
Ended up as a Catstodon-maintained patch after its initial two Pull Requests to glitch-soc, but was handed over to [Essem's fork, Chuckya](https://github.com/TheEssem/mastodon) and is now pending [its fourth attempt of merging into glitch-soc](https://github.com/glitch-soc/mastodon/pull/2462).
|
Ended up as a Catstodon-maintained patch after its initial two Pull Requests to glitch-soc, but was handed over to [Essem's fork, Chuckya](https://github.com/TheEssem/mastodon) and is now pending [its fourth attempt of merging into glitch-soc](https://github.com/glitch-soc/mastodon/pull/2462).
|
||||||
- Lifts the "only federate local favourites" restriction on favourites/likes and emoji reactions.
|
- Lifts the "only federate local favourites" restriction on favourites/likes and emoji reactions.
|
||||||
|
- Cherry-picks the [activity filter branch](https://github.com/chikorita157/mastodon-sakura/tree/newmain-tmp3-noellabo-filtering) from [Sakurajima Mastodon](https://github.com/chikorita157/mastodon-sakura).
|
||||||
|
|
||||||
## Previous differences now merged into glitch-soc
|
## Previous differences now merged into glitch-soc
|
||||||
|
|
||||||
|
|
2
Vagrantfile
vendored
2
Vagrantfile
vendored
|
@ -188,7 +188,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||||
|
|
||||||
config.vm.post_up_message = <<MESSAGE
|
config.vm.post_up_message = <<MESSAGE
|
||||||
To start server
|
To start server
|
||||||
$ vagrant ssh -c "cd /vagrant && foreman start"
|
$ vagrant ssh -c "cd /vagrant && bin/dev"
|
||||||
MESSAGE
|
MESSAGE
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ActivityPub::BaseController < Api::BaseController
|
class ActivityPub::BaseController < Api::BaseController
|
||||||
|
include SignatureVerification
|
||||||
|
include AccountOwnedConcern
|
||||||
|
|
||||||
skip_before_action :require_authenticated_user!
|
skip_before_action :require_authenticated_user!
|
||||||
skip_before_action :require_not_suspended!
|
skip_before_action :require_not_suspended!
|
||||||
skip_around_action :set_locale
|
skip_around_action :set_locale
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ActivityPub::ClaimsController < ActivityPub::BaseController
|
class ActivityPub::ClaimsController < ActivityPub::BaseController
|
||||||
include SignatureVerification
|
|
||||||
include AccountOwnedConcern
|
|
||||||
|
|
||||||
skip_before_action :authenticate_user!
|
skip_before_action :authenticate_user!
|
||||||
|
|
||||||
before_action :require_account_signature!
|
before_action :require_account_signature!
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ActivityPub::CollectionsController < ActivityPub::BaseController
|
class ActivityPub::CollectionsController < ActivityPub::BaseController
|
||||||
include SignatureVerification
|
|
||||||
include AccountOwnedConcern
|
|
||||||
|
|
||||||
vary_by -> { 'Signature' if authorized_fetch_mode? }
|
vary_by -> { 'Signature' if authorized_fetch_mode? }
|
||||||
|
|
||||||
before_action :require_account_signature!, if: :authorized_fetch_mode?
|
before_action :require_account_signature!, if: :authorized_fetch_mode?
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ActivityPub::FollowersSynchronizationsController < ActivityPub::BaseController
|
class ActivityPub::FollowersSynchronizationsController < ActivityPub::BaseController
|
||||||
include SignatureVerification
|
|
||||||
include AccountOwnedConcern
|
|
||||||
|
|
||||||
vary_by -> { 'Signature' if authorized_fetch_mode? }
|
vary_by -> { 'Signature' if authorized_fetch_mode? }
|
||||||
|
|
||||||
before_action :require_account_signature!
|
before_action :require_account_signature!
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ActivityPub::InboxesController < ActivityPub::BaseController
|
class ActivityPub::InboxesController < ActivityPub::BaseController
|
||||||
include SignatureVerification
|
|
||||||
include JsonLdHelper
|
include JsonLdHelper
|
||||||
include AccountOwnedConcern
|
|
||||||
|
|
||||||
before_action :skip_unknown_actor_activity
|
before_action :skip_unknown_actor_activity
|
||||||
before_action :require_actor_signature!
|
before_action :require_actor_signature!
|
||||||
|
@ -62,11 +60,10 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
|
||||||
return if raw_params.blank? || ENV['DISABLE_FOLLOWERS_SYNCHRONIZATION'] == 'true' || signed_request_account.nil?
|
return if raw_params.blank? || ENV['DISABLE_FOLLOWERS_SYNCHRONIZATION'] == 'true' || signed_request_account.nil?
|
||||||
|
|
||||||
# Re-using the syntax for signature parameters
|
# Re-using the syntax for signature parameters
|
||||||
tree = SignatureParamsParser.new.parse(raw_params)
|
params = SignatureParser.parse(raw_params)
|
||||||
params = SignatureParamsTransformer.new.apply(tree)
|
|
||||||
|
|
||||||
ActivityPub::PrepareFollowersSynchronizationService.new.call(signed_request_account, params)
|
ActivityPub::PrepareFollowersSynchronizationService.new.call(signed_request_account, params)
|
||||||
rescue Parslet::ParseFailed
|
rescue SignatureParser::ParsingError
|
||||||
Rails.logger.warn 'Error parsing Collection-Synchronization header'
|
Rails.logger.warn 'Error parsing Collection-Synchronization header'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
class ActivityPub::OutboxesController < ActivityPub::BaseController
|
class ActivityPub::OutboxesController < ActivityPub::BaseController
|
||||||
LIMIT = 20
|
LIMIT = 20
|
||||||
|
|
||||||
include SignatureVerification
|
|
||||||
include AccountOwnedConcern
|
|
||||||
|
|
||||||
vary_by -> { 'Signature' if authorized_fetch_mode? || page_requested? }
|
vary_by -> { 'Signature' if authorized_fetch_mode? || page_requested? }
|
||||||
|
|
||||||
before_action :require_account_signature!, if: :authorized_fetch_mode?
|
before_action :require_account_signature!, if: :authorized_fetch_mode?
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ActivityPub::RepliesController < ActivityPub::BaseController
|
class ActivityPub::RepliesController < ActivityPub::BaseController
|
||||||
include SignatureVerification
|
|
||||||
include Authorization
|
include Authorization
|
||||||
include AccountOwnedConcern
|
|
||||||
|
|
||||||
DESCENDANTS_LIMIT = 60
|
DESCENDANTS_LIMIT = 60
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ module Admin
|
||||||
def unblock_email
|
def unblock_email
|
||||||
authorize @account, :unblock_email?
|
authorize @account, :unblock_email?
|
||||||
|
|
||||||
CanonicalEmailBlock.where(reference_account: @account).delete_all
|
CanonicalEmailBlock.matching_account(@account).delete_all
|
||||||
|
|
||||||
log_action :unblock_email, @account
|
log_action :unblock_email, @account
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_params
|
def resource_params
|
||||||
params.require(:rule).permit(:text, :priority)
|
params.require(:rule).permit(:text, :hint, :priority)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,7 @@ class Api::BaseController < ApplicationController
|
||||||
include Api::AccessTokenTrackingConcern
|
include Api::AccessTokenTrackingConcern
|
||||||
include Api::CachingConcern
|
include Api::CachingConcern
|
||||||
include Api::ContentSecurityPolicy
|
include Api::ContentSecurityPolicy
|
||||||
|
include Api::ErrorHandling
|
||||||
|
|
||||||
skip_before_action :require_functional!, unless: :limited_federation_mode?
|
skip_before_action :require_functional!, unless: :limited_federation_mode?
|
||||||
|
|
||||||
|
@ -18,51 +19,6 @@ class Api::BaseController < ApplicationController
|
||||||
|
|
||||||
protect_from_forgery with: :null_session
|
protect_from_forgery with: :null_session
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
|
|
||||||
render json: { error: e.to_s }, status: 422
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordNotUnique do
|
|
||||||
render json: { error: 'Duplicate record' }, status: 422
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from Date::Error do
|
|
||||||
render json: { error: 'Invalid date supplied' }, status: 422
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordNotFound do
|
|
||||||
render json: { error: 'Record not found' }, status: 404
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do
|
|
||||||
render json: { error: 'Remote data could not be fetched' }, status: 503
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from OpenSSL::SSL::SSLError do
|
|
||||||
render json: { error: 'Remote SSL certificate could not be verified' }, status: 503
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from Mastodon::NotPermittedError do
|
|
||||||
render json: { error: 'This action is not allowed' }, status: 403
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from Seahorse::Client::NetworkingError do |e|
|
|
||||||
Rails.logger.warn "Storage server error: #{e}"
|
|
||||||
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight do
|
|
||||||
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from Mastodon::RateLimitExceededError do
|
|
||||||
render json: { error: I18n.t('errors.429') }, status: 429
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue_from ActionController::ParameterMissing, Mastodon::InvalidParameterError do |e|
|
|
||||||
render json: { error: e.to_s }, status: 400
|
|
||||||
end
|
|
||||||
|
|
||||||
def doorkeeper_unauthorized_render_options(error: nil)
|
def doorkeeper_unauthorized_render_options(error: nil)
|
||||||
{ json: { error: error.try(:description) || 'Not authorized' } }
|
{ json: { error: error.try(:description) || 'Not authorized' } }
|
||||||
end
|
end
|
||||||
|
@ -73,6 +29,14 @@ class Api::BaseController < ApplicationController
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
def pagination_max_id
|
||||||
|
pagination_collection.last.id
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_since_id
|
||||||
|
pagination_collection.first.id
|
||||||
|
end
|
||||||
|
|
||||||
def set_pagination_headers(next_path = nil, prev_path = nil)
|
def set_pagination_headers(next_path = nil, prev_path = nil)
|
||||||
links = []
|
links = []
|
||||||
links << [next_path, [%w(rel next)]] if next_path
|
links << [next_path, [%w(rel next)]] if next_path
|
||||||
|
@ -140,6 +104,10 @@ class Api::BaseController < ApplicationController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def insert_pagination_headers
|
||||||
|
set_pagination_headers(next_path, prev_path)
|
||||||
|
end
|
||||||
|
|
||||||
def pagination_options_invalid?
|
def pagination_options_invalid?
|
||||||
params.slice(:limit, :offset).values.map(&:to_i).any?(&:negative?)
|
params.slice(:limit, :offset).values.map(&:to_i).any?(&:negative?)
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,10 +41,6 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_account_followers_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_account_followers_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,10 +41,6 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_account_following_index_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_account_following_index_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
||||||
before_action -> { authorize_if_got_token! :read, :'read:statuses' }
|
before_action -> { authorize_if_got_token! :read, :'read:statuses' }
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
|
||||||
after_action :insert_pagination_headers, unless: -> { truthy_param?(:pinned) }
|
after_action :insert_pagination_headers
|
||||||
|
|
||||||
def index
|
def index
|
||||||
cache_if_unauthenticated!
|
cache_if_unauthenticated!
|
||||||
|
@ -35,10 +35,6 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
||||||
params.slice(:limit, *AccountStatusesFilter::KEYS).permit(:limit, *AccountStatusesFilter::KEYS).merge(core_params)
|
params.slice(:limit, *AccountStatusesFilter::KEYS).permit(:limit, *AccountStatusesFilter::KEYS).merge(core_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_account_statuses_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_account_statuses_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -51,11 +47,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
||||||
@statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)
|
@statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@statuses.last.id
|
@statuses
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@statuses.first.id
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -125,10 +125,6 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
||||||
translated_params
|
translated_params
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_admin_accounts_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
api_v1_admin_accounts_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -137,12 +133,8 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
||||||
api_v1_admin_accounts_url(pagination_params(min_id: pagination_since_id)) unless @accounts.empty?
|
api_v1_admin_accounts_url(pagination_params(min_id: pagination_since_id)) unless @accounts.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@accounts.last.id
|
@accounts
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@accounts.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -65,10 +65,6 @@ class Api::V1::Admin::CanonicalEmailBlocksController < Api::BaseController
|
||||||
@canonical_email_block = CanonicalEmailBlock.find(params[:id])
|
@canonical_email_block = CanonicalEmailBlock.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_admin_canonical_email_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
api_v1_admin_canonical_email_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -77,12 +73,8 @@ class Api::V1::Admin::CanonicalEmailBlocksController < Api::BaseController
|
||||||
api_v1_admin_canonical_email_blocks_url(pagination_params(min_id: pagination_since_id)) unless @canonical_email_blocks.empty?
|
api_v1_admin_canonical_email_blocks_url(pagination_params(min_id: pagination_since_id)) unless @canonical_email_blocks.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@canonical_email_blocks.last.id
|
@canonical_email_blocks
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@canonical_email_blocks.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -61,10 +61,6 @@ class Api::V1::Admin::DomainAllowsController < Api::BaseController
|
||||||
DomainAllow.all
|
DomainAllow.all
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_admin_domain_allows_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
api_v1_admin_domain_allows_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -73,12 +69,8 @@ class Api::V1::Admin::DomainAllowsController < Api::BaseController
|
||||||
api_v1_admin_domain_allows_url(pagination_params(min_id: pagination_since_id)) unless @domain_allows.empty?
|
api_v1_admin_domain_allows_url(pagination_params(min_id: pagination_since_id)) unless @domain_allows.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@domain_allows.last.id
|
@domain_allows
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@domain_allows.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -72,10 +72,6 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
|
||||||
params.permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate)
|
params.permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_admin_domain_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
api_v1_admin_domain_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -84,12 +80,8 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
|
||||||
api_v1_admin_domain_blocks_url(pagination_params(min_id: pagination_since_id)) unless @domain_blocks.empty?
|
api_v1_admin_domain_blocks_url(pagination_params(min_id: pagination_since_id)) unless @domain_blocks.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@domain_blocks.last.id
|
@domain_blocks
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@domain_blocks.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -58,10 +58,6 @@ class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController
|
||||||
params.permit(:domain, :allow_with_approval)
|
params.permit(:domain, :allow_with_approval)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_admin_email_domain_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
api_v1_admin_email_domain_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -70,12 +66,8 @@ class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController
|
||||||
api_v1_admin_email_domain_blocks_url(pagination_params(min_id: pagination_since_id)) unless @email_domain_blocks.empty?
|
api_v1_admin_email_domain_blocks_url(pagination_params(min_id: pagination_since_id)) unless @email_domain_blocks.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@email_domain_blocks.last.id
|
@email_domain_blocks
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@email_domain_blocks.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -63,10 +63,6 @@ class Api::V1::Admin::IpBlocksController < Api::BaseController
|
||||||
params.permit(:ip, :severity, :comment, :expires_in)
|
params.permit(:ip, :severity, :comment, :expires_in)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_admin_ip_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
api_v1_admin_ip_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -75,12 +71,8 @@ class Api::V1::Admin::IpBlocksController < Api::BaseController
|
||||||
api_v1_admin_ip_blocks_url(pagination_params(min_id: pagination_since_id)) unless @ip_blocks.empty?
|
api_v1_admin_ip_blocks_url(pagination_params(min_id: pagination_since_id)) unless @ip_blocks.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@ip_blocks.last.id
|
@ip_blocks
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@ip_blocks.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -35,6 +35,7 @@ class Api::V1::Admin::ReportsController < Api::BaseController
|
||||||
def update
|
def update
|
||||||
authorize @report, :update?
|
authorize @report, :update?
|
||||||
@report.update!(report_params)
|
@report.update!(report_params)
|
||||||
|
log_action :update, @report
|
||||||
render json: @report, serializer: REST::Admin::ReportSerializer
|
render json: @report, serializer: REST::Admin::ReportSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -88,10 +89,6 @@ class Api::V1::Admin::ReportsController < Api::BaseController
|
||||||
params.permit(*FILTER_PARAMS)
|
params.permit(*FILTER_PARAMS)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_admin_reports_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
api_v1_admin_reports_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -100,12 +97,8 @@ class Api::V1::Admin::ReportsController < Api::BaseController
|
||||||
api_v1_admin_reports_url(pagination_params(min_id: pagination_since_id)) unless @reports.empty?
|
api_v1_admin_reports_url(pagination_params(min_id: pagination_since_id)) unless @reports.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@reports.last.id
|
@reports
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@reports.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -44,10 +44,6 @@ class Api::V1::Admin::TagsController < Api::BaseController
|
||||||
params.permit(:display_name, :trendable, :usable, :listable)
|
params.permit(:display_name, :trendable, :usable, :listable)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_admin_tags_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
api_v1_admin_tags_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -56,12 +52,8 @@ class Api::V1::Admin::TagsController < Api::BaseController
|
||||||
api_v1_admin_tags_url(pagination_params(min_id: pagination_since_id)) unless @tags.empty?
|
api_v1_admin_tags_url(pagination_params(min_id: pagination_since_id)) unless @tags.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@tags.last.id
|
@tags
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@tags.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -42,10 +42,6 @@ class Api::V1::Admin::Trends::Links::PreviewCardProvidersController < Api::BaseC
|
||||||
@providers = PreviewCardProvider.all.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
@providers = PreviewCardProvider.all.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_admin_trends_links_preview_card_providers_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
api_v1_admin_trends_links_preview_card_providers_url(pagination_params(max_id: pagination_max_id)) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -54,12 +50,8 @@ class Api::V1::Admin::Trends::Links::PreviewCardProvidersController < Api::BaseC
|
||||||
api_v1_admin_trends_links_preview_card_providers_url(pagination_params(min_id: pagination_since_id)) unless @providers.empty?
|
api_v1_admin_trends_links_preview_card_providers_url(pagination_params(min_id: pagination_since_id)) unless @providers.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@providers.last.id
|
@providers
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@providers.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -28,10 +28,6 @@ class Api::V1::BlocksController < Api::BaseController
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_blocks_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_blocks_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -40,12 +36,8 @@ class Api::V1::BlocksController < Api::BaseController
|
||||||
api_v1_blocks_url pagination_params(since_id: pagination_since_id) unless paginated_blocks.empty?
|
api_v1_blocks_url pagination_params(since_id: pagination_since_id) unless paginated_blocks.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
paginated_blocks.last.id
|
paginated_blocks
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
paginated_blocks.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -31,10 +31,6 @@ class Api::V1::BookmarksController < Api::BaseController
|
||||||
current_account.bookmarks
|
current_account.bookmarks
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_bookmarks_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_bookmarks_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -43,12 +39,8 @@ class Api::V1::BookmarksController < Api::BaseController
|
||||||
api_v1_bookmarks_url pagination_params(min_id: pagination_since_id) unless results.empty?
|
api_v1_bookmarks_url pagination_params(min_id: pagination_since_id) unless results.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
results.last.id
|
results
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
results.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -53,10 +53,6 @@ class Api::V1::ConversationsController < Api::BaseController
|
||||||
.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_conversations_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_conversations_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,10 +29,6 @@ class Api::V1::Crypto::EncryptedMessagesController < Api::BaseController
|
||||||
@encrypted_messages = @current_device.encrypted_messages.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
@encrypted_messages = @current_device.encrypted_messages.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_crypto_encrypted_messages_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_crypto_encrypted_messages_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -41,12 +37,8 @@ class Api::V1::Crypto::EncryptedMessagesController < Api::BaseController
|
||||||
api_v1_crypto_encrypted_messages_url pagination_params(min_id: pagination_since_id) unless @encrypted_messages.empty?
|
api_v1_crypto_encrypted_messages_url pagination_params(min_id: pagination_since_id) unless @encrypted_messages.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@encrypted_messages.last.id
|
@encrypted_messages
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@encrypted_messages.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -38,10 +38,6 @@ class Api::V1::DomainBlocksController < Api::BaseController
|
||||||
current_account.domain_blocks
|
current_account.domain_blocks
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_domain_blocks_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_domain_blocks_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -50,12 +46,8 @@ class Api::V1::DomainBlocksController < Api::BaseController
|
||||||
api_v1_domain_blocks_url pagination_params(since_id: pagination_since_id) unless @blocks.empty?
|
api_v1_domain_blocks_url pagination_params(since_id: pagination_since_id) unless @blocks.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@blocks.last.id
|
@blocks
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@blocks.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -28,10 +28,6 @@ class Api::V1::EndorsementsController < Api::BaseController
|
||||||
current_account.endorsed_accounts.includes(:account_stat, :user).without_suspended
|
current_account.endorsed_accounts.includes(:account_stat, :user).without_suspended
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
return if unlimited?
|
return if unlimited?
|
||||||
|
|
||||||
|
@ -44,12 +40,8 @@ class Api::V1::EndorsementsController < Api::BaseController
|
||||||
api_v1_endorsements_url pagination_params(since_id: pagination_since_id) unless @accounts.empty?
|
api_v1_endorsements_url pagination_params(since_id: pagination_since_id) unless @accounts.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@accounts.last.id
|
@accounts
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@accounts.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -31,10 +31,6 @@ class Api::V1::FavouritesController < Api::BaseController
|
||||||
current_account.favourites
|
current_account.favourites
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_favourites_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_favourites_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -43,12 +39,8 @@ class Api::V1::FavouritesController < Api::BaseController
|
||||||
api_v1_favourites_url pagination_params(min_id: pagination_since_id) unless results.empty?
|
api_v1_favourites_url pagination_params(min_id: pagination_since_id) unless results.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
results.last.id
|
results
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
results.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -12,6 +12,10 @@ class Api::V1::FeaturedTags::SuggestionsController < Api::BaseController
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_recently_used_tags
|
def set_recently_used_tags
|
||||||
@recently_used_tags = Tag.recently_used(current_account).where.not(id: current_account.featured_tags).limit(10)
|
@recently_used_tags = Tag.recently_used(current_account).where.not(id: featured_tag_ids).limit(10)
|
||||||
|
end
|
||||||
|
|
||||||
|
def featured_tag_ids
|
||||||
|
current_account.featured_tags.pluck(:tag_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,10 +48,6 @@ class Api::V1::FollowRequestsController < Api::BaseController
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_follow_requests_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_follow_requests_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,10 +22,6 @@ class Api::V1::FollowedTagsController < Api::BaseController
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_followed_tags_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_followed_tags_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -34,12 +30,8 @@ class Api::V1::FollowedTagsController < Api::BaseController
|
||||||
api_v1_followed_tags_url pagination_params(since_id: pagination_since_id) unless @results.empty?
|
api_v1_followed_tags_url pagination_params(since_id: pagination_since_id) unless @results.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@results.last.id
|
@results
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@results.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -55,10 +55,6 @@ class Api::V1::Lists::AccountsController < Api::BaseController
|
||||||
params.permit(account_ids: [])
|
params.permit(account_ids: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
return if unlimited?
|
return if unlimited?
|
||||||
|
|
||||||
|
@ -71,12 +67,8 @@ class Api::V1::Lists::AccountsController < Api::BaseController
|
||||||
api_v1_list_accounts_url pagination_params(since_id: pagination_since_id) unless @accounts.empty?
|
api_v1_list_accounts_url pagination_params(since_id: pagination_since_id) unless @accounts.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@accounts.last.id
|
@accounts
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@accounts.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
|
@ -28,10 +28,6 @@ class Api::V1::MutesController < Api::BaseController
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_mutes_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_mutes_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -40,12 +36,8 @@ class Api::V1::MutesController < Api::BaseController
|
||||||
api_v1_mutes_url pagination_params(since_id: pagination_since_id) unless paginated_mutes.empty?
|
api_v1_mutes_url pagination_params(since_id: pagination_since_id) unless paginated_mutes.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
paginated_mutes.last.id
|
paginated_mutes
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
paginated_mutes.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def records_continue?
|
def records_continue?
|
||||||
|
|
37
app/controllers/api/v1/notifications/policies_controller.rb
Normal file
37
app/controllers/api/v1/notifications/policies_controller.rb
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Notifications::PoliciesController < Api::BaseController
|
||||||
|
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, only: :show
|
||||||
|
before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: :update
|
||||||
|
|
||||||
|
before_action :require_user!
|
||||||
|
before_action :set_policy
|
||||||
|
|
||||||
|
def show
|
||||||
|
render json: @policy, serializer: REST::NotificationPolicySerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@policy.update!(resource_params)
|
||||||
|
render json: @policy, serializer: REST::NotificationPolicySerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_policy
|
||||||
|
@policy = NotificationPolicy.find_or_initialize_by(account: current_account)
|
||||||
|
|
||||||
|
with_read_replica do
|
||||||
|
@policy.summarize!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_params
|
||||||
|
params.permit(
|
||||||
|
:filter_not_following,
|
||||||
|
:filter_not_followers,
|
||||||
|
:filter_new_accounts,
|
||||||
|
:filter_private_mentions
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
75
app/controllers/api/v1/notifications/requests_controller.rb
Normal file
75
app/controllers/api/v1/notifications/requests_controller.rb
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Notifications::RequestsController < Api::BaseController
|
||||||
|
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, only: :index
|
||||||
|
before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, except: :index
|
||||||
|
|
||||||
|
before_action :require_user!
|
||||||
|
before_action :set_request, except: :index
|
||||||
|
|
||||||
|
after_action :insert_pagination_headers, only: :index
|
||||||
|
|
||||||
|
def index
|
||||||
|
with_read_replica do
|
||||||
|
@requests = load_requests
|
||||||
|
@relationships = relationships
|
||||||
|
end
|
||||||
|
|
||||||
|
render json: @requests, each_serializer: REST::NotificationRequestSerializer, relationships: @relationships
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render json: @request, serializer: REST::NotificationRequestSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def accept
|
||||||
|
AcceptNotificationRequestService.new.call(@request)
|
||||||
|
render_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
def dismiss
|
||||||
|
@request.update!(dismissed: true)
|
||||||
|
render_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_requests
|
||||||
|
requests = NotificationRequest.where(account: current_account).where(dismissed: truthy_param?(:dismissed) || false).includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id(
|
||||||
|
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
||||||
|
params_slice(:max_id, :since_id, :min_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
NotificationRequest.preload_cache_collection(requests) do |statuses|
|
||||||
|
cache_collection(statuses, Status)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def relationships
|
||||||
|
StatusRelationshipsPresenter.new(@requests.map(&:last_status), current_user&.account_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_request
|
||||||
|
@request = NotificationRequest.where(account: current_account).find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_path
|
||||||
|
api_v1_notifications_requests_url pagination_params(max_id: pagination_max_id) unless @requests.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def prev_path
|
||||||
|
api_v1_notifications_requests_url pagination_params(min_id: pagination_since_id) unless @requests.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_max_id
|
||||||
|
@requests.last.id
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_since_id
|
||||||
|
@requests.first.id
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_params(core_params)
|
||||||
|
params.slice(:dismissed).permit(:dismissed).merge(core_params)
|
||||||
|
end
|
||||||
|
end
|
|
@ -58,7 +58,8 @@ class Api::V1::NotificationsController < Api::BaseController
|
||||||
current_account.notifications.without_suspended.browserable(
|
current_account.notifications.without_suspended.browserable(
|
||||||
types: Array(browserable_params[:types]),
|
types: Array(browserable_params[:types]),
|
||||||
exclude_types: Array(browserable_params[:exclude_types]),
|
exclude_types: Array(browserable_params[:exclude_types]),
|
||||||
from_account_id: browserable_params[:account_id]
|
from_account_id: browserable_params[:account_id],
|
||||||
|
include_filtered: truthy_param?(:include_filtered)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -66,10 +67,6 @@ class Api::V1::NotificationsController < Api::BaseController
|
||||||
@notifications.reject { |notification| notification.target_status.nil? }.map(&:target_status)
|
@notifications.reject { |notification| notification.target_status.nil? }.map(&:target_status)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_notifications_url pagination_params(max_id: pagination_max_id) unless @notifications.empty?
|
api_v1_notifications_url pagination_params(max_id: pagination_max_id) unless @notifications.empty?
|
||||||
end
|
end
|
||||||
|
@ -78,19 +75,15 @@ class Api::V1::NotificationsController < Api::BaseController
|
||||||
api_v1_notifications_url pagination_params(min_id: pagination_since_id) unless @notifications.empty?
|
api_v1_notifications_url pagination_params(min_id: pagination_since_id) unless @notifications.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@notifications.last.id
|
@notifications
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@notifications.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def browserable_params
|
def browserable_params
|
||||||
params.permit(:account_id, types: [], exclude_types: [])
|
params.permit(:account_id, :include_filtered, types: [], exclude_types: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_params(core_params)
|
def pagination_params(core_params)
|
||||||
params.slice(:limit, :account_id, :types, :exclude_types).permit(:limit, :account_id, types: [], exclude_types: []).merge(core_params)
|
params.slice(:limit, :account_id, :types, :exclude_types, :include_filtered).permit(:limit, :account_id, :include_filtered, types: [], exclude_types: []).merge(core_params)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -47,10 +47,6 @@ class Api::V1::ScheduledStatusesController < Api::BaseController
|
||||||
params.slice(:limit).permit(:limit).merge(core_params)
|
params.slice(:limit).permit(:limit).merge(core_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_scheduled_statuses_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_scheduled_statuses_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
@ -63,11 +59,7 @@ class Api::V1::ScheduledStatusesController < Api::BaseController
|
||||||
@statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)
|
@statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_max_id
|
def pagination_collection
|
||||||
@statuses.last.id
|
@statuses
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@statuses.first.id
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,10 +34,6 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::V1::Statuses::Bas
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_status_favourited_by_index_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_status_favourited_by_index_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,10 +30,6 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::V1::Statuses::Base
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_path
|
def next_path
|
||||||
api_v1_status_reblogged_by_index_url pagination_params(max_id: pagination_max_id) if records_continue?
|
api_v1_status_reblogged_by_index_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||||
end
|
end
|
||||||
|
|
|
@ -72,13 +72,9 @@ class Api::V1::StatusesController < Api::BaseController
|
||||||
with_rate_limit: true
|
with_rate_limit: true
|
||||||
)
|
)
|
||||||
|
|
||||||
render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer
|
render json: @status, serializer: serializer_for_status
|
||||||
rescue PostStatusService::UnexpectedMentionsError => e
|
rescue PostStatusService::UnexpectedMentionsError => e
|
||||||
unexpected_accounts = ActiveModel::Serializer::CollectionSerializer.new(
|
render json: unexpected_accounts_error_json(e), status: 422
|
||||||
e.accounts,
|
|
||||||
serializer: REST::AccountSerializer
|
|
||||||
)
|
|
||||||
render json: { error: e.message, unexpected_accounts: unexpected_accounts }, status: 422
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
@ -158,6 +154,21 @@ class Api::V1::StatusesController < Api::BaseController
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def serializer_for_status
|
||||||
|
@status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def unexpected_accounts_error_json(error)
|
||||||
|
{
|
||||||
|
error: error.message,
|
||||||
|
unexpected_accounts: serialized_accounts(error.accounts),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialized_accounts(accounts)
|
||||||
|
ActiveModel::Serializer::CollectionSerializer.new(accounts, serializer: REST::AccountSerializer)
|
||||||
|
end
|
||||||
|
|
||||||
def pagination_params(core_params)
|
def pagination_params(core_params)
|
||||||
params.slice(:limit).permit(:limit).merge(core_params)
|
params.slice(:limit).permit(:limit).merge(core_params)
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,16 +5,8 @@ class Api::V1::Timelines::BaseController < Api::BaseController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def insert_pagination_headers
|
def pagination_collection
|
||||||
set_pagination_headers(next_path, prev_path)
|
@statuses
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_max_id
|
|
||||||
@statuses.last.id
|
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_since_id
|
|
||||||
@statuses.first.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def next_path_params
|
def next_path_params
|
||||||
|
|
|
@ -34,10 +34,6 @@ class Api::V1::Trends::LinksController < Api::BaseController
|
||||||
scope
|
scope
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_params(core_params)
|
def pagination_params(core_params)
|
||||||
params.slice(:limit).permit(:limit).merge(core_params)
|
params.slice(:limit).permit(:limit).merge(core_params)
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,10 +33,6 @@ class Api::V1::Trends::StatusesController < Api::BaseController
|
||||||
scope
|
scope
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_params(core_params)
|
def pagination_params(core_params)
|
||||||
params.slice(:limit).permit(:limit).merge(core_params)
|
params.slice(:limit).permit(:limit).merge(core_params)
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,10 +30,6 @@ class Api::V1::Trends::TagsController < Api::BaseController
|
||||||
Trends.tags.query.allowed
|
Trends.tags.query.allowed
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
|
||||||
set_pagination_headers(next_path, prev_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def pagination_params(core_params)
|
def pagination_params(core_params)
|
||||||
params.slice(:limit).permit(:limit).merge(core_params)
|
params.slice(:limit).permit(:limit).merge(core_params)
|
||||||
end
|
end
|
||||||
|
|
|
@ -131,7 +131,7 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def single_user_mode?
|
def single_user_mode?
|
||||||
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.where('id > 0').exists?
|
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.without_internal.exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
def use_seamless_external_login?
|
def use_seamless_external_login?
|
||||||
|
@ -180,7 +180,7 @@ class ApplicationController < ActionController::Base
|
||||||
use_pack 'error'
|
use_pack 'error'
|
||||||
render 'errors/self_destruct', layout: 'auth', status: 410, formats: [:html]
|
render 'errors/self_destruct', layout: 'auth', status: 410, formats: [:html]
|
||||||
end
|
end
|
||||||
format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[410] }, status: code }
|
format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[410] }, status: 410 }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,9 @@ class Auth::SessionsController < Devise::SessionsController
|
||||||
)
|
)
|
||||||
|
|
||||||
# Only send a notification email every hour at most
|
# Only send a notification email every hour at most
|
||||||
return if redis.set("2fa_failure_notification:#{user.id}", '1', ex: 1.hour, get: true).present?
|
return if redis.get("2fa_failure_notification:#{user.id}").present?
|
||||||
|
|
||||||
|
redis.set("2fa_failure_notification:#{user.id}", '1', ex: 1.hour)
|
||||||
|
|
||||||
UserMailer.failed_2fa(user, request.remote_ip, request.user_agent, Time.now.utc).deliver_later!
|
UserMailer.failed_2fa(user, request.remote_ip, request.user_agent, Time.now.utc).deliver_later!
|
||||||
end
|
end
|
||||||
|
|
52
app/controllers/concerns/api/error_handling.rb
Normal file
52
app/controllers/concerns/api/error_handling.rb
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api::ErrorHandling
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
|
||||||
|
render json: { error: e.to_s }, status: 422
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_from ActiveRecord::RecordNotUnique do
|
||||||
|
render json: { error: 'Duplicate record' }, status: 422
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_from Date::Error do
|
||||||
|
render json: { error: 'Invalid date supplied' }, status: 422
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_from ActiveRecord::RecordNotFound do
|
||||||
|
render json: { error: 'Record not found' }, status: 404
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do
|
||||||
|
render json: { error: 'Remote data could not be fetched' }, status: 503
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_from OpenSSL::SSL::SSLError do
|
||||||
|
render json: { error: 'Remote SSL certificate could not be verified' }, status: 503
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_from Mastodon::NotPermittedError do
|
||||||
|
render json: { error: 'This action is not allowed' }, status: 403
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_from Seahorse::Client::NetworkingError do |e|
|
||||||
|
Rails.logger.warn "Storage server error: #{e}"
|
||||||
|
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight do
|
||||||
|
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_from Mastodon::RateLimitExceededError do
|
||||||
|
render json: { error: I18n.t('errors.429') }, status: 429
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_from ActionController::ParameterMissing, Mastodon::InvalidParameterError do |e|
|
||||||
|
render json: { error: e.to_s }, status: 400
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,39 +12,6 @@ module SignatureVerification
|
||||||
|
|
||||||
class SignatureVerificationError < StandardError; end
|
class SignatureVerificationError < StandardError; end
|
||||||
|
|
||||||
class SignatureParamsParser < Parslet::Parser
|
|
||||||
rule(:token) { match("[0-9a-zA-Z!#$%&'*+.^_`|~-]").repeat(1).as(:token) }
|
|
||||||
rule(:quoted_string) { str('"') >> (qdtext | quoted_pair).repeat.as(:quoted_string) >> str('"') }
|
|
||||||
# qdtext and quoted_pair are not exactly according to spec but meh
|
|
||||||
rule(:qdtext) { match('[^\\\\"]') }
|
|
||||||
rule(:quoted_pair) { str('\\') >> any }
|
|
||||||
rule(:bws) { match('\s').repeat }
|
|
||||||
rule(:param) { (token.as(:key) >> bws >> str('=') >> bws >> (token | quoted_string).as(:value)).as(:param) }
|
|
||||||
rule(:comma) { bws >> str(',') >> bws }
|
|
||||||
# Old versions of node-http-signature add an incorrect "Signature " prefix to the header
|
|
||||||
rule(:buggy_prefix) { str('Signature ') }
|
|
||||||
rule(:params) { buggy_prefix.maybe >> (param >> (comma >> param).repeat).as(:params) }
|
|
||||||
root(:params)
|
|
||||||
end
|
|
||||||
|
|
||||||
class SignatureParamsTransformer < Parslet::Transform
|
|
||||||
rule(params: subtree(:param)) do
|
|
||||||
(param.is_a?(Array) ? param : [param]).each_with_object({}) { |(key, value), hash| hash[key] = value }
|
|
||||||
end
|
|
||||||
|
|
||||||
rule(param: { key: simple(:key), value: simple(:val) }) do
|
|
||||||
[key, val]
|
|
||||||
end
|
|
||||||
|
|
||||||
rule(quoted_string: simple(:string)) do
|
|
||||||
string.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
rule(token: simple(:string)) do
|
|
||||||
string.to_s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def require_account_signature!
|
def require_account_signature!
|
||||||
render json: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_account
|
render json: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_account
|
||||||
end
|
end
|
||||||
|
@ -135,12 +102,8 @@ module SignatureVerification
|
||||||
end
|
end
|
||||||
|
|
||||||
def signature_params
|
def signature_params
|
||||||
@signature_params ||= begin
|
@signature_params ||= SignatureParser.parse(request.headers['Signature'])
|
||||||
raw_signature = request.headers['Signature']
|
rescue SignatureParser::ParsingError
|
||||||
tree = SignatureParamsParser.new.parse(raw_signature)
|
|
||||||
SignatureParamsTransformer.new.apply(tree)
|
|
||||||
end
|
|
||||||
rescue Parslet::ParseFailed
|
|
||||||
raise SignatureVerificationError, 'Error parsing signature parameters'
|
raise SignatureVerificationError, 'Error parsing signature parameters'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,6 @@ class CustomCssController < ActionController::Base # rubocop:disable Rails/Appli
|
||||||
helper_method :custom_css_styles
|
helper_method :custom_css_styles
|
||||||
|
|
||||||
def set_user_roles
|
def set_user_roles
|
||||||
@user_roles = UserRole.where(highlighted: true).where.not(color: [nil, ''])
|
@user_roles = UserRole.providing_styles
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,8 @@ class InstanceActorsController < ActivityPub::BaseController
|
||||||
serialization_scope nil
|
serialization_scope nil
|
||||||
|
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
|
||||||
|
skip_before_action :authenticate_user! # From `AccountOwnedConcern`
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
skip_before_action :update_user_sign_in
|
skip_before_action :update_user_sign_in
|
||||||
|
|
||||||
|
@ -16,6 +18,11 @@ class InstanceActorsController < ActivityPub::BaseController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
# Skips various `before_action` from `AccountOwnedConcern`
|
||||||
|
def account_required?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
def set_account
|
def set_account
|
||||||
@account = Account.representative
|
@account = Account.representative
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,27 +1,26 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class IntentsController < ApplicationController
|
class IntentsController < ApplicationController
|
||||||
before_action :check_uri
|
EXPECTED_SCHEME = 'web+mastodon'
|
||||||
|
|
||||||
|
before_action :handle_invalid_uri, unless: :valid_uri?
|
||||||
rescue_from Addressable::URI::InvalidURIError, with: :handle_invalid_uri
|
rescue_from Addressable::URI::InvalidURIError, with: :handle_invalid_uri
|
||||||
|
|
||||||
def show
|
def show
|
||||||
if uri.scheme == 'web+mastodon'
|
|
||||||
case uri.host
|
case uri.host
|
||||||
when 'follow'
|
when 'follow'
|
||||||
return redirect_to authorize_interaction_path(uri: uri.query_values['uri'].delete_prefix('acct:'))
|
redirect_to authorize_interaction_path(uri: uri.query_values['uri'].delete_prefix('acct:'))
|
||||||
when 'share'
|
when 'share'
|
||||||
return redirect_to share_path(text: uri.query_values['text'])
|
redirect_to share_path(text: uri.query_values['text'])
|
||||||
|
else
|
||||||
|
handle_invalid_uri
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
not_found
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def check_uri
|
def valid_uri?
|
||||||
not_found if uri.blank?
|
uri.present? && uri.scheme == EXPECTED_SCHEME
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_invalid_uri
|
def handle_invalid_uri
|
||||||
|
|
61
app/controllers/severed_relationships_controller.rb
Normal file
61
app/controllers/severed_relationships_controller.rb
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SeveredRelationshipsController < ApplicationController
|
||||||
|
layout 'admin'
|
||||||
|
|
||||||
|
before_action :authenticate_user!
|
||||||
|
before_action :set_body_classes
|
||||||
|
before_action :set_cache_headers
|
||||||
|
|
||||||
|
before_action :set_event, only: [:following, :followers]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@events = AccountRelationshipSeveranceEvent.where(account: current_account)
|
||||||
|
end
|
||||||
|
|
||||||
|
def following
|
||||||
|
respond_to do |format|
|
||||||
|
format.csv { send_data following_data, filename: "following-#{@event.target_name}-#{@event.created_at.to_date.iso8601}.csv" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def followers
|
||||||
|
respond_to do |format|
|
||||||
|
format.csv { send_data followers_data, filename: "followers-#{@event.target_name}-#{@event.created_at.to_date.iso8601}.csv" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_event
|
||||||
|
@event = AccountRelationshipSeveranceEvent.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def following_data
|
||||||
|
CSV.generate(headers: ['Account address', 'Show boosts', 'Notify on new posts', 'Languages'], write_headers: true) do |csv|
|
||||||
|
@event.severed_relationships.active.about_local_account(current_account).includes(:remote_account).reorder(id: :desc).each do |follow|
|
||||||
|
csv << [acct(follow.target_account), follow.show_reblogs, follow.notify, follow.languages&.join(', ')]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def followers_data
|
||||||
|
CSV.generate(headers: ['Account address'], write_headers: true) do |csv|
|
||||||
|
@event.severed_relationships.passive.about_local_account(current_account).includes(:remote_account).reorder(id: :desc).each do |follow|
|
||||||
|
csv << [acct(follow.account)]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def acct(account)
|
||||||
|
account.local? ? account.local_username_and_domain : account.acct
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_body_classes
|
||||||
|
@body_classes = 'admin'
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_cache_headers
|
||||||
|
response.cache_control.replace(private: true, no_store: true)
|
||||||
|
end
|
||||||
|
end
|
|
@ -28,14 +28,6 @@ module ApplicationHelper
|
||||||
number_to_human(number, **options)
|
number_to_human(number, **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def active_nav_class(*paths)
|
|
||||||
paths.any? { |path| current_page?(path) } ? 'active' : ''
|
|
||||||
end
|
|
||||||
|
|
||||||
def show_landing_strip?
|
|
||||||
!user_signed_in? && !single_user_mode?
|
|
||||||
end
|
|
||||||
|
|
||||||
def open_registrations?
|
def open_registrations?
|
||||||
Setting.registrations_mode == 'open'
|
Setting.registrations_mode == 'open'
|
||||||
end
|
end
|
||||||
|
@ -122,7 +114,7 @@ module ApplicationHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_icon
|
def check_icon
|
||||||
content_tag(:svg, tag.path('fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z'), xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 20 20', fill: 'currentColor')
|
inline_svg_tag 'check.svg'
|
||||||
end
|
end
|
||||||
|
|
||||||
def visibility_icon(status)
|
def visibility_icon(status)
|
||||||
|
@ -214,7 +206,7 @@ module ApplicationHelper
|
||||||
state_params[:moved_to_account] = current_account.moved_to_account
|
state_params[:moved_to_account] = current_account.moved_to_account
|
||||||
end
|
end
|
||||||
|
|
||||||
state_params[:owner] = Account.local.without_suspended.where('id > 0').first if single_user_mode?
|
state_params[:owner] = Account.local.without_suspended.without_internal.first if single_user_mode?
|
||||||
|
|
||||||
json = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(state_params), serializer: InitialStateSerializer).to_json
|
json = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(state_params), serializer: InitialStateSerializer).to_json
|
||||||
# rubocop:disable Rails/OutputSafety
|
# rubocop:disable Rails/OutputSafety
|
||||||
|
|
|
@ -21,15 +21,4 @@ module BrandingHelper
|
||||||
def render_logo
|
def render_logo
|
||||||
image_pack_tag('logo.svg', alt: 'Mastodon', class: 'logo logo--icon')
|
image_pack_tag('logo.svg', alt: 'Mastodon', class: 'logo logo--icon')
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_symbol(version = :icon)
|
|
||||||
path = case version
|
|
||||||
when :icon
|
|
||||||
'logo-symbol-icon.svg'
|
|
||||||
when :wordmark
|
|
||||||
'logo-symbol-wordmark.svg'
|
|
||||||
end
|
|
||||||
|
|
||||||
render(file: Rails.root.join('app', 'javascript', 'images', path)).html_safe # rubocop:disable Rails/OutputSafety
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,12 +25,21 @@ module ContextHelper
|
||||||
memorial: { 'toot' => 'http://joinmastodon.org/ns#', 'memorial' => 'toot:memorial' },
|
memorial: { 'toot' => 'http://joinmastodon.org/ns#', 'memorial' => 'toot:memorial' },
|
||||||
voters_count: { 'toot' => 'http://joinmastodon.org/ns#', 'votersCount' => 'toot:votersCount' },
|
voters_count: { 'toot' => 'http://joinmastodon.org/ns#', 'votersCount' => 'toot:votersCount' },
|
||||||
olm: {
|
olm: {
|
||||||
'toot' => 'http://joinmastodon.org/ns#', 'Device' => 'toot:Device', 'Ed25519Signature' => 'toot:Ed25519Signature', 'Ed25519Key' => 'toot:Ed25519Key', 'Curve25519Key' => 'toot:Curve25519Key', 'EncryptedMessage' => 'toot:EncryptedMessage', 'publicKeyBase64' => 'toot:publicKeyBase64', 'deviceId' => 'toot:deviceId',
|
'toot' => 'http://joinmastodon.org/ns#',
|
||||||
|
'Device' => 'toot:Device',
|
||||||
|
'Ed25519Signature' => 'toot:Ed25519Signature',
|
||||||
|
'Ed25519Key' => 'toot:Ed25519Key',
|
||||||
|
'Curve25519Key' => 'toot:Curve25519Key',
|
||||||
|
'EncryptedMessage' => 'toot:EncryptedMessage',
|
||||||
|
'publicKeyBase64' => 'toot:publicKeyBase64',
|
||||||
|
'deviceId' => 'toot:deviceId',
|
||||||
'claim' => { '@type' => '@id', '@id' => 'toot:claim' },
|
'claim' => { '@type' => '@id', '@id' => 'toot:claim' },
|
||||||
'fingerprintKey' => { '@type' => '@id', '@id' => 'toot:fingerprintKey' },
|
'fingerprintKey' => { '@type' => '@id', '@id' => 'toot:fingerprintKey' },
|
||||||
'identityKey' => { '@type' => '@id', '@id' => 'toot:identityKey' },
|
'identityKey' => { '@type' => '@id', '@id' => 'toot:identityKey' },
|
||||||
'devices' => { '@type' => '@id', '@id' => 'toot:devices' },
|
'devices' => { '@type' => '@id', '@id' => 'toot:devices' },
|
||||||
'messageFranking' => 'toot:messageFranking', 'messageType' => 'toot:messageType', 'cipherText' => 'toot:cipherText'
|
'messageFranking' => 'toot:messageFranking',
|
||||||
|
'messageType' => 'toot:messageType',
|
||||||
|
'cipherText' => 'toot:cipherText',
|
||||||
},
|
},
|
||||||
suspended: { 'toot' => 'http://joinmastodon.org/ns#', 'suspended' => 'toot:suspended' },
|
suspended: { 'toot' => 'http://joinmastodon.org/ns#', 'suspended' => 'toot:suspended' },
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
|
@ -109,6 +109,7 @@ module LanguagesHelper
|
||||||
mn: ['Mongolian', 'Монгол хэл'].freeze,
|
mn: ['Mongolian', 'Монгол хэл'].freeze,
|
||||||
mr: ['Marathi', 'मराठी'].freeze,
|
mr: ['Marathi', 'मराठी'].freeze,
|
||||||
ms: ['Malay', 'Bahasa Melayu'].freeze,
|
ms: ['Malay', 'Bahasa Melayu'].freeze,
|
||||||
|
'ms-Arab': ['Jawi Malay', 'بهاس ملايو'].freeze,
|
||||||
mt: ['Maltese', 'Malti'].freeze,
|
mt: ['Maltese', 'Malti'].freeze,
|
||||||
my: ['Burmese', 'ဗမာစာ'].freeze,
|
my: ['Burmese', 'ဗမာစာ'].freeze,
|
||||||
na: ['Nauru', 'Ekakairũ Naoero'].freeze,
|
na: ['Nauru', 'Ekakairũ Naoero'].freeze,
|
||||||
|
@ -127,7 +128,7 @@ module LanguagesHelper
|
||||||
om: ['Oromo', 'Afaan Oromoo'].freeze,
|
om: ['Oromo', 'Afaan Oromoo'].freeze,
|
||||||
or: ['Oriya', 'ଓଡ଼ିଆ'].freeze,
|
or: ['Oriya', 'ଓଡ଼ିଆ'].freeze,
|
||||||
os: ['Ossetian', 'ирон æвзаг'].freeze,
|
os: ['Ossetian', 'ирон æвзаг'].freeze,
|
||||||
pa: ['Panjabi', 'ਪੰਜਾਬੀ'].freeze,
|
pa: ['Punjabi', 'ਪੰਜਾਬੀ'].freeze,
|
||||||
pi: ['Pāli', 'पाऴि'].freeze,
|
pi: ['Pāli', 'पाऴि'].freeze,
|
||||||
pl: ['Polish', 'Polski'].freeze,
|
pl: ['Polish', 'Polski'].freeze,
|
||||||
ps: ['Pashto', 'پښتو'].freeze,
|
ps: ['Pashto', 'پښتو'].freeze,
|
||||||
|
@ -191,15 +192,20 @@ module LanguagesHelper
|
||||||
chr: ['Cherokee', 'ᏣᎳᎩ ᎦᏬᏂᎯᏍᏗ'].freeze,
|
chr: ['Cherokee', 'ᏣᎳᎩ ᎦᏬᏂᎯᏍᏗ'].freeze,
|
||||||
ckb: ['Sorani (Kurdish)', 'سۆرانی'].freeze,
|
ckb: ['Sorani (Kurdish)', 'سۆرانی'].freeze,
|
||||||
cnr: ['Montenegrin', 'crnogorski'].freeze,
|
cnr: ['Montenegrin', 'crnogorski'].freeze,
|
||||||
|
csb: ['Kashubian', 'Kaszëbsczi'].freeze,
|
||||||
jbo: ['Lojban', 'la .lojban.'].freeze,
|
jbo: ['Lojban', 'la .lojban.'].freeze,
|
||||||
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
||||||
ldn: ['Láadan', 'Láadan'].freeze,
|
ldn: ['Láadan', 'Láadan'].freeze,
|
||||||
lfn: ['Lingua Franca Nova', 'lingua franca nova'].freeze,
|
lfn: ['Lingua Franca Nova', 'lingua franca nova'].freeze,
|
||||||
|
moh: ['Mohawk', 'Kanienʼkéha'].freeze,
|
||||||
|
nds: ['Low German', 'Plattdüütsch'].freeze,
|
||||||
|
pdc: ['Pennsylvania Dutch', 'Pennsilfaani-Deitsch'].freeze,
|
||||||
sco: ['Scots', 'Scots'].freeze,
|
sco: ['Scots', 'Scots'].freeze,
|
||||||
sma: ['Southern Sami', 'Åarjelsaemien Gïele'].freeze,
|
sma: ['Southern Sami', 'Åarjelsaemien Gïele'].freeze,
|
||||||
smj: ['Lule Sami', 'Julevsámegiella'].freeze,
|
smj: ['Lule Sami', 'Julevsámegiella'].freeze,
|
||||||
szl: ['Silesian', 'ślůnsko godka'].freeze,
|
szl: ['Silesian', 'ślůnsko godka'].freeze,
|
||||||
tok: ['Toki Pona', 'toki pona'].freeze,
|
tok: ['Toki Pona', 'toki pona'].freeze,
|
||||||
|
vai: ['Vai', 'ꕙꔤ'].freeze,
|
||||||
xal: ['Kalmyk', 'Хальмг келн'].freeze,
|
xal: ['Kalmyk', 'Хальмг келн'].freeze,
|
||||||
zba: ['Balaibalan', 'باليبلن'].freeze,
|
zba: ['Balaibalan', 'باليبلن'].freeze,
|
||||||
zgh: ['Standard Moroccan Tamazight', 'ⵜⴰⵎⴰⵣⵉⵖⵜ'].freeze,
|
zgh: ['Standard Moroccan Tamazight', 'ⵜⴰⵎⴰⵣⵉⵖⵜ'].freeze,
|
||||||
|
|
|
@ -15,9 +15,20 @@ module ReactComponentHelper
|
||||||
div_tag_with_data(data)
|
div_tag_with_data(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def serialized_media_attachments(media_attachments)
|
||||||
|
media_attachments.map { |attachment| serialized_attachment(attachment) }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def div_tag_with_data(data)
|
def div_tag_with_data(data)
|
||||||
content_tag(:div, nil, data: data)
|
content_tag(:div, nil, data: data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def serialized_attachment(attachment)
|
||||||
|
ActiveModelSerializers::SerializableResource.new(
|
||||||
|
attachment,
|
||||||
|
serializer: REST::MediaAttachmentSerializer
|
||||||
|
).as_json
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,14 +4,6 @@ module StatusesHelper
|
||||||
EMBEDDED_CONTROLLER = 'statuses'
|
EMBEDDED_CONTROLLER = 'statuses'
|
||||||
EMBEDDED_ACTION = 'embed'
|
EMBEDDED_ACTION = 'embed'
|
||||||
|
|
||||||
def link_to_newer(url)
|
|
||||||
link_to t('statuses.show_newer'), url, class: 'load-more load-gap'
|
|
||||||
end
|
|
||||||
|
|
||||||
def link_to_older(url)
|
|
||||||
link_to t('statuses.show_older'), url, class: 'load-more load-gap'
|
|
||||||
end
|
|
||||||
|
|
||||||
def nothing_here(extra_classes = '')
|
def nothing_here(extra_classes = '')
|
||||||
content_tag(:div, class: "nothing-here #{extra_classes}") do
|
content_tag(:div, class: "nothing-here #{extra_classes}") do
|
||||||
t('accounts.nothing_here')
|
t('accounts.nothing_here')
|
||||||
|
|
|
@ -1,228 +0,0 @@
|
||||||
// This file will be loaded on admin pages, regardless of theme.
|
|
||||||
|
|
||||||
import 'packs/public-path';
|
|
||||||
import Rails from '@rails/ujs';
|
|
||||||
|
|
||||||
import ready from '../mastodon/ready';
|
|
||||||
|
|
||||||
const setAnnouncementEndsAttributes = (target) => {
|
|
||||||
const valid = target?.value && target?.validity?.valid;
|
|
||||||
const element = document.querySelector('input[type="datetime-local"]#announcement_ends_at');
|
|
||||||
if (valid) {
|
|
||||||
element.classList.remove('optional');
|
|
||||||
element.required = true;
|
|
||||||
element.min = target.value;
|
|
||||||
} else {
|
|
||||||
element.classList.add('optional');
|
|
||||||
element.removeAttribute('required');
|
|
||||||
element.removeAttribute('min');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Rails.delegate(document, 'input[type="datetime-local"]#announcement_starts_at', 'change', ({ target }) => {
|
|
||||||
setAnnouncementEndsAttributes(target);
|
|
||||||
});
|
|
||||||
|
|
||||||
const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]';
|
|
||||||
|
|
||||||
const showSelectAll = () => {
|
|
||||||
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
|
|
||||||
selectAllMatchingElement.classList.add('active');
|
|
||||||
};
|
|
||||||
|
|
||||||
const hideSelectAll = () => {
|
|
||||||
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
|
|
||||||
const hiddenField = document.querySelector('#select_all_matching');
|
|
||||||
const selectedMsg = document.querySelector('.batch-table__select-all .selected');
|
|
||||||
const notSelectedMsg = document.querySelector('.batch-table__select-all .not-selected');
|
|
||||||
|
|
||||||
selectAllMatchingElement.classList.remove('active');
|
|
||||||
selectedMsg.classList.remove('active');
|
|
||||||
notSelectedMsg.classList.add('active');
|
|
||||||
hiddenField.value = '0';
|
|
||||||
};
|
|
||||||
|
|
||||||
Rails.delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
|
|
||||||
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
|
|
||||||
|
|
||||||
[].forEach.call(document.querySelectorAll(batchCheckboxClassName), (content) => {
|
|
||||||
content.checked = target.checked;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (selectAllMatchingElement) {
|
|
||||||
if (target.checked) {
|
|
||||||
showSelectAll();
|
|
||||||
} else {
|
|
||||||
hideSelectAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Rails.delegate(document, '.batch-table__select-all button', 'click', () => {
|
|
||||||
const hiddenField = document.querySelector('#select_all_matching');
|
|
||||||
const active = hiddenField.value === '1';
|
|
||||||
const selectedMsg = document.querySelector('.batch-table__select-all .selected');
|
|
||||||
const notSelectedMsg = document.querySelector('.batch-table__select-all .not-selected');
|
|
||||||
|
|
||||||
if (active) {
|
|
||||||
hiddenField.value = '0';
|
|
||||||
selectedMsg.classList.remove('active');
|
|
||||||
notSelectedMsg.classList.add('active');
|
|
||||||
} else {
|
|
||||||
hiddenField.value = '1';
|
|
||||||
notSelectedMsg.classList.remove('active');
|
|
||||||
selectedMsg.classList.add('active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Rails.delegate(document, batchCheckboxClassName, 'change', () => {
|
|
||||||
const checkAllElement = document.querySelector('#batch_checkbox_all');
|
|
||||||
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
|
|
||||||
|
|
||||||
if (checkAllElement) {
|
|
||||||
checkAllElement.checked = [].every.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
|
||||||
checkAllElement.indeterminate = !checkAllElement.checked && [].some.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
|
||||||
|
|
||||||
if (selectAllMatchingElement) {
|
|
||||||
if (checkAllElement.checked) {
|
|
||||||
showSelectAll();
|
|
||||||
} else {
|
|
||||||
hideSelectAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Rails.delegate(document, '.media-spoiler-show-button', 'click', () => {
|
|
||||||
[].forEach.call(document.querySelectorAll('button.media-spoiler'), (element) => {
|
|
||||||
element.click();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Rails.delegate(document, '.media-spoiler-hide-button', 'click', () => {
|
|
||||||
[].forEach.call(document.querySelectorAll('.spoiler-button.spoiler-button--visible button'), (element) => {
|
|
||||||
element.click();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Rails.delegate(document, '.filter-subset--with-select select', 'change', ({ target }) => {
|
|
||||||
target.form.submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
const onDomainBlockSeverityChange = (target) => {
|
|
||||||
const rejectMediaDiv = document.querySelector('.input.with_label.domain_block_reject_media');
|
|
||||||
const rejectReportsDiv = document.querySelector('.input.with_label.domain_block_reject_reports');
|
|
||||||
|
|
||||||
if (rejectMediaDiv) {
|
|
||||||
rejectMediaDiv.style.display = (target.value === 'suspend') ? 'none' : 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rejectReportsDiv) {
|
|
||||||
rejectReportsDiv.style.display = (target.value === 'suspend') ? 'none' : 'block';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Rails.delegate(document, '#domain_block_severity', 'change', ({ target }) => onDomainBlockSeverityChange(target));
|
|
||||||
|
|
||||||
const onEnableBootstrapTimelineAccountsChange = (target) => {
|
|
||||||
const bootstrapTimelineAccountsField = document.querySelector('#form_admin_settings_bootstrap_timeline_accounts');
|
|
||||||
|
|
||||||
if (bootstrapTimelineAccountsField) {
|
|
||||||
bootstrapTimelineAccountsField.disabled = !target.checked;
|
|
||||||
if (target.checked) {
|
|
||||||
bootstrapTimelineAccountsField.parentElement.classList.remove('disabled');
|
|
||||||
bootstrapTimelineAccountsField.parentElement.parentElement.classList.remove('disabled');
|
|
||||||
} else {
|
|
||||||
bootstrapTimelineAccountsField.parentElement.classList.add('disabled');
|
|
||||||
bootstrapTimelineAccountsField.parentElement.parentElement.classList.add('disabled');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Rails.delegate(document, '#form_admin_settings_enable_bootstrap_timeline_accounts', 'change', ({ target }) => onEnableBootstrapTimelineAccountsChange(target));
|
|
||||||
|
|
||||||
const onChangeRegistrationMode = (target) => {
|
|
||||||
const enabled = target.value === 'approved';
|
|
||||||
|
|
||||||
[].forEach.call(document.querySelectorAll('#form_admin_settings_require_invite_text'), (input) => {
|
|
||||||
input.disabled = !enabled;
|
|
||||||
if (enabled) {
|
|
||||||
let element = input;
|
|
||||||
do {
|
|
||||||
element.classList.remove('disabled');
|
|
||||||
element = element.parentElement;
|
|
||||||
} while (element && !element.classList.contains('fields-group'));
|
|
||||||
} else {
|
|
||||||
let element = input;
|
|
||||||
do {
|
|
||||||
element.classList.add('disabled');
|
|
||||||
element = element.parentElement;
|
|
||||||
} while (element && !element.classList.contains('fields-group'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const convertUTCDateTimeToLocal = (value) => {
|
|
||||||
const date = new Date(value + 'Z');
|
|
||||||
const twoChars = (x) => (x.toString().padStart(2, '0'));
|
|
||||||
return `${date.getFullYear()}-${twoChars(date.getMonth()+1)}-${twoChars(date.getDate())}T${twoChars(date.getHours())}:${twoChars(date.getMinutes())}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const convertLocalDatetimeToUTC = (value) => {
|
|
||||||
const re = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})/;
|
|
||||||
const match = re.exec(value);
|
|
||||||
const date = new Date(match[1], match[2] - 1, match[3], match[4], match[5]);
|
|
||||||
const fullISO8601 = date.toISOString();
|
|
||||||
return fullISO8601.slice(0, fullISO8601.indexOf('T') + 6);
|
|
||||||
};
|
|
||||||
|
|
||||||
Rails.delegate(document, '#form_admin_settings_registrations_mode', 'change', ({ target }) => onChangeRegistrationMode(target));
|
|
||||||
|
|
||||||
ready(() => {
|
|
||||||
const domainBlockSeverityInput = document.getElementById('domain_block_severity');
|
|
||||||
if (domainBlockSeverityInput) onDomainBlockSeverityChange(domainBlockSeverityInput);
|
|
||||||
|
|
||||||
const enableBootstrapTimelineAccounts = document.getElementById('form_admin_settings_enable_bootstrap_timeline_accounts');
|
|
||||||
if (enableBootstrapTimelineAccounts) onEnableBootstrapTimelineAccountsChange(enableBootstrapTimelineAccounts);
|
|
||||||
|
|
||||||
const registrationMode = document.getElementById('form_admin_settings_registrations_mode');
|
|
||||||
if (registrationMode) onChangeRegistrationMode(registrationMode);
|
|
||||||
|
|
||||||
const checkAllElement = document.querySelector('#batch_checkbox_all');
|
|
||||||
if (checkAllElement) {
|
|
||||||
checkAllElement.checked = [].every.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
|
||||||
checkAllElement.indeterminate = !checkAllElement.checked && [].some.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.querySelector('a#add-instance-button')?.addEventListener('click', (e) => {
|
|
||||||
const domain = document.querySelector('input[type="text"]#by_domain')?.value;
|
|
||||||
|
|
||||||
if (domain) {
|
|
||||||
const url = new URL(event.target.href);
|
|
||||||
url.searchParams.set('_domain', domain);
|
|
||||||
e.target.href = url;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
[].forEach.call(document.querySelectorAll('input[type="datetime-local"]'), element => {
|
|
||||||
if (element.value) {
|
|
||||||
element.value = convertUTCDateTimeToLocal(element.value);
|
|
||||||
}
|
|
||||||
if (element.placeholder) {
|
|
||||||
element.placeholder = convertUTCDateTimeToLocal(element.placeholder);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Rails.delegate(document, 'form', 'submit', ({ target }) => {
|
|
||||||
[].forEach.call(target.querySelectorAll('input[type="datetime-local"]'), element => {
|
|
||||||
if (element.value && element.validity.valid) {
|
|
||||||
element.value = convertLocalDatetimeToUTC(element.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const announcementStartsAt = document.querySelector('input[type="datetime-local"]#announcement_starts_at');
|
|
||||||
if (announcementStartsAt) {
|
|
||||||
setAnnouncementEndsAttributes(announcementStartsAt);
|
|
||||||
}
|
|
||||||
});
|
|
340
app/javascript/core/admin.ts
Normal file
340
app/javascript/core/admin.ts
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
// This file will be loaded on admin pages, regardless of theme.
|
||||||
|
|
||||||
|
import 'packs/public-path';
|
||||||
|
|
||||||
|
import Rails from '@rails/ujs';
|
||||||
|
|
||||||
|
import ready from '../mastodon/ready';
|
||||||
|
|
||||||
|
const setAnnouncementEndsAttributes = (target: HTMLInputElement) => {
|
||||||
|
const valid = target.value && target.validity.valid;
|
||||||
|
const element = document.querySelector<HTMLInputElement>(
|
||||||
|
'input[type="datetime-local"]#announcement_ends_at',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!element) return;
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
element.classList.remove('optional');
|
||||||
|
element.required = true;
|
||||||
|
element.min = target.value;
|
||||||
|
} else {
|
||||||
|
element.classList.add('optional');
|
||||||
|
element.removeAttribute('required');
|
||||||
|
element.removeAttribute('min');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Rails.delegate(
|
||||||
|
document,
|
||||||
|
'input[type="datetime-local"]#announcement_starts_at',
|
||||||
|
'change',
|
||||||
|
({ target }) => {
|
||||||
|
if (target instanceof HTMLInputElement)
|
||||||
|
setAnnouncementEndsAttributes(target);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]';
|
||||||
|
|
||||||
|
const showSelectAll = () => {
|
||||||
|
const selectAllMatchingElement = document.querySelector(
|
||||||
|
'.batch-table__select-all',
|
||||||
|
);
|
||||||
|
selectAllMatchingElement?.classList.add('active');
|
||||||
|
};
|
||||||
|
|
||||||
|
const hideSelectAll = () => {
|
||||||
|
const selectAllMatchingElement = document.querySelector(
|
||||||
|
'.batch-table__select-all',
|
||||||
|
);
|
||||||
|
const hiddenField = document.querySelector<HTMLInputElement>(
|
||||||
|
'input#select_all_matching',
|
||||||
|
);
|
||||||
|
const selectedMsg = document.querySelector(
|
||||||
|
'.batch-table__select-all .selected',
|
||||||
|
);
|
||||||
|
const notSelectedMsg = document.querySelector(
|
||||||
|
'.batch-table__select-all .not-selected',
|
||||||
|
);
|
||||||
|
|
||||||
|
selectAllMatchingElement?.classList.remove('active');
|
||||||
|
selectedMsg?.classList.remove('active');
|
||||||
|
notSelectedMsg?.classList.add('active');
|
||||||
|
if (hiddenField) hiddenField.value = '0';
|
||||||
|
};
|
||||||
|
|
||||||
|
Rails.delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
|
||||||
|
if (!(target instanceof HTMLInputElement)) return;
|
||||||
|
|
||||||
|
const selectAllMatchingElement = document.querySelector(
|
||||||
|
'.batch-table__select-all',
|
||||||
|
);
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelectorAll<HTMLInputElement>(batchCheckboxClassName)
|
||||||
|
.forEach((content) => {
|
||||||
|
content.checked = target.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (selectAllMatchingElement) {
|
||||||
|
if (target.checked) {
|
||||||
|
showSelectAll();
|
||||||
|
} else {
|
||||||
|
hideSelectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Rails.delegate(document, '.batch-table__select-all button', 'click', () => {
|
||||||
|
const hiddenField = document.querySelector<HTMLInputElement>(
|
||||||
|
'#select_all_matching',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hiddenField) return;
|
||||||
|
|
||||||
|
const active = hiddenField.value === '1';
|
||||||
|
const selectedMsg = document.querySelector(
|
||||||
|
'.batch-table__select-all .selected',
|
||||||
|
);
|
||||||
|
const notSelectedMsg = document.querySelector(
|
||||||
|
'.batch-table__select-all .not-selected',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!selectedMsg || !notSelectedMsg) return;
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
hiddenField.value = '0';
|
||||||
|
selectedMsg.classList.remove('active');
|
||||||
|
notSelectedMsg.classList.add('active');
|
||||||
|
} else {
|
||||||
|
hiddenField.value = '1';
|
||||||
|
notSelectedMsg.classList.remove('active');
|
||||||
|
selectedMsg.classList.add('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Rails.delegate(document, batchCheckboxClassName, 'change', () => {
|
||||||
|
const checkAllElement = document.querySelector<HTMLInputElement>(
|
||||||
|
'input#batch_checkbox_all',
|
||||||
|
);
|
||||||
|
const selectAllMatchingElement = document.querySelector(
|
||||||
|
'.batch-table__select-all',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (checkAllElement) {
|
||||||
|
const allCheckboxes = Array.from(
|
||||||
|
document.querySelectorAll<HTMLInputElement>(batchCheckboxClassName),
|
||||||
|
);
|
||||||
|
checkAllElement.checked = allCheckboxes.every((content) => content.checked);
|
||||||
|
checkAllElement.indeterminate =
|
||||||
|
!checkAllElement.checked &&
|
||||||
|
allCheckboxes.some((content) => content.checked);
|
||||||
|
|
||||||
|
if (selectAllMatchingElement) {
|
||||||
|
if (checkAllElement.checked) {
|
||||||
|
showSelectAll();
|
||||||
|
} else {
|
||||||
|
hideSelectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Rails.delegate(
|
||||||
|
document,
|
||||||
|
'.filter-subset--with-select select',
|
||||||
|
'change',
|
||||||
|
({ target }) => {
|
||||||
|
if (target instanceof HTMLSelectElement) target.form?.submit();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const onDomainBlockSeverityChange = (target: HTMLSelectElement) => {
|
||||||
|
const rejectMediaDiv = document.querySelector(
|
||||||
|
'.input.with_label.domain_block_reject_media',
|
||||||
|
);
|
||||||
|
const rejectReportsDiv = document.querySelector(
|
||||||
|
'.input.with_label.domain_block_reject_reports',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rejectMediaDiv && rejectMediaDiv instanceof HTMLElement) {
|
||||||
|
rejectMediaDiv.style.display =
|
||||||
|
target.value === 'suspend' ? 'none' : 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rejectReportsDiv && rejectReportsDiv instanceof HTMLElement) {
|
||||||
|
rejectReportsDiv.style.display =
|
||||||
|
target.value === 'suspend' ? 'none' : 'block';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Rails.delegate(document, '#domain_block_severity', 'change', ({ target }) => {
|
||||||
|
if (target instanceof HTMLSelectElement) onDomainBlockSeverityChange(target);
|
||||||
|
});
|
||||||
|
|
||||||
|
const onEnableBootstrapTimelineAccountsChange = (target: HTMLInputElement) => {
|
||||||
|
const bootstrapTimelineAccountsField =
|
||||||
|
document.querySelector<HTMLInputElement>(
|
||||||
|
'#form_admin_settings_bootstrap_timeline_accounts',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (bootstrapTimelineAccountsField) {
|
||||||
|
bootstrapTimelineAccountsField.disabled = !target.checked;
|
||||||
|
if (target.checked) {
|
||||||
|
bootstrapTimelineAccountsField.parentElement?.classList.remove(
|
||||||
|
'disabled',
|
||||||
|
);
|
||||||
|
bootstrapTimelineAccountsField.parentElement?.parentElement?.classList.remove(
|
||||||
|
'disabled',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
bootstrapTimelineAccountsField.parentElement?.classList.add('disabled');
|
||||||
|
bootstrapTimelineAccountsField.parentElement?.parentElement?.classList.add(
|
||||||
|
'disabled',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Rails.delegate(
|
||||||
|
document,
|
||||||
|
'#form_admin_settings_enable_bootstrap_timeline_accounts',
|
||||||
|
'change',
|
||||||
|
({ target }) => {
|
||||||
|
if (target instanceof HTMLInputElement)
|
||||||
|
onEnableBootstrapTimelineAccountsChange(target);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const onChangeRegistrationMode = (target: HTMLSelectElement) => {
|
||||||
|
const enabled = target.value === 'approved';
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelectorAll<HTMLElement>(
|
||||||
|
'.form_admin_settings_registrations_mode .warning-hint',
|
||||||
|
)
|
||||||
|
.forEach((warning_hint) => {
|
||||||
|
warning_hint.style.display = target.value === 'open' ? 'inline' : 'none';
|
||||||
|
});
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelectorAll<HTMLInputElement>(
|
||||||
|
'input#form_admin_settings_require_invite_text',
|
||||||
|
)
|
||||||
|
.forEach((input) => {
|
||||||
|
input.disabled = !enabled;
|
||||||
|
if (enabled) {
|
||||||
|
let element: HTMLElement | null = input;
|
||||||
|
do {
|
||||||
|
element.classList.remove('disabled');
|
||||||
|
element = element.parentElement;
|
||||||
|
} while (element && !element.classList.contains('fields-group'));
|
||||||
|
} else {
|
||||||
|
let element: HTMLElement | null = input;
|
||||||
|
do {
|
||||||
|
element.classList.add('disabled');
|
||||||
|
element = element.parentElement;
|
||||||
|
} while (element && !element.classList.contains('fields-group'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const convertUTCDateTimeToLocal = (value: string) => {
|
||||||
|
const date = new Date(value + 'Z');
|
||||||
|
const twoChars = (x: number) => x.toString().padStart(2, '0');
|
||||||
|
return `${date.getFullYear()}-${twoChars(date.getMonth() + 1)}-${twoChars(date.getDate())}T${twoChars(date.getHours())}:${twoChars(date.getMinutes())}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
function convertLocalDatetimeToUTC(value: string) {
|
||||||
|
const date = new Date(value);
|
||||||
|
const fullISO8601 = date.toISOString();
|
||||||
|
return fullISO8601.slice(0, fullISO8601.indexOf('T') + 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rails.delegate(
|
||||||
|
document,
|
||||||
|
'#form_admin_settings_registrations_mode',
|
||||||
|
'change',
|
||||||
|
({ target }) => {
|
||||||
|
if (target instanceof HTMLSelectElement) onChangeRegistrationMode(target);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
ready(() => {
|
||||||
|
const domainBlockSeveritySelect = document.querySelector<HTMLSelectElement>(
|
||||||
|
'select#domain_block_severity',
|
||||||
|
);
|
||||||
|
if (domainBlockSeveritySelect)
|
||||||
|
onDomainBlockSeverityChange(domainBlockSeveritySelect);
|
||||||
|
|
||||||
|
const enableBootstrapTimelineAccounts =
|
||||||
|
document.querySelector<HTMLInputElement>(
|
||||||
|
'input#form_admin_settings_enable_bootstrap_timeline_accounts',
|
||||||
|
);
|
||||||
|
if (enableBootstrapTimelineAccounts)
|
||||||
|
onEnableBootstrapTimelineAccountsChange(enableBootstrapTimelineAccounts);
|
||||||
|
|
||||||
|
const registrationMode = document.querySelector<HTMLSelectElement>(
|
||||||
|
'select#form_admin_settings_registrations_mode',
|
||||||
|
);
|
||||||
|
if (registrationMode) onChangeRegistrationMode(registrationMode);
|
||||||
|
|
||||||
|
const checkAllElement = document.querySelector<HTMLInputElement>(
|
||||||
|
'input#batch_checkbox_all',
|
||||||
|
);
|
||||||
|
if (checkAllElement) {
|
||||||
|
const allCheckboxes = Array.from(
|
||||||
|
document.querySelectorAll<HTMLInputElement>(batchCheckboxClassName),
|
||||||
|
);
|
||||||
|
checkAllElement.checked = allCheckboxes.every((content) => content.checked);
|
||||||
|
checkAllElement.indeterminate =
|
||||||
|
!checkAllElement.checked &&
|
||||||
|
allCheckboxes.some((content) => content.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelector('a#add-instance-button')
|
||||||
|
?.addEventListener('click', (e) => {
|
||||||
|
const domain = document.querySelector<HTMLInputElement>(
|
||||||
|
'input[type="text"]#by_domain',
|
||||||
|
)?.value;
|
||||||
|
|
||||||
|
if (domain && e.target instanceof HTMLAnchorElement) {
|
||||||
|
const url = new URL(e.target.href);
|
||||||
|
url.searchParams.set('_domain', domain);
|
||||||
|
e.target.href = url.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelectorAll<HTMLInputElement>('input[type="datetime-local"]')
|
||||||
|
.forEach((element) => {
|
||||||
|
if (element.value) {
|
||||||
|
element.value = convertUTCDateTimeToLocal(element.value);
|
||||||
|
}
|
||||||
|
if (element.placeholder) {
|
||||||
|
element.placeholder = convertUTCDateTimeToLocal(element.placeholder);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Rails.delegate(document, 'form', 'submit', ({ target }) => {
|
||||||
|
if (target instanceof HTMLFormElement)
|
||||||
|
target
|
||||||
|
.querySelectorAll<HTMLInputElement>('input[type="datetime-local"]')
|
||||||
|
.forEach((element) => {
|
||||||
|
if (element.value && element.validity.valid) {
|
||||||
|
element.value = convertLocalDatetimeToUTC(element.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const announcementStartsAt = document.querySelector<HTMLInputElement>(
|
||||||
|
'input[type="datetime-local"]#announcement_starts_at',
|
||||||
|
);
|
||||||
|
if (announcementStartsAt) {
|
||||||
|
setAnnouncementEndsAttributes(announcementStartsAt);
|
||||||
|
}
|
||||||
|
}).catch((reason) => {
|
||||||
|
throw reason;
|
||||||
|
});
|
|
@ -1,25 +0,0 @@
|
||||||
// This file will be loaded on embed pages, regardless of theme.
|
|
||||||
|
|
||||||
import 'packs/public-path';
|
|
||||||
|
|
||||||
window.addEventListener('message', e => {
|
|
||||||
const data = e.data || {};
|
|
||||||
|
|
||||||
if (!window.parent || data.type !== 'setHeight') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setEmbedHeight () {
|
|
||||||
window.parent.postMessage({
|
|
||||||
type: 'setHeight',
|
|
||||||
id: data.id,
|
|
||||||
height: document.getElementsByTagName('html')[0].scrollHeight,
|
|
||||||
}, '*');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (['interactive', 'complete'].includes(document.readyState)) {
|
|
||||||
setEmbedHeight();
|
|
||||||
} else {
|
|
||||||
document.addEventListener('DOMContentLoaded', setEmbedHeight);
|
|
||||||
}
|
|
||||||
});
|
|
41
app/javascript/core/embed.ts
Normal file
41
app/javascript/core/embed.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// This file will be loaded on embed pages, regardless of theme.
|
||||||
|
|
||||||
|
import 'packs/public-path';
|
||||||
|
import ready from '../mastodon/ready';
|
||||||
|
|
||||||
|
interface SetHeightMessage {
|
||||||
|
type: 'setHeight';
|
||||||
|
id: string;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSetHeightMessage(data: unknown): data is SetHeightMessage {
|
||||||
|
if (
|
||||||
|
data &&
|
||||||
|
typeof data === 'object' &&
|
||||||
|
'type' in data &&
|
||||||
|
data.type === 'setHeight'
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('message', (e) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typings are not correct, it can be null in very rare cases
|
||||||
|
if (!e.data || !isSetHeightMessage(e.data) || !window.parent) return;
|
||||||
|
|
||||||
|
const data = e.data;
|
||||||
|
|
||||||
|
ready(() => {
|
||||||
|
window.parent.postMessage(
|
||||||
|
{
|
||||||
|
type: 'setHeight',
|
||||||
|
id: data.id,
|
||||||
|
height: document.getElementsByTagName('html')[0].scrollHeight,
|
||||||
|
},
|
||||||
|
'*',
|
||||||
|
);
|
||||||
|
}).catch((e) => {
|
||||||
|
console.error('Error in setHeightMessage postMessage', e);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,44 +0,0 @@
|
||||||
// This file will be loaded on settings pages, regardless of theme.
|
|
||||||
|
|
||||||
import 'packs/public-path';
|
|
||||||
import Rails from '@rails/ujs';
|
|
||||||
|
|
||||||
Rails.delegate(document, '#edit_profile input[type=file]', 'change', ({ target }) => {
|
|
||||||
const avatar = document.getElementById(target.id + '-preview');
|
|
||||||
const [file] = target.files || [];
|
|
||||||
const url = file ? URL.createObjectURL(file) : avatar.dataset.originalSrc;
|
|
||||||
|
|
||||||
avatar.src = url;
|
|
||||||
});
|
|
||||||
|
|
||||||
Rails.delegate(document, '.input-copy input', 'click', ({ target }) => {
|
|
||||||
target.focus();
|
|
||||||
target.select();
|
|
||||||
target.setSelectionRange(0, target.value.length);
|
|
||||||
});
|
|
||||||
|
|
||||||
Rails.delegate(document, '.input-copy button', 'click', ({ target }) => {
|
|
||||||
const input = target.parentNode.querySelector('.input-copy__wrapper input');
|
|
||||||
|
|
||||||
const oldReadOnly = input.readonly;
|
|
||||||
|
|
||||||
input.readonly = false;
|
|
||||||
input.focus();
|
|
||||||
input.select();
|
|
||||||
input.setSelectionRange(0, input.value.length);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (document.execCommand('copy')) {
|
|
||||||
input.blur();
|
|
||||||
target.parentNode.classList.add('copied');
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
target.parentNode.classList.remove('copied');
|
|
||||||
}, 700);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
input.readonly = oldReadOnly;
|
|
||||||
});
|
|
70
app/javascript/core/settings.ts
Normal file
70
app/javascript/core/settings.ts
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// This file will be loaded on settings pages, regardless of theme.
|
||||||
|
|
||||||
|
import 'packs/public-path';
|
||||||
|
import Rails from '@rails/ujs';
|
||||||
|
|
||||||
|
Rails.delegate(
|
||||||
|
document,
|
||||||
|
'#edit_profile input[type=file]',
|
||||||
|
'change',
|
||||||
|
({ target }) => {
|
||||||
|
if (!(target instanceof HTMLInputElement)) return;
|
||||||
|
|
||||||
|
const avatar = document.querySelector<HTMLImageElement>(
|
||||||
|
`img#${target.id}-preview`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!avatar) return;
|
||||||
|
|
||||||
|
let file: File | undefined;
|
||||||
|
if (target.files) file = target.files[0];
|
||||||
|
|
||||||
|
const url = file ? URL.createObjectURL(file) : avatar.dataset.originalSrc;
|
||||||
|
|
||||||
|
if (url) avatar.src = url;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Rails.delegate(document, '.input-copy input', 'click', ({ target }) => {
|
||||||
|
if (!(target instanceof HTMLInputElement)) return;
|
||||||
|
|
||||||
|
target.focus();
|
||||||
|
target.select();
|
||||||
|
target.setSelectionRange(0, target.value.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
Rails.delegate(document, '.input-copy button', 'click', ({ target }) => {
|
||||||
|
if (!(target instanceof HTMLButtonElement)) return;
|
||||||
|
|
||||||
|
const input = target.parentNode?.querySelector<HTMLInputElement>(
|
||||||
|
'.input-copy__wrapper input',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!input) return;
|
||||||
|
|
||||||
|
const oldReadOnly = input.readOnly;
|
||||||
|
|
||||||
|
input.readOnly = false;
|
||||||
|
input.focus();
|
||||||
|
input.select();
|
||||||
|
input.setSelectionRange(0, input.value.length);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (document.execCommand('copy')) {
|
||||||
|
input.blur();
|
||||||
|
|
||||||
|
const parent = target.parentElement;
|
||||||
|
|
||||||
|
if (!parent) return;
|
||||||
|
parent.classList.add('copied');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
parent.classList.remove('copied');
|
||||||
|
}, 700);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
input.readOnly = oldReadOnly;
|
||||||
|
});
|
|
@ -2,12 +2,12 @@
|
||||||
# theme.
|
# theme.
|
||||||
pack:
|
pack:
|
||||||
about:
|
about:
|
||||||
admin: admin.js
|
admin: admin.ts
|
||||||
auth: auth.js
|
auth: auth.js
|
||||||
common:
|
common:
|
||||||
filename: common.js
|
filename: common.js
|
||||||
stylesheet: true
|
stylesheet: true
|
||||||
embed: embed.js
|
embed: embed.ts
|
||||||
error:
|
error:
|
||||||
home:
|
home:
|
||||||
inert:
|
inert:
|
||||||
|
@ -18,7 +18,7 @@ pack:
|
||||||
stylesheet: true
|
stylesheet: true
|
||||||
modal:
|
modal:
|
||||||
public:
|
public:
|
||||||
settings: settings.js
|
settings: settings.ts
|
||||||
sign_up:
|
sign_up:
|
||||||
share:
|
share:
|
||||||
remote_interaction_helper: remote_interaction_helper.ts
|
remote_interaction_helper: remote_interaction_helper.ts
|
||||||
|
|
|
@ -66,11 +66,9 @@ export const FOLLOW_REQUESTS_EXPAND_SUCCESS = 'FOLLOW_REQUESTS_EXPAND_SUCCESS';
|
||||||
export const FOLLOW_REQUESTS_EXPAND_FAIL = 'FOLLOW_REQUESTS_EXPAND_FAIL';
|
export const FOLLOW_REQUESTS_EXPAND_FAIL = 'FOLLOW_REQUESTS_EXPAND_FAIL';
|
||||||
|
|
||||||
export const FOLLOW_REQUEST_AUTHORIZE_REQUEST = 'FOLLOW_REQUEST_AUTHORIZE_REQUEST';
|
export const FOLLOW_REQUEST_AUTHORIZE_REQUEST = 'FOLLOW_REQUEST_AUTHORIZE_REQUEST';
|
||||||
export const FOLLOW_REQUEST_AUTHORIZE_SUCCESS = 'FOLLOW_REQUEST_AUTHORIZE_SUCCESS';
|
|
||||||
export const FOLLOW_REQUEST_AUTHORIZE_FAIL = 'FOLLOW_REQUEST_AUTHORIZE_FAIL';
|
export const FOLLOW_REQUEST_AUTHORIZE_FAIL = 'FOLLOW_REQUEST_AUTHORIZE_FAIL';
|
||||||
|
|
||||||
export const FOLLOW_REQUEST_REJECT_REQUEST = 'FOLLOW_REQUEST_REJECT_REQUEST';
|
export const FOLLOW_REQUEST_REJECT_REQUEST = 'FOLLOW_REQUEST_REJECT_REQUEST';
|
||||||
export const FOLLOW_REQUEST_REJECT_SUCCESS = 'FOLLOW_REQUEST_REJECT_SUCCESS';
|
|
||||||
export const FOLLOW_REQUEST_REJECT_FAIL = 'FOLLOW_REQUEST_REJECT_FAIL';
|
export const FOLLOW_REQUEST_REJECT_FAIL = 'FOLLOW_REQUEST_REJECT_FAIL';
|
||||||
|
|
||||||
export const PINNED_ACCOUNTS_FETCH_REQUEST = 'PINNED_ACCOUNTS_FETCH_REQUEST';
|
export const PINNED_ACCOUNTS_FETCH_REQUEST = 'PINNED_ACCOUNTS_FETCH_REQUEST';
|
||||||
|
@ -93,11 +91,6 @@ export * from './accounts_typed';
|
||||||
export function fetchAccount(id) {
|
export function fetchAccount(id) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(fetchRelationships([id]));
|
dispatch(fetchRelationships([id]));
|
||||||
|
|
||||||
if (getState().getIn(['accounts', id], null) !== null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchAccountRequest(id));
|
dispatch(fetchAccountRequest(id));
|
||||||
|
|
||||||
api(getState).get(`/api/v1/accounts/${id}`).then(response => {
|
api(getState).get(`/api/v1/accounts/${id}`).then(response => {
|
||||||
|
|
|
@ -12,8 +12,6 @@ export const BLOCKS_EXPAND_REQUEST = 'BLOCKS_EXPAND_REQUEST';
|
||||||
export const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS';
|
export const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS';
|
||||||
export const BLOCKS_EXPAND_FAIL = 'BLOCKS_EXPAND_FAIL';
|
export const BLOCKS_EXPAND_FAIL = 'BLOCKS_EXPAND_FAIL';
|
||||||
|
|
||||||
export const BLOCKS_INIT_MODAL = 'BLOCKS_INIT_MODAL';
|
|
||||||
|
|
||||||
export function fetchBlocks() {
|
export function fetchBlocks() {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(fetchBlocksRequest());
|
dispatch(fetchBlocksRequest());
|
||||||
|
@ -90,11 +88,12 @@ export function expandBlocksFail(error) {
|
||||||
|
|
||||||
export function initBlockModal(account) {
|
export function initBlockModal(account) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
dispatch({
|
dispatch(openModal({
|
||||||
type: BLOCKS_INIT_MODAL,
|
modalType: 'BLOCK',
|
||||||
account,
|
modalProps: {
|
||||||
});
|
accountId: account.get('id'),
|
||||||
|
acct: account.get('acct'),
|
||||||
dispatch(openModal({ modalType: 'BLOCK' }));
|
},
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ let fetchComposeSuggestionsAccountsController;
|
||||||
let fetchComposeSuggestionsTagsController;
|
let fetchComposeSuggestionsTagsController;
|
||||||
|
|
||||||
export const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
|
export const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
|
||||||
export const COMPOSE_CYCLE_ELEFRIEND = 'COMPOSE_CYCLE_ELEFRIEND';
|
|
||||||
export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
|
export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
|
||||||
export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
|
export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
|
||||||
export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
|
export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
|
||||||
|
@ -59,7 +58,7 @@ export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE';
|
||||||
export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE';
|
export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE';
|
||||||
export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
|
export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
|
||||||
export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
|
export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
|
||||||
export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';
|
export const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE';
|
||||||
export const COMPOSE_CONTENT_TYPE_CHANGE = 'COMPOSE_CONTENT_TYPE_CHANGE';
|
export const COMPOSE_CONTENT_TYPE_CHANGE = 'COMPOSE_CONTENT_TYPE_CHANGE';
|
||||||
export const COMPOSE_LANGUAGE_CHANGE = 'COMPOSE_LANGUAGE_CHANGE';
|
export const COMPOSE_LANGUAGE_CHANGE = 'COMPOSE_LANGUAGE_CHANGE';
|
||||||
|
|
||||||
|
@ -82,6 +81,7 @@ 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_CHANGE_MEDIA_ORDER = 'COMPOSE_CHANGE_MEDIA_ORDER';
|
||||||
|
|
||||||
export const COMPOSE_SET_STATUS = 'COMPOSE_SET_STATUS';
|
export const COMPOSE_SET_STATUS = 'COMPOSE_SET_STATUS';
|
||||||
export const COMPOSE_FOCUS = 'COMPOSE_FOCUS';
|
export const COMPOSE_FOCUS = 'COMPOSE_FOCUS';
|
||||||
|
@ -117,12 +117,6 @@ export function changeCompose(text) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cycleElefriendCompose() {
|
|
||||||
return {
|
|
||||||
type: COMPOSE_CYCLE_ELEFRIEND,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function replyCompose(status, routerHistory) {
|
export function replyCompose(status, routerHistory) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const prependCWRe = getState().getIn(['local_settings', 'prepend_cw_re']);
|
const prependCWRe = getState().getIn(['local_settings', 'prepend_cw_re']);
|
||||||
|
@ -148,13 +142,13 @@ export function resetCompose() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const focusCompose = (routerHistory, defaultText) => dispatch => {
|
export const focusCompose = (routerHistory, defaultText) => (dispatch, getState) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: COMPOSE_FOCUS,
|
type: COMPOSE_FOCUS,
|
||||||
defaultText,
|
defaultText,
|
||||||
});
|
});
|
||||||
|
|
||||||
ensureComposeIsVisible(routerHistory);
|
ensureComposeIsVisible(getState, routerHistory);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function mentionCompose(account, routerHistory) {
|
export function mentionCompose(account, routerHistory) {
|
||||||
|
@ -179,7 +173,7 @@ export function directCompose(account, routerHistory) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function submitCompose(routerHistory) {
|
export function submitCompose(routerHistory, overridePrivacy = null) {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
let status = getState().getIn(['compose', 'text'], '');
|
let status = getState().getIn(['compose', 'text'], '');
|
||||||
const media = getState().getIn(['compose', 'media_attachments']);
|
const media = getState().getIn(['compose', 'media_attachments']);
|
||||||
|
@ -228,7 +222,7 @@ export function submitCompose(routerHistory) {
|
||||||
media_attributes,
|
media_attributes,
|
||||||
sensitive: getState().getIn(['compose', 'sensitive']) || (spoilerText.length > 0 && media.size !== 0),
|
sensitive: getState().getIn(['compose', 'sensitive']) || (spoilerText.length > 0 && media.size !== 0),
|
||||||
spoiler_text: spoilerText,
|
spoiler_text: spoilerText,
|
||||||
visibility: getState().getIn(['compose', 'privacy']),
|
visibility: overridePrivacy || getState().getIn(['compose', 'privacy']),
|
||||||
poll: getState().getIn(['compose', 'poll'], null),
|
poll: getState().getIn(['compose', 'poll'], null),
|
||||||
language: getState().getIn(['compose', 'language']),
|
language: getState().getIn(['compose', 'language']),
|
||||||
},
|
},
|
||||||
|
@ -246,11 +240,6 @@ export function submitCompose(routerHistory) {
|
||||||
dispatch(insertIntoTagHistory(response.data.tags, status));
|
dispatch(insertIntoTagHistory(response.data.tags, status));
|
||||||
dispatch(submitComposeSuccess({ ...response.data }));
|
dispatch(submitComposeSuccess({ ...response.data }));
|
||||||
|
|
||||||
// If the response has no data then we can't do anything else.
|
|
||||||
if (!response.data) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// To make the app more responsive, immediately push the status
|
// To make the app more responsive, immediately push the status
|
||||||
// into the columns
|
// into the columns
|
||||||
const insertIfOnline = timelineId => {
|
const insertIfOnline = timelineId => {
|
||||||
|
@ -278,12 +267,14 @@ export function submitCompose(routerHistory) {
|
||||||
insertIfOnline('direct');
|
insertIfOnline('direct');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getState().getIn(['local_settings', 'show_published_toast'])) {
|
||||||
dispatch(showAlert({
|
dispatch(showAlert({
|
||||||
message: statusId === null ? messages.published : messages.saved,
|
message: statusId === null ? messages.published : messages.saved,
|
||||||
action: messages.open,
|
action: messages.open,
|
||||||
dismissAfter: 10000,
|
dismissAfter: 10000,
|
||||||
onClick: () => routerHistory.push(`/@${response.data.account.username}/${response.data.id}`),
|
onClick: () => routerHistory.push(`/@${response.data.account.username}/${response.data.id}`),
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
dispatch(submitComposeFail(error));
|
dispatch(submitComposeFail(error));
|
||||||
});
|
});
|
||||||
|
@ -660,15 +651,19 @@ export const readyComposeSuggestionsTags = (token, tags) => ({
|
||||||
|
|
||||||
export function selectComposeSuggestion(position, token, suggestion, path) {
|
export function selectComposeSuggestion(position, token, suggestion, path) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
let completion;
|
let completion, startPosition;
|
||||||
|
|
||||||
if (suggestion.type === 'emoji') {
|
if (suggestion.type === 'emoji') {
|
||||||
completion = suggestion.native || suggestion.colons;
|
completion = suggestion.native || suggestion.colons;
|
||||||
|
startPosition = position - 1;
|
||||||
|
|
||||||
dispatch(useEmoji(suggestion));
|
dispatch(useEmoji(suggestion));
|
||||||
} else if (suggestion.type === 'hashtag') {
|
} else if (suggestion.type === 'hashtag') {
|
||||||
completion = `#${suggestion.name}`;
|
completion = `#${suggestion.name}`;
|
||||||
|
startPosition = position - 1;
|
||||||
} else if (suggestion.type === 'account') {
|
} else if (suggestion.type === 'account') {
|
||||||
completion = '@' + getState().getIn(['accounts', suggestion.id, 'acct']);
|
completion = getState().getIn(['accounts', suggestion.id, 'acct']);
|
||||||
|
startPosition = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't want to replace hashtags that vary only in case due to accessibility, but we need to fire off an event so that
|
// We don't want to replace hashtags that vary only in case due to accessibility, but we need to fire off an event so that
|
||||||
|
@ -676,7 +671,7 @@ export function selectComposeSuggestion(position, token, suggestion, path) {
|
||||||
if (suggestion.type !== 'hashtag' || token.slice(1).localeCompare(suggestion.name, undefined, { sensitivity: 'accent' }) !== 0) {
|
if (suggestion.type !== 'hashtag' || token.slice(1).localeCompare(suggestion.name, undefined, { sensitivity: 'accent' }) !== 0) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: COMPOSE_SUGGESTION_SELECT,
|
type: COMPOSE_SUGGESTION_SELECT,
|
||||||
position,
|
position: startPosition,
|
||||||
token,
|
token,
|
||||||
completion,
|
completion,
|
||||||
path,
|
path,
|
||||||
|
@ -684,7 +679,7 @@ export function selectComposeSuggestion(position, token, suggestion, path) {
|
||||||
} else {
|
} else {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: COMPOSE_SUGGESTION_IGNORE,
|
type: COMPOSE_SUGGESTION_IGNORE,
|
||||||
position,
|
position: startPosition,
|
||||||
token,
|
token,
|
||||||
completion,
|
completion,
|
||||||
path,
|
path,
|
||||||
|
@ -786,18 +781,26 @@ export function changeComposeVisibility(value) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeComposeContentType(value) {
|
export function insertEmojiCompose(position, emoji, needsSpace) {
|
||||||
return {
|
|
||||||
type: COMPOSE_CONTENT_TYPE_CHANGE,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function insertEmojiCompose(position, emoji) {
|
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_EMOJI_INSERT,
|
type: COMPOSE_EMOJI_INSERT,
|
||||||
position,
|
position,
|
||||||
emoji,
|
emoji,
|
||||||
|
needsSpace,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeComposing(value) {
|
||||||
|
return {
|
||||||
|
type: COMPOSE_COMPOSING_CHANGE,
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeComposeContentType(value) {
|
||||||
|
return {
|
||||||
|
type: COMPOSE_CONTENT_TYPE_CHANGE,
|
||||||
|
value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,11 +823,12 @@ export function addPollOption(title) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changePollOption(index, title) {
|
export function changePollOption(index, title, maxOptions) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_POLL_OPTION_CHANGE,
|
type: COMPOSE_POLL_OPTION_CHANGE,
|
||||||
index,
|
index,
|
||||||
title,
|
title,
|
||||||
|
maxOptions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,3 +846,9 @@ export function changePollSettings(expiresIn, isMultiple) {
|
||||||
isMultiple,
|
isMultiple,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const changeMediaOrder = (a, b) => ({
|
||||||
|
type: COMPOSE_CHANGE_MEDIA_ORDER,
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import api, { getLinks } from '../api';
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
import { blockDomainSuccess, unblockDomainSuccess } from "./domain_blocks_typed";
|
import { blockDomainSuccess, unblockDomainSuccess } from "./domain_blocks_typed";
|
||||||
|
import { openModal } from './modal';
|
||||||
|
|
||||||
|
|
||||||
export * from "./domain_blocks_typed";
|
export * from "./domain_blocks_typed";
|
||||||
|
|
||||||
|
@ -150,3 +152,12 @@ export function expandDomainBlocksFail(error) {
|
||||||
error,
|
error,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const initDomainBlockModal = account => dispatch => dispatch(openModal({
|
||||||
|
modalType: 'DOMAIN_BLOCK',
|
||||||
|
modalProps: {
|
||||||
|
domain: account.get('acct').split('@')[1],
|
||||||
|
acct: account.get('acct'),
|
||||||
|
accountId: account.get('id'),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
|
@ -12,10 +12,6 @@ export const MUTES_EXPAND_REQUEST = 'MUTES_EXPAND_REQUEST';
|
||||||
export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS';
|
export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS';
|
||||||
export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL';
|
export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL';
|
||||||
|
|
||||||
export const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL';
|
|
||||||
export const MUTES_TOGGLE_HIDE_NOTIFICATIONS = 'MUTES_TOGGLE_HIDE_NOTIFICATIONS';
|
|
||||||
export const MUTES_CHANGE_DURATION = 'MUTES_CHANGE_DURATION';
|
|
||||||
|
|
||||||
export function fetchMutes() {
|
export function fetchMutes() {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(fetchMutesRequest());
|
dispatch(fetchMutesRequest());
|
||||||
|
@ -92,26 +88,12 @@ export function expandMutesFail(error) {
|
||||||
|
|
||||||
export function initMuteModal(account) {
|
export function initMuteModal(account) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
dispatch({
|
dispatch(openModal({
|
||||||
type: MUTES_INIT_MODAL,
|
modalType: 'MUTE',
|
||||||
account,
|
modalProps: {
|
||||||
});
|
accountId: account.get('id'),
|
||||||
|
acct: account.get('acct'),
|
||||||
dispatch(openModal({ modalType: 'MUTE' }));
|
},
|
||||||
};
|
}));
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleHideNotifications() {
|
|
||||||
return dispatch => {
|
|
||||||
dispatch({ type: MUTES_TOGGLE_HIDE_NOTIFICATIONS });
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeMuteDuration(duration) {
|
|
||||||
return dispatch => {
|
|
||||||
dispatch({
|
|
||||||
type: MUTES_CHANGE_DURATION,
|
|
||||||
duration,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue