Compare commits
46 Commits
13.0.0-rc.
...
13.0.0-rc.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d513848f65 | ||
![]() |
ae6af6aefd | ||
![]() |
a0ae9f7593 | ||
![]() |
dace5b6940 | ||
![]() |
2d8b97287e | ||
![]() |
ec63a50de2 | ||
![]() |
6e2d7e9792 | ||
![]() |
39349dcba5 | ||
![]() |
a5b1fe5d16 | ||
![]() |
91bbb67e4a | ||
![]() |
f368bce9d5 | ||
![]() |
fbfe42d6f0 | ||
![]() |
f3c5ca6cf4 | ||
![]() |
0022267072 | ||
![]() |
30fced38c4 | ||
![]() |
7e5f3dbf11 | ||
![]() |
9f0dfb5517 | ||
![]() |
678c7d9502 | ||
![]() |
91a3c3943d | ||
![]() |
c46b45a467 | ||
![]() |
9385767b12 | ||
![]() |
7795ff0c95 | ||
![]() |
a9acd72eb7 | ||
![]() |
67d366c3ca | ||
![]() |
1f8f051ee2 | ||
![]() |
94004b7a3f | ||
![]() |
3e9f88506e | ||
![]() |
81f11d8f86 | ||
![]() |
518b3e2f73 | ||
![]() |
d0157b3bfd | ||
![]() |
7fc8d2e6d5 | ||
![]() |
fb0f9711ba | ||
![]() |
92136272b0 | ||
![]() |
e1159e9ef2 | ||
![]() |
a2e61c6708 | ||
![]() |
726959911c | ||
![]() |
d59914b959 | ||
![]() |
07025caee9 | ||
![]() |
1c0289e490 | ||
![]() |
275fcd8bbc | ||
![]() |
0c0aa93668 | ||
![]() |
bfcd5ea440 | ||
![]() |
3ff43cca02 | ||
![]() |
6bd536c526 | ||
![]() |
7738a36014 | ||
![]() |
daddec8362 |
151
.config/docker_example.yml
Normal file
151
.config/docker_example.yml
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
# Misskey configuration
|
||||||
|
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
# ┌─────┐
|
||||||
|
#───┘ URL └─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Final accessible URL seen by a user.
|
||||||
|
url: https://example.tld/
|
||||||
|
|
||||||
|
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||||
|
# URL SETTINGS AFTER THAT!
|
||||||
|
|
||||||
|
# ┌───────────────────────┐
|
||||||
|
#───┘ Port and TLS settings └───────────────────────────────────
|
||||||
|
|
||||||
|
#
|
||||||
|
# Misskey requires a reverse proxy to support HTTPS connections.
|
||||||
|
#
|
||||||
|
# +----- https://example.tld/ ------------+
|
||||||
|
# +------+ |+-------------+ +----------------+|
|
||||||
|
# | User | ---> || Proxy (443) | ---> | Misskey (3000) ||
|
||||||
|
# +------+ |+-------------+ +----------------+|
|
||||||
|
# +---------------------------------------+
|
||||||
|
#
|
||||||
|
# You need to set up a reverse proxy. (e.g. nginx)
|
||||||
|
# An encrypted connection with HTTPS is highly recommended
|
||||||
|
# because tokens may be transferred in GET requests.
|
||||||
|
|
||||||
|
# The port that your Misskey server should listen on.
|
||||||
|
port: 3000
|
||||||
|
|
||||||
|
# ┌──────────────────────────┐
|
||||||
|
#───┘ PostgreSQL configuration └────────────────────────────────
|
||||||
|
|
||||||
|
db:
|
||||||
|
host: db
|
||||||
|
port: 5432
|
||||||
|
|
||||||
|
# Database name
|
||||||
|
db: misskey
|
||||||
|
|
||||||
|
# Auth
|
||||||
|
user: example-misskey-user
|
||||||
|
pass: example-misskey-pass
|
||||||
|
|
||||||
|
# Whether disable Caching queries
|
||||||
|
#disableCache: true
|
||||||
|
|
||||||
|
# Extra Connection options
|
||||||
|
#extra:
|
||||||
|
# ssl: true
|
||||||
|
|
||||||
|
# ┌─────────────────────┐
|
||||||
|
#───┘ Redis configuration └─────────────────────────────────────
|
||||||
|
|
||||||
|
redis:
|
||||||
|
host: redis
|
||||||
|
port: 6379
|
||||||
|
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||||
|
#pass: example-pass
|
||||||
|
#prefix: example-prefix
|
||||||
|
#db: 1
|
||||||
|
|
||||||
|
# ┌─────────────────────────────┐
|
||||||
|
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||||
|
|
||||||
|
#elasticsearch:
|
||||||
|
# host: localhost
|
||||||
|
# port: 9200
|
||||||
|
# ssl: false
|
||||||
|
# user:
|
||||||
|
# pass:
|
||||||
|
|
||||||
|
# ┌───────────────┐
|
||||||
|
#───┘ ID generation └───────────────────────────────────────────
|
||||||
|
|
||||||
|
# You can select the ID generation method.
|
||||||
|
# You don't usually need to change this setting, but you can
|
||||||
|
# change it according to your preferences.
|
||||||
|
|
||||||
|
# Available methods:
|
||||||
|
# aid ... Short, Millisecond accuracy
|
||||||
|
# meid ... Similar to ObjectID, Millisecond accuracy
|
||||||
|
# ulid ... Millisecond accuracy
|
||||||
|
# objectid ... This is left for backward compatibility
|
||||||
|
|
||||||
|
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||||
|
# ID SETTINGS AFTER THAT!
|
||||||
|
|
||||||
|
id: 'aid'
|
||||||
|
|
||||||
|
# ┌─────────────────────┐
|
||||||
|
#───┘ Other configuration └─────────────────────────────────────
|
||||||
|
|
||||||
|
# Whether disable HSTS
|
||||||
|
#disableHsts: true
|
||||||
|
|
||||||
|
# Number of worker processes
|
||||||
|
#clusterLimit: 1
|
||||||
|
|
||||||
|
# Job concurrency per worker
|
||||||
|
# deliverJobConcurrency: 128
|
||||||
|
# inboxJobConcurrency: 16
|
||||||
|
|
||||||
|
# Job rate limiter
|
||||||
|
# deliverJobPerSec: 128
|
||||||
|
# inboxJobPerSec: 16
|
||||||
|
|
||||||
|
# Job attempts
|
||||||
|
# deliverJobMaxAttempts: 12
|
||||||
|
# inboxJobMaxAttempts: 8
|
||||||
|
|
||||||
|
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||||
|
#outgoingAddressFamily: ipv4
|
||||||
|
|
||||||
|
# Syslog option
|
||||||
|
#syslog:
|
||||||
|
# host: localhost
|
||||||
|
# port: 514
|
||||||
|
|
||||||
|
# Proxy for HTTP/HTTPS
|
||||||
|
#proxy: http://127.0.0.1:3128
|
||||||
|
|
||||||
|
proxyBypassHosts:
|
||||||
|
- api.deepl.com
|
||||||
|
- api-free.deepl.com
|
||||||
|
- www.recaptcha.net
|
||||||
|
- hcaptcha.com
|
||||||
|
- challenges.cloudflare.com
|
||||||
|
|
||||||
|
# Proxy for SMTP/SMTPS
|
||||||
|
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
|
||||||
|
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
|
||||||
|
#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5
|
||||||
|
|
||||||
|
# Media Proxy
|
||||||
|
#mediaProxy: https://example.com/proxy
|
||||||
|
|
||||||
|
# Proxy remote files (default: false)
|
||||||
|
#proxyRemoteFiles: true
|
||||||
|
|
||||||
|
# Sign to ActivityPub GET request (default: true)
|
||||||
|
signToActivityPubGet: true
|
||||||
|
|
||||||
|
#allowedPrivateNetworks: [
|
||||||
|
# '127.0.0.1/32'
|
||||||
|
#]
|
||||||
|
|
||||||
|
# Upload or download file size limits (bytes)
|
||||||
|
#maxFileSize: 262144000
|
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@@ -5,6 +5,11 @@
|
|||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
open-pull-requests-limit: 0
|
||||||
- package-ecosystem: npm
|
- package-ecosystem: npm
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
@@ -20,3 +25,8 @@ updates:
|
|||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
open-pull-requests-limit: 0
|
open-pull-requests-limit: 0
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: "/packages/sw"
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
open-pull-requests-limit: 0
|
||||||
|
18
.github/workflows/check_copyright_year.yml
vendored
Normal file
18
.github/workflows/check_copyright_year.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
name: Check copyright year
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check_copyright_year:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3.2.0
|
||||||
|
- run: |
|
||||||
|
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
|
||||||
|
echo "Please change copyright year!"
|
||||||
|
exit 1
|
||||||
|
fi
|
4
.github/workflows/docker-develop.yml
vendored
4
.github/workflows/docker-develop.yml
vendored
@@ -10,10 +10,10 @@ jobs:
|
|||||||
push_to_registry:
|
push_to_registry:
|
||||||
name: Push Docker image to Docker Hub
|
name: Push Docker image to Docker Hub
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == 'misskey-dev/misskey'
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3.3.0
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v3
|
uses: docker/metadata-action@v3
|
||||||
|
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3.3.0
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v3
|
uses: docker/metadata-action@v3
|
||||||
|
30
.github/workflows/lint.yml
vendored
30
.github/workflows/lint.yml
vendored
@@ -8,22 +8,26 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
yarn_install:
|
pnpm_install:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3.3.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: actions/setup-node@v3.2.0
|
- uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 7
|
||||||
|
run_install: false
|
||||||
|
- uses: actions/setup-node@v3.6.0
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 18.x
|
||||||
cache: 'yarn'
|
cache: 'pnpm'
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
- run: yarn install --immutable
|
- run: pnpm i --frozen-lockfile
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
needs: [yarn_install]
|
needs: [pnpm_install]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
@@ -33,14 +37,18 @@ jobs:
|
|||||||
- frontend
|
- frontend
|
||||||
- sw
|
- sw
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3.3.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: actions/setup-node@v3.2.0
|
- uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 7
|
||||||
|
run_install: false
|
||||||
|
- uses: actions/setup-node@v3.6.0
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 18.x
|
||||||
cache: 'yarn'
|
cache: 'pnpm'
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
- run: yarn install --immutable
|
- run: pnpm i --frozen-lockfile
|
||||||
- run: yarn workspace ${{ matrix.workspace }} run lint
|
- run: pnpm --filter ${{ matrix.workspace }} run lint
|
||||||
|
8
.github/workflows/pr-preview-deploy.yml
vendored
8
.github/workflows/pr-preview-deploy.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
github.event.client_payload.slash_command.sha != '' &&
|
github.event.client_payload.slash_command.sha != '' &&
|
||||||
contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha)
|
contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha)
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@v5
|
- uses: actions/github-script@v6.3.3
|
||||||
id: check-id
|
id: check-id
|
||||||
env:
|
env:
|
||||||
number: ${{ github.event.client_payload.pull_request.number }}
|
number: ${{ github.event.client_payload.pull_request.number }}
|
||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
|
|
||||||
return check[0].id;
|
return check[0].id;
|
||||||
|
|
||||||
- uses: actions/github-script@v5
|
- uses: actions/github-script@v6.3.3
|
||||||
env:
|
env:
|
||||||
check_id: ${{ steps.check-id.outputs.result }}
|
check_id: ${{ steps.check-id.outputs.result }}
|
||||||
details_url: ${{ github.server_url }}/${{ github.repository }}/runs/${{ github.run_id }}
|
details_url: ${{ github.server_url }}/${{ github.repository }}/runs/${{ github.run_id }}
|
||||||
@@ -53,7 +53,7 @@ jobs:
|
|||||||
|
|
||||||
# Check out merge commit
|
# Check out merge commit
|
||||||
- name: Fork based /deploy checkout
|
- name: Fork based /deploy checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3.3.0
|
||||||
with:
|
with:
|
||||||
ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge'
|
ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge'
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
timeout: 15m
|
timeout: 15m
|
||||||
|
|
||||||
# Update check run called "integration-fork"
|
# Update check run called "integration-fork"
|
||||||
- uses: actions/github-script@v5
|
- uses: actions/github-script@v6.3.3
|
||||||
id: update-check-run
|
id: update-check-run
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
env:
|
env:
|
||||||
|
41
.github/workflows/test.yml
vendored
41
.github/workflows/test.yml
vendored
@@ -23,31 +23,35 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
POSTGRES_DB: test-misskey
|
POSTGRES_DB: test-misskey
|
||||||
POSTGRES_HOST_AUTH_METHOD: trust
|
POSTGRES_HOST_AUTH_METHOD: trust
|
||||||
YARN_CHECKSUM_BEHAVIOR: update
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:6
|
image: redis:6
|
||||||
ports:
|
ports:
|
||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3.3.0
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 7
|
||||||
|
run_install: false
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v3.2.0
|
uses: actions/setup-node@v3.6.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'yarn'
|
cache: 'pnpm'
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
- run: yarn install --immutable
|
- run: pnpm i --frozen-lockfile
|
||||||
- name: Check yarn.lock
|
- name: Check pnpm-lock.yaml
|
||||||
run: git diff --exit-code yarn.lock
|
run: git diff --exit-code pnpm-lock.yaml
|
||||||
- name: Copy Configure
|
- name: Copy Configure
|
||||||
run: cp .github/misskey/test.yml .config
|
run: cp .github/misskey/test.yml .config
|
||||||
- name: Build
|
- name: Build
|
||||||
run: yarn build
|
run: pnpm build
|
||||||
- name: Test
|
- name: Test
|
||||||
run: yarn jest-and-coverage
|
run: pnpm jest-and-coverage
|
||||||
- name: Upload Coverage
|
- name: Upload Coverage
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -77,7 +81,7 @@ jobs:
|
|||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3.3.0
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
# https://github.com/cypress-io/cypress-docker-images/issues/150
|
# https://github.com/cypress-io/cypress-docker-images/issues/150
|
||||||
@@ -86,19 +90,22 @@ jobs:
|
|||||||
# if: ${{ matrix.browser == 'firefox' }}
|
# if: ${{ matrix.browser == 'firefox' }}
|
||||||
#- uses: browser-actions/setup-firefox@latest
|
#- uses: browser-actions/setup-firefox@latest
|
||||||
# if: ${{ matrix.browser == 'firefox' }}
|
# if: ${{ matrix.browser == 'firefox' }}
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 7
|
||||||
|
run_install: false
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v3.2.0
|
uses: actions/setup-node@v3.6.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'yarn'
|
cache: 'pnpm'
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
- run: yarn install --immutable
|
- run: pnpm i --frozen-lockfile
|
||||||
env:
|
|
||||||
YARN_CHECKSUM_BEHAVIOR: update
|
|
||||||
- name: Copy Configure
|
- name: Copy Configure
|
||||||
run: cp .github/misskey/test.yml .config
|
run: cp .github/misskey/test.yml .config
|
||||||
- name: Build
|
- name: Build
|
||||||
run: yarn build
|
run: pnpm build
|
||||||
# https://github.com/cypress-io/cypress/issues/4351#issuecomment-559489091
|
# https://github.com/cypress-io/cypress/issues/4351#issuecomment-559489091
|
||||||
- name: ALSA Env
|
- name: ALSA Env
|
||||||
run: echo -e 'pcm.!default {\n type hw\n card 0\n}\n\nctl.!default {\n type hw\n card 0\n}' > ~/.asoundrc
|
run: echo -e 'pcm.!default {\n type hw\n card 0\n}\n\nctl.!default {\n type hw\n card 0\n}' > ~/.asoundrc
|
||||||
@@ -106,7 +113,7 @@ jobs:
|
|||||||
uses: cypress-io/github-action@v4
|
uses: cypress-io/github-action@v4
|
||||||
with:
|
with:
|
||||||
install: false
|
install: false
|
||||||
start: yarn start:test
|
start: pnpm start:test
|
||||||
wait-on: 'http://localhost:61812'
|
wait-on: 'http://localhost:61812'
|
||||||
headless: false
|
headless: false
|
||||||
browser: ${{ matrix.browser }}
|
browser: ${{ matrix.browser }}
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -30,6 +30,7 @@ coverage
|
|||||||
# config
|
# config
|
||||||
/.config/*
|
/.config/*
|
||||||
!/.config/example.yml
|
!/.config/example.yml
|
||||||
|
!/.config/docker_example.yml
|
||||||
!/.config/docker_example.env
|
!/.config/docker_example.env
|
||||||
|
|
||||||
# misskey
|
# misskey
|
||||||
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"search.exclude": {
|
||||||
|
"**/node_modules": true
|
||||||
|
}
|
||||||
|
}
|
546
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
546
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
807
.yarn/releases/yarn-3.3.0.cjs
vendored
807
.yarn/releases/yarn-3.3.0.cjs
vendored
File diff suppressed because one or more lines are too long
42
.yarnrc.yml
42
.yarnrc.yml
@@ -1,42 +0,0 @@
|
|||||||
httpTimeout: 600000
|
|
||||||
|
|
||||||
nmHoistingLimits: none
|
|
||||||
|
|
||||||
nodeLinker: pnpm
|
|
||||||
|
|
||||||
packageExtensions:
|
|
||||||
"@bull-board/api@*":
|
|
||||||
peerDependencies:
|
|
||||||
"@bull-board/ui": "*"
|
|
||||||
"@tensorflow/tfjs@*":
|
|
||||||
dependencies:
|
|
||||||
long: "*"
|
|
||||||
chartjs-adapter-date-fns@*:
|
|
||||||
peerDependencies:
|
|
||||||
date-fns: "*"
|
|
||||||
consolidate@*:
|
|
||||||
dependencies:
|
|
||||||
ejs: "*"
|
|
||||||
# these are needed to extend fastify types
|
|
||||||
"@fastify/accepts@*":
|
|
||||||
peerDependencies:
|
|
||||||
fastify: "*"
|
|
||||||
"@fastify/cookie@*":
|
|
||||||
peerDependencies:
|
|
||||||
fastify: "*"
|
|
||||||
"@fastify/static@*":
|
|
||||||
peerDependencies:
|
|
||||||
fastify: "*"
|
|
||||||
"@fastify/view@*":
|
|
||||||
peerDependencies:
|
|
||||||
fastify: "*"
|
|
||||||
|
|
||||||
plugins:
|
|
||||||
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
|
||||||
spec: "@yarnpkg/plugin-interactive-tools"
|
|
||||||
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
|
|
||||||
spec: "@yarnpkg/plugin-workspace-tools"
|
|
||||||
|
|
||||||
progressBarStyle: patrick
|
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-3.3.0.cjs
|
|
@@ -31,8 +31,7 @@ You should also include the user name that made the change.
|
|||||||
- Misskey not using 15 specific features at 13.0.0, but may do so in the future.
|
- Misskey not using 15 specific features at 13.0.0, but may do so in the future.
|
||||||
- Elasticsearchのサポートが削除されました
|
- Elasticsearchのサポートが削除されました
|
||||||
- 代わりに今後任意の検索プロバイダを設定できる仕組みを構想しています。その仕組みを使えば今まで通りElasticsearchも利用できます
|
- 代わりに今後任意の検索プロバイダを設定できる仕組みを構想しています。その仕組みを使えば今まで通りElasticsearchも利用できます
|
||||||
- Migrate to Yarn Berry (v3.2.1) @ThatOneCalculator
|
- Yarnからpnpmに移行されました
|
||||||
- You may have to `yarn run clean-all`, `sudo corepack enable` and `yarn set version berry` before running `yarn install` if you're still on yarn classic
|
|
||||||
- インスタンスブロックはサブドメインにも適用されるようになります
|
- インスタンスブロックはサブドメインにも適用されるようになります
|
||||||
- ロールの導入に伴い、いくつかの機能がロールと統合されました
|
- ロールの導入に伴い、いくつかの機能がロールと統合されました
|
||||||
- モデレーターはロールに統合されました。今までのモデレーター情報は失われるため、予めモデレーター一覧を記録しておき、アップデート後にモデレーターロールを作りアサインし直してください。
|
- モデレーターはロールに統合されました。今までのモデレーター情報は失われるため、予めモデレーター一覧を記録しておき、アップデート後にモデレーターロールを作りアサインし直してください。
|
||||||
@@ -64,6 +63,7 @@ You should also include the user name that made the change.
|
|||||||
- API: `user`および`note`エンティティに`emojis`プロパティが含まれなくなりました
|
- API: `user`および`note`エンティティに`emojis`プロパティが含まれなくなりました
|
||||||
- API: `user`エンティティに`avatarColor`および`bannerColor`プロパティが含まれなくなりました
|
- API: `user`エンティティに`avatarColor`および`bannerColor`プロパティが含まれなくなりました
|
||||||
- API: `instance`エンティティに`latestStatus`、`lastCommunicatedAt`、`latestRequestSentAt`プロパティが含まれなくなりました
|
- API: `instance`エンティティに`latestStatus`、`lastCommunicatedAt`、`latestRequestSentAt`プロパティが含まれなくなりました
|
||||||
|
- API: `instance`エンティティの`caughtAt`は`firstRetrievedAt`に名前が変わりました
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
- Role system @syuilo
|
- Role system @syuilo
|
||||||
@@ -74,6 +74,7 @@ You should also include the user name that made the change.
|
|||||||
- Push notification of Antenna note @tamaina
|
- Push notification of Antenna note @tamaina
|
||||||
- AVIF support @tamaina
|
- AVIF support @tamaina
|
||||||
- Add Cloudflare Turnstile CAPTCHA support @CyberRex0
|
- Add Cloudflare Turnstile CAPTCHA support @CyberRex0
|
||||||
|
- レートリミットをユーザーごとに調整可能に @syuilo
|
||||||
- 非モデレーターでも、権限を持つロールをアサインされたユーザーはインスタンスの招待コードを発行できるように @syuilo
|
- 非モデレーターでも、権限を持つロールをアサインされたユーザーはインスタンスの招待コードを発行できるように @syuilo
|
||||||
- 非モデレーターでも、権限を持つロールをアサインされたユーザーはカスタム絵文字の追加、編集、削除を行えるように @syuilo
|
- 非モデレーターでも、権限を持つロールをアサインされたユーザーはカスタム絵文字の追加、編集、削除を行えるように @syuilo
|
||||||
- クリップおよびクリップ内のノートの作成可能数を設定可能に @syuilo
|
- クリップおよびクリップ内のノートの作成可能数を設定可能に @syuilo
|
||||||
@@ -87,6 +88,7 @@ You should also include the user name that made the change.
|
|||||||
- Server: Judge instance block by endsWith @tamaina
|
- Server: Judge instance block by endsWith @tamaina
|
||||||
- Server: improve note scoring for featured notes @CyberRex0
|
- Server: improve note scoring for featured notes @CyberRex0
|
||||||
- Server: アンケート選択肢の文字数制限を緩和 @syuilo
|
- Server: アンケート選択肢の文字数制限を緩和 @syuilo
|
||||||
|
- Server: プロフィールの文字数制限を緩和 @syuilo
|
||||||
- Server: add rate limits for some endpoints @syuilo
|
- Server: add rate limits for some endpoints @syuilo
|
||||||
- Server: improve stats api performance @syuilo
|
- Server: improve stats api performance @syuilo
|
||||||
- Server: improve nodeinfo performance @syuilo
|
- Server: improve nodeinfo performance @syuilo
|
||||||
@@ -99,6 +101,7 @@ You should also include the user name that made the change.
|
|||||||
- Client: Add link to user RSS feed in profile menu @ssmucny
|
- Client: Add link to user RSS feed in profile menu @ssmucny
|
||||||
- Client: Compress non-animated PNG files @saschanaz
|
- Client: Compress non-animated PNG files @saschanaz
|
||||||
- Client: YouTube window player @sim1222
|
- Client: YouTube window player @sim1222
|
||||||
|
- Client: show readable error when rate limit exceeded @syuilo
|
||||||
- Client: enhance dashboard of control panel @syuilo
|
- Client: enhance dashboard of control panel @syuilo
|
||||||
- Client: Vite is upgraded to v4 @syuilo, @tamaina
|
- Client: Vite is upgraded to v4 @syuilo, @tamaina
|
||||||
- Client: HMR is available while yarn dev @tamaina
|
- Client: HMR is available while yarn dev @tamaina
|
||||||
|
2
COPYING
2
COPYING
@@ -1,5 +1,5 @@
|
|||||||
Unless otherwise stated this repository is
|
Unless otherwise stated this repository is
|
||||||
Copyright © 2014-2022 syuilo and contributers
|
Copyright © 2014-2023 syuilo and contributers
|
||||||
|
|
||||||
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
|
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
|
||||||
|
|
||||||
|
17
Dockerfile
17
Dockerfile
@@ -2,27 +2,27 @@ ARG NODE_VERSION=18.13.0-bullseye
|
|||||||
|
|
||||||
FROM node:${NODE_VERSION} AS builder
|
FROM node:${NODE_VERSION} AS builder
|
||||||
|
|
||||||
ARG NODE_ENV=production
|
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
build-essential
|
build-essential
|
||||||
|
|
||||||
WORKDIR /misskey
|
WORKDIR /misskey
|
||||||
|
|
||||||
COPY [".yarnrc.yml", "package.json", "yarn.lock", "./"]
|
COPY ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
|
||||||
COPY [".yarn", "./.yarn"]
|
|
||||||
COPY ["scripts", "./scripts"]
|
COPY ["scripts", "./scripts"]
|
||||||
COPY ["packages/backend/package.json", "./packages/backend/"]
|
COPY ["packages/backend/package.json", "./packages/backend/"]
|
||||||
COPY ["packages/frontend/package.json", "./packages/frontend/"]
|
COPY ["packages/frontend/package.json", "./packages/frontend/"]
|
||||||
COPY ["packages/sw/package.json", "./packages/sw/"]
|
COPY ["packages/sw/package.json", "./packages/sw/"]
|
||||||
|
|
||||||
RUN yarn install --immutable
|
RUN npm i -g pnpm
|
||||||
|
RUN pnpm i --frozen-lockfile
|
||||||
|
|
||||||
COPY . ./
|
COPY . ./
|
||||||
|
|
||||||
|
ARG NODE_ENV=production
|
||||||
|
|
||||||
RUN git submodule update --init
|
RUN git submodule update --init
|
||||||
RUN yarn build
|
RUN pnpm build
|
||||||
|
|
||||||
FROM node:${NODE_VERSION}-slim AS runner
|
FROM node:${NODE_VERSION}-slim AS runner
|
||||||
|
|
||||||
@@ -37,17 +37,18 @@ RUN apt-get update \
|
|||||||
&& groupadd -g "${GID}" misskey \
|
&& groupadd -g "${GID}" misskey \
|
||||||
&& useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey
|
&& useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey
|
||||||
|
|
||||||
|
RUN npm i -g pnpm
|
||||||
USER misskey
|
USER misskey
|
||||||
WORKDIR /misskey
|
WORKDIR /misskey
|
||||||
|
|
||||||
COPY --chown=misskey:misskey --from=builder /misskey/.yarn/install-state.gz ./.yarn/install-state.gz
|
|
||||||
COPY --chown=misskey:misskey --from=builder /misskey/node_modules ./node_modules
|
COPY --chown=misskey:misskey --from=builder /misskey/node_modules ./node_modules
|
||||||
COPY --chown=misskey:misskey --from=builder /misskey/built ./built
|
COPY --chown=misskey:misskey --from=builder /misskey/built ./built
|
||||||
COPY --chown=misskey:misskey --from=builder /misskey/packages/backend/node_modules ./packages/backend/node_modules
|
COPY --chown=misskey:misskey --from=builder /misskey/packages/backend/node_modules ./packages/backend/node_modules
|
||||||
COPY --chown=misskey:misskey --from=builder /misskey/packages/backend/built ./packages/backend/built
|
COPY --chown=misskey:misskey --from=builder /misskey/packages/backend/built ./packages/backend/built
|
||||||
COPY --chown=misskey:misskey --from=builder /misskey/packages/frontend/node_modules ./packages/frontend/node_modules
|
COPY --chown=misskey:misskey --from=builder /misskey/packages/frontend/node_modules ./packages/frontend/node_modules
|
||||||
|
COPY --chown=misskey:misskey --from=builder /misskey/fluent-emojis /misskey/fluent-emojis
|
||||||
COPY --chown=misskey:misskey . ./
|
COPY --chown=misskey:misskey . ./
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||||
CMD ["yarn", "run", "migrateandstart"]
|
CMD ["pnpm", "run", "migrateandstart"]
|
||||||
|
@@ -39,7 +39,7 @@ describe('After user signed in', () => {
|
|||||||
cy.get('.mk-widget-select select').select(widgetName, { force: true });
|
cy.get('.mk-widget-select select').select(widgetName, { force: true });
|
||||||
cy.get('.data-cy-bg._modalBg.data-cy-transparent').click({ multiple: true, force: true });
|
cy.get('.data-cy-bg._modalBg.data-cy-transparent').click({ multiple: true, force: true });
|
||||||
cy.get('.mk-widget-add').click({ force: true });
|
cy.get('.mk-widget-add').click({ force: true });
|
||||||
cy.get(`.mkw-${widgetName}`).should('exist');
|
cy.get(`.data-cy-mkw-${widgetName}`).should('exist');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,7 +44,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./db:/var/lib/postgresql/data
|
- ./db:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: "pg_isready"
|
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
|
||||||
interval: 5s
|
interval: 5s
|
||||||
retries: 20
|
retries: 20
|
||||||
|
|
||||||
|
@@ -818,6 +818,12 @@ cannotLoad: "تعذر التحميل"
|
|||||||
like: "أعجبني"
|
like: "أعجبني"
|
||||||
show: "المظهر"
|
show: "المظهر"
|
||||||
color: "اللون"
|
color: "اللون"
|
||||||
|
_role:
|
||||||
|
priority: "الأولوية"
|
||||||
|
_priority:
|
||||||
|
low: "منخفضة"
|
||||||
|
middle: "متوسط"
|
||||||
|
high: "عالية"
|
||||||
_emailUnavailable:
|
_emailUnavailable:
|
||||||
used: "هذا البريد الإلكتروني مستخدم"
|
used: "هذا البريد الإلكتروني مستخدم"
|
||||||
format: "صيغة البريد الإلكتروني غير صالحة"
|
format: "صيغة البريد الإلكتروني غير صالحة"
|
||||||
|
@@ -854,6 +854,12 @@ account: "অ্যাকাউন্টগুলি"
|
|||||||
like: "পছন্দ করা"
|
like: "পছন্দ করা"
|
||||||
show: "প্রদর্শন"
|
show: "প্রদর্শন"
|
||||||
color: "রং"
|
color: "রং"
|
||||||
|
_role:
|
||||||
|
priority: "অগ্রাধিকার"
|
||||||
|
_priority:
|
||||||
|
low: "নিম্ন"
|
||||||
|
middle: "মাঝারি"
|
||||||
|
high: "উচ্চ"
|
||||||
_emailUnavailable:
|
_emailUnavailable:
|
||||||
used: "এই ইমেইল ঠিকানাটি ইতোমধ্যে ব্যবহৃত হয়েছে"
|
used: "এই ইমেইল ঠিকানাটি ইতোমধ্যে ব্যবহৃত হয়েছে"
|
||||||
format: "এই ইমেল ঠিকানাটি সঠিকভাবে লিখা হয়নি"
|
format: "এই ইমেল ঠিকানাটি সঠিকভাবে লিখা হয়নি"
|
||||||
|
@@ -612,6 +612,12 @@ fast: "Rychlá"
|
|||||||
account: "Účty"
|
account: "Účty"
|
||||||
show: "Zobrazit"
|
show: "Zobrazit"
|
||||||
color: "Barva"
|
color: "Barva"
|
||||||
|
_role:
|
||||||
|
priority: "Priorita"
|
||||||
|
_priority:
|
||||||
|
low: "Nízká"
|
||||||
|
middle: "Střední"
|
||||||
|
high: "Vysoká"
|
||||||
_ad:
|
_ad:
|
||||||
back: "Zpět"
|
back: "Zpět"
|
||||||
_gallery:
|
_gallery:
|
||||||
|
@@ -933,6 +933,8 @@ unassign: "Entfernen"
|
|||||||
color: "Farbe"
|
color: "Farbe"
|
||||||
manageCustomEmojis: "Benutzerdefinierte Emojis verwalten"
|
manageCustomEmojis: "Benutzerdefinierte Emojis verwalten"
|
||||||
youCannotCreateAnymore: "Du hast das Erstellungslimit erreicht."
|
youCannotCreateAnymore: "Du hast das Erstellungslimit erreicht."
|
||||||
|
cannotPerformTemporary: "Vorübergehend nicht verfügbar"
|
||||||
|
cannotPerformTemporaryDescription: "Diese Aktion ist wegen des Überschreitenes des Ausführungslimits temporär nicht verfügbar. Bitte versuche es nach einiger Zeit erneut."
|
||||||
_role:
|
_role:
|
||||||
new: "Rolle erstellen"
|
new: "Rolle erstellen"
|
||||||
edit: "Rolle bearbeiten"
|
edit: "Rolle bearbeiten"
|
||||||
@@ -949,11 +951,17 @@ _role:
|
|||||||
isPublic: "Öffentliche Rolle"
|
isPublic: "Öffentliche Rolle"
|
||||||
descriptionOfIsPublic: "Ist dies aktiviert, so kann jeder die Liste der Benutzer, die dieser Rolle zugewiesen sind, einsehen. Zusätzlich wird diese Rolle im Profil zugewiesener Benutzer angezeigt."
|
descriptionOfIsPublic: "Ist dies aktiviert, so kann jeder die Liste der Benutzer, die dieser Rolle zugewiesen sind, einsehen. Zusätzlich wird diese Rolle im Profil zugewiesener Benutzer angezeigt."
|
||||||
options: "Optionen"
|
options: "Optionen"
|
||||||
|
policies: "Richtlinien"
|
||||||
baseRole: "Rollenvorlage"
|
baseRole: "Rollenvorlage"
|
||||||
useBaseValue: "Wert der Rollenvorlage verwenden"
|
useBaseValue: "Wert der Rollenvorlage verwenden"
|
||||||
chooseRoleToAssign: "Zuzuweisende Rolle auswählen"
|
chooseRoleToAssign: "Zuzuweisende Rolle auswählen"
|
||||||
canEditMembersByModerator: "Moderatoren können Benutzern diese Rolle zuweisen"
|
canEditMembersByModerator: "Moderatoren können Benutzern diese Rolle zuweisen"
|
||||||
descriptionOfCanEditMembersByModerator: "Wenn aktiviert, so können Moderatoren und Adminstratoren anderen Benutzern diese Rolle zuweisen bzw. diese Zuweisung aufheben. Wenn deaktiviert, so ist es nur Administratoren möglich, Zuweisungen dieser Rolle zu verwalten."
|
descriptionOfCanEditMembersByModerator: "Wenn aktiviert, so können Moderatoren und Adminstratoren anderen Benutzern diese Rolle zuweisen bzw. diese Zuweisung aufheben. Wenn deaktiviert, so ist es nur Administratoren möglich, Zuweisungen dieser Rolle zu verwalten."
|
||||||
|
priority: "Priorität"
|
||||||
|
_priority:
|
||||||
|
low: "Niedrig"
|
||||||
|
middle: "Mittel"
|
||||||
|
high: "Hoch"
|
||||||
_options:
|
_options:
|
||||||
gtlAvailable: "Kann auf die globale Chronik zugreifen"
|
gtlAvailable: "Kann auf die globale Chronik zugreifen"
|
||||||
ltlAvailable: "Kann auf die lokale Chronik zugreifen"
|
ltlAvailable: "Kann auf die lokale Chronik zugreifen"
|
||||||
@@ -969,6 +977,8 @@ _role:
|
|||||||
noteEachClipsMax: "Maximale Anzahl an Notizen innerhalb eines Clips"
|
noteEachClipsMax: "Maximale Anzahl an Notizen innerhalb eines Clips"
|
||||||
userListMax: "Maximale Anzahl an Benutzern in einer Benutzerliste"
|
userListMax: "Maximale Anzahl an Benutzern in einer Benutzerliste"
|
||||||
userEachUserListsMax: "Maximale Anzahl an Benutzerlisten"
|
userEachUserListsMax: "Maximale Anzahl an Benutzerlisten"
|
||||||
|
rateLimitFactor: "Versuchsanzahl"
|
||||||
|
descriptionOfRateLimitFactor: "Je niedriger desto weniger restriktiv, je höher destro restriktiver."
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "Lokaler Benutzer"
|
isLocal: "Lokaler Benutzer"
|
||||||
isRemote: "Benutzer fremder Instanz"
|
isRemote: "Benutzer fremder Instanz"
|
||||||
|
@@ -933,6 +933,8 @@ unassign: "Unassign"
|
|||||||
color: "Color"
|
color: "Color"
|
||||||
manageCustomEmojis: "Manage Custom Emojis"
|
manageCustomEmojis: "Manage Custom Emojis"
|
||||||
youCannotCreateAnymore: "You've hit the creation limit."
|
youCannotCreateAnymore: "You've hit the creation limit."
|
||||||
|
cannotPerformTemporary: "Temporarily unavailable"
|
||||||
|
cannotPerformTemporaryDescription: "This action cannot be performed temporarily due to exceeding the execution limit. Please wait for a while and then try again."
|
||||||
_role:
|
_role:
|
||||||
new: "New role"
|
new: "New role"
|
||||||
edit: "Edit role"
|
edit: "Edit role"
|
||||||
@@ -949,11 +951,17 @@ _role:
|
|||||||
isPublic: "Public role"
|
isPublic: "Public role"
|
||||||
descriptionOfIsPublic: "Anyone will be able to view a list of users assigned to this role. In addition, this role will be displayed in the profiles of assigned users."
|
descriptionOfIsPublic: "Anyone will be able to view a list of users assigned to this role. In addition, this role will be displayed in the profiles of assigned users."
|
||||||
options: "Role options"
|
options: "Role options"
|
||||||
|
policies: "Policies"
|
||||||
baseRole: "Base role"
|
baseRole: "Base role"
|
||||||
useBaseValue: "Use base role value"
|
useBaseValue: "Use base role value"
|
||||||
chooseRoleToAssign: "Select the role to assign"
|
chooseRoleToAssign: "Select the role to assign"
|
||||||
canEditMembersByModerator: "Allow moderators to edit the list members of this role"
|
canEditMembersByModerator: "Allow moderators to edit the list members of this role"
|
||||||
descriptionOfCanEditMembersByModerator: "When turned on, moderators as well as administrators will be able to assign and unassign users to this role. When turned off, only administrators will be able to assign users."
|
descriptionOfCanEditMembersByModerator: "When turned on, moderators as well as administrators will be able to assign and unassign users to this role. When turned off, only administrators will be able to assign users."
|
||||||
|
priority: "Priority"
|
||||||
|
_priority:
|
||||||
|
low: "Low"
|
||||||
|
middle: "Medium"
|
||||||
|
high: "High"
|
||||||
_options:
|
_options:
|
||||||
gtlAvailable: "Viewing the global timeline"
|
gtlAvailable: "Viewing the global timeline"
|
||||||
ltlAvailable: "Viewing the local timeline"
|
ltlAvailable: "Viewing the local timeline"
|
||||||
@@ -969,6 +977,8 @@ _role:
|
|||||||
noteEachClipsMax: "Maximum number of notes within a clip"
|
noteEachClipsMax: "Maximum number of notes within a clip"
|
||||||
userListMax: "Maximum number of user lists"
|
userListMax: "Maximum number of user lists"
|
||||||
userEachUserListsMax: "Maximum number of users within a user list"
|
userEachUserListsMax: "Maximum number of users within a user list"
|
||||||
|
rateLimitFactor: "Rate limit"
|
||||||
|
descriptionOfRateLimitFactor: "Lower rate limits are less restrictive, higher ones more restrictive. "
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "Local user"
|
isLocal: "Local user"
|
||||||
isRemote: "Remote user"
|
isRemote: "Remote user"
|
||||||
|
@@ -919,6 +919,12 @@ numberOfProfileView: "Número de vistas de perfil"
|
|||||||
like: "¡Muy bien!"
|
like: "¡Muy bien!"
|
||||||
show: "Apariencia"
|
show: "Apariencia"
|
||||||
color: "Color"
|
color: "Color"
|
||||||
|
_role:
|
||||||
|
priority: "Prioridad"
|
||||||
|
_priority:
|
||||||
|
low: "Baja"
|
||||||
|
middle: "Mediano"
|
||||||
|
high: "Alta"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Reduce el esfuerzo de la moderación el el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor."
|
description: "Reduce el esfuerzo de la moderación el el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor."
|
||||||
sensitivity: "Sensibilidad de detección"
|
sensitivity: "Sensibilidad de detección"
|
||||||
|
@@ -916,6 +916,12 @@ show: "Affichage"
|
|||||||
neverShow: "Ne plus afficher"
|
neverShow: "Ne plus afficher"
|
||||||
remindMeLater: "Peut-être plus tard"
|
remindMeLater: "Peut-être plus tard"
|
||||||
color: "Couleur"
|
color: "Couleur"
|
||||||
|
_role:
|
||||||
|
priority: "Priorité"
|
||||||
|
_priority:
|
||||||
|
low: "Basse"
|
||||||
|
middle: "Moyen"
|
||||||
|
high: "Haute"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "L'apprentissage automatique peut être utilisé pour détecter automatiquement les médias sensibles à modérer. La sollicitation des serveurs augmente légèrement."
|
description: "L'apprentissage automatique peut être utilisé pour détecter automatiquement les médias sensibles à modérer. La sollicitation des serveurs augmente légèrement."
|
||||||
sensitivity: "Sensibilité de la détection"
|
sensitivity: "Sensibilité de la détection"
|
||||||
|
@@ -860,6 +860,12 @@ unlike: "Tidak Suka"
|
|||||||
numberOfLikes: "Jumlah yang disukai"
|
numberOfLikes: "Jumlah yang disukai"
|
||||||
show: "Tampilkan"
|
show: "Tampilkan"
|
||||||
color: "Warna"
|
color: "Warna"
|
||||||
|
_role:
|
||||||
|
priority: "Prioritas"
|
||||||
|
_priority:
|
||||||
|
low: "Rendah"
|
||||||
|
middle: "Sedang"
|
||||||
|
high: "Tinggi"
|
||||||
_emailUnavailable:
|
_emailUnavailable:
|
||||||
used: "Alamat surel ini telah digunakan"
|
used: "Alamat surel ini telah digunakan"
|
||||||
format: "Format tidak valid."
|
format: "Format tidak valid."
|
||||||
|
@@ -8,7 +8,7 @@ search: "Cerca"
|
|||||||
notifications: "Notifiche"
|
notifications: "Notifiche"
|
||||||
username: "Nome utente"
|
username: "Nome utente"
|
||||||
password: "Password"
|
password: "Password"
|
||||||
forgotPassword: "Hai dimenticato la tua password?"
|
forgotPassword: "Hai dimenticato la password?"
|
||||||
fetchingAsApObject: "Recuperando dal Fediverso..."
|
fetchingAsApObject: "Recuperando dal Fediverso..."
|
||||||
ok: "OK"
|
ok: "OK"
|
||||||
gotIt: "Ho capito"
|
gotIt: "Ho capito"
|
||||||
@@ -325,7 +325,7 @@ connectService: "Connessione"
|
|||||||
disconnectService: "Disconnessione "
|
disconnectService: "Disconnessione "
|
||||||
enableLocalTimeline: "Abilita Timeline locale"
|
enableLocalTimeline: "Abilita Timeline locale"
|
||||||
enableGlobalTimeline: "Abilita Timeline federata"
|
enableGlobalTimeline: "Abilita Timeline federata"
|
||||||
disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori e i moderatori potranno sempre accederci."
|
disablingTimelinesInfo: "Anche disabilitandole, gli Amministratori e i Moderatori potranno comunque accedervi."
|
||||||
registration: "Iscriviti"
|
registration: "Iscriviti"
|
||||||
enableRegistration: "Permettere nuove registrazioni"
|
enableRegistration: "Permettere nuove registrazioni"
|
||||||
invite: "Invita"
|
invite: "Invita"
|
||||||
@@ -932,27 +932,35 @@ assign: "Assegna"
|
|||||||
unassign: "Disassegna"
|
unassign: "Disassegna"
|
||||||
color: "Colore"
|
color: "Colore"
|
||||||
manageCustomEmojis: "Gestisci le emoji personalizzate"
|
manageCustomEmojis: "Gestisci le emoji personalizzate"
|
||||||
|
youCannotCreateAnymore: "Non puoi creare, hai raggiunto il limite."
|
||||||
|
cannotPerformTemporary: "Indisponibilità temporanea"
|
||||||
|
cannotPerformTemporaryDescription: "L'attività non può essere svolta, poiché si è raggiunto il limite di esecuzioni possibili. Per favore, riprova più tardi."
|
||||||
_role:
|
_role:
|
||||||
new: "Nuovo ruolo"
|
new: "Nuovo ruolo"
|
||||||
edit: "Modifica ruolo"
|
edit: "Modifica ruolo"
|
||||||
name: "Nome del ruolo"
|
name: "Nome del ruolo"
|
||||||
description: "Descrizione del ruolo"
|
description: "Descrizione del ruolo"
|
||||||
permission: "Permessi del ruolo"
|
permission: "Permessi globali del ruolo"
|
||||||
descriptionOfPermission: "<b>Moderatori</b> possono svolgere le attività di moderazione basilari.\n<b>Amministratori</b> possono modificare la configurazione dell'istanza."
|
descriptionOfPermission: "<b>Moderatori</b> possono svolgere le attività di moderazione basilari.\n<b>Amministratori</b> possono modificare la configurazione dell'istanza."
|
||||||
assignTarget: "Assegna il target"
|
assignTarget: "Modalità di assegnazione del ruolo"
|
||||||
descriptionOfAssignTarget: "<b>Manuale</b> per assegnare manualmente questo ruolo ai profili.\n<b>Condizionale</b> per assegnare o rimuovere automaticamente questo ruolo ai profili, secondo determinate condizioni."
|
descriptionOfAssignTarget: "<b>Manuale</b>: per assegnare manualmente questo ruolo ai profili.\n<b>Condizionale</b>: per assegnare o rimuovere automaticamente questo ruolo ai profili, a precise condizioni."
|
||||||
manual: "Manuale"
|
manual: "Manuale"
|
||||||
conditional: "Condizionale"
|
conditional: "Condizionale"
|
||||||
condition: "Condizioni"
|
condition: "Condizioni"
|
||||||
isConditionalRole: "Questo è un ruolo condizionato"
|
isConditionalRole: "Questo è un ruolo condizionato"
|
||||||
isPublic: "Ruolo pubblico"
|
isPublic: "Ruolo pubblico"
|
||||||
descriptionOfIsPublic: "La lista di profili assegnati a questo ruolo è visibile a chiunque. Inoltre, il ruolo verrà mostrato nei relativi profili."
|
descriptionOfIsPublic: "La lista di profili assegnati a questo ruolo è visibile a chiunque. Inoltre, il nome del ruolo verrà mostrato pubblicamente nei relativi profili."
|
||||||
options: "Opzioni del ruolo"
|
options: "Opzioni del ruolo"
|
||||||
baseRole: "Ruolo di base"
|
baseRole: "Ruolo di base"
|
||||||
useBaseValue: "Eredita dal ruolo base"
|
useBaseValue: "Eredita dal ruolo base"
|
||||||
chooseRoleToAssign: "Seleziona il ruolo da assegnare"
|
chooseRoleToAssign: "Seleziona il ruolo da assegnare"
|
||||||
canEditMembersByModerator: "Consenti ai Moderatori di modificare i membri di questo ruolo"
|
canEditMembersByModerator: "Anche i Moderatori assegnano profili a questo ruolo"
|
||||||
descriptionOfCanEditMembersByModerator: "Se attivo, anche i Moderatori potranno assegnare o togliere questo ruolo. Altrimenti, se disattivo, potranno solo gli Amministratori."
|
descriptionOfCanEditMembersByModerator: "Se disattivo, potranno farlo solamente gli Amministratori."
|
||||||
|
priority: "Priorità"
|
||||||
|
_priority:
|
||||||
|
low: "Bassa"
|
||||||
|
middle: "Medio"
|
||||||
|
high: "Alta"
|
||||||
_options:
|
_options:
|
||||||
gtlAvailable: "Disponibilità della Timeline Federata"
|
gtlAvailable: "Disponibilità della Timeline Federata"
|
||||||
ltlAvailable: "Disponibilità della Timeline Locale"
|
ltlAvailable: "Disponibilità della Timeline Locale"
|
||||||
@@ -960,12 +968,25 @@ _role:
|
|||||||
canInvite: "Genera codici di invito all'istanza"
|
canInvite: "Genera codici di invito all'istanza"
|
||||||
canManageCustomEmojis: "Gestire le emoji personalizzate"
|
canManageCustomEmojis: "Gestire le emoji personalizzate"
|
||||||
driveCapacity: "Capienza del Drive"
|
driveCapacity: "Capienza del Drive"
|
||||||
antennaMax: "Numero massimo di Antenne"
|
pinMax: "Quantità massima di Note in primo piano"
|
||||||
|
antennaMax: "Quantità massima di Antenne"
|
||||||
|
wordMuteMax: "Lunghezza massima del filtro parole"
|
||||||
|
webhookMax: "Quantità massima di Webhook"
|
||||||
|
clipMax: "Quantità massima di Clip"
|
||||||
|
noteEachClipsMax: "Quantità massima di Note nella Clip"
|
||||||
|
userListMax: "Quantità massima di liste"
|
||||||
|
userEachUserListsMax: "Quantità massima di profili per lista"
|
||||||
|
rateLimitFactor: "Limite del rapporto"
|
||||||
|
descriptionOfRateLimitFactor: "I rapporti più bassi sono meno restrittivi, quelli più alti lo sono di più."
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "Profilo locale"
|
isLocal: "Profilo locale"
|
||||||
isRemote: "Profilo remoto"
|
isRemote: "Profilo remoto"
|
||||||
createdLessThan: "Creato meno di"
|
createdLessThan: "Creato meno di"
|
||||||
createdMoreThan: "Creato più di"
|
createdMoreThan: "Creato più di"
|
||||||
|
followersLessThanOrEq: "Ha meno di N follower"
|
||||||
|
followersMoreThanOrEq: "Ha più di N follower"
|
||||||
|
followingLessThanOrEq: "Segue N profili o meno"
|
||||||
|
followingMoreThanOrEq: "Segue N profili o più"
|
||||||
and: "E"
|
and: "E"
|
||||||
or: "O"
|
or: "O"
|
||||||
not: "NON"
|
not: "NON"
|
||||||
@@ -1384,7 +1405,7 @@ _cw:
|
|||||||
_poll:
|
_poll:
|
||||||
noOnlyOneChoice: "Sono necessarie almeno 2 risposte"
|
noOnlyOneChoice: "Sono necessarie almeno 2 risposte"
|
||||||
choiceN: "Opzione {n}"
|
choiceN: "Opzione {n}"
|
||||||
noMore: "Hai aggiunto il numero massimo di opzioni."
|
noMore: "Hai raggiunto il limite di opzioni."
|
||||||
canMultipleVote: "Possibilità di risposte multiple"
|
canMultipleVote: "Possibilità di risposte multiple"
|
||||||
expiration: "Scadenza"
|
expiration: "Scadenza"
|
||||||
infinite: "Non scade"
|
infinite: "Non scade"
|
||||||
|
@@ -933,6 +933,8 @@ unassign: "アサインを解除"
|
|||||||
color: "色"
|
color: "色"
|
||||||
manageCustomEmojis: "カスタム絵文字の管理"
|
manageCustomEmojis: "カスタム絵文字の管理"
|
||||||
youCannotCreateAnymore: "これ以上作成することはできません。"
|
youCannotCreateAnymore: "これ以上作成することはできません。"
|
||||||
|
cannotPerformTemporary: "一時的に利用できません"
|
||||||
|
cannotPerformTemporaryDescription: "操作回数が制限を超過するため一時的に利用できません。しばらく時間を置いてから再度お試しください。"
|
||||||
|
|
||||||
_role:
|
_role:
|
||||||
new: "ロールの作成"
|
new: "ロールの作成"
|
||||||
@@ -950,11 +952,17 @@ _role:
|
|||||||
isPublic: "ロールを公開"
|
isPublic: "ロールを公開"
|
||||||
descriptionOfIsPublic: "ロールにアサインされたユーザーを誰でも見ることができます。また、ユーザーのプロフィールでこのロールが表示されます。"
|
descriptionOfIsPublic: "ロールにアサインされたユーザーを誰でも見ることができます。また、ユーザーのプロフィールでこのロールが表示されます。"
|
||||||
options: "オプション"
|
options: "オプション"
|
||||||
|
policies: "ポリシー"
|
||||||
baseRole: "ベースロール"
|
baseRole: "ベースロール"
|
||||||
useBaseValue: "ベースロールの値を使用"
|
useBaseValue: "ベースロールの値を使用"
|
||||||
chooseRoleToAssign: "アサインするロールを選択"
|
chooseRoleToAssign: "アサインするロールを選択"
|
||||||
canEditMembersByModerator: "モデレーターのメンバー編集を許可"
|
canEditMembersByModerator: "モデレーターのメンバー編集を許可"
|
||||||
descriptionOfCanEditMembersByModerator: "オンにすると、管理者に加えてモデレーターもこのロールへユーザーをアサイン/アサイン解除できるようになります。オフにすると管理者のみが行えます。"
|
descriptionOfCanEditMembersByModerator: "オンにすると、管理者に加えてモデレーターもこのロールへユーザーをアサイン/アサイン解除できるようになります。オフにすると管理者のみが行えます。"
|
||||||
|
priority: "優先度"
|
||||||
|
_priority:
|
||||||
|
low: "低"
|
||||||
|
middle: "中"
|
||||||
|
high: "高"
|
||||||
_options:
|
_options:
|
||||||
gtlAvailable: "グローバルタイムラインの閲覧"
|
gtlAvailable: "グローバルタイムラインの閲覧"
|
||||||
ltlAvailable: "ローカルタイムラインの閲覧"
|
ltlAvailable: "ローカルタイムラインの閲覧"
|
||||||
@@ -970,6 +978,8 @@ _role:
|
|||||||
noteEachClipsMax: "クリップ内のノートの最大数"
|
noteEachClipsMax: "クリップ内のノートの最大数"
|
||||||
userListMax: "ユーザーリストの作成可能数"
|
userListMax: "ユーザーリストの作成可能数"
|
||||||
userEachUserListsMax: "ユーザーリスト内のユーザーの最大数"
|
userEachUserListsMax: "ユーザーリスト内のユーザーの最大数"
|
||||||
|
rateLimitFactor: "レートリミット"
|
||||||
|
descriptionOfRateLimitFactor: "小さいほど制限が緩和され、大きいほど制限が強化されます。"
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "ローカルユーザー"
|
isLocal: "ローカルユーザー"
|
||||||
isRemote: "リモートユーザー"
|
isRemote: "リモートユーザー"
|
||||||
|
@@ -926,29 +926,71 @@ didYouLikeMisskey: "Misskeyを気に入っとっただけましたん?"
|
|||||||
pleaseDonate: "Misskeyは{host}が使用している無料のソフトウェアやで。これからも開発を続けれるように、寄付したってな~。"
|
pleaseDonate: "Misskeyは{host}が使用している無料のソフトウェアやで。これからも開発を続けれるように、寄付したってな~。"
|
||||||
roles: "ロール"
|
roles: "ロール"
|
||||||
role: "ロール"
|
role: "ロール"
|
||||||
|
normalUser: "一般ユーザー"
|
||||||
undefined: "未定義"
|
undefined: "未定義"
|
||||||
assign: "アサイン"
|
assign: "アサイン"
|
||||||
unassign: "アサインを解除"
|
unassign: "アサインを解除"
|
||||||
color: "色"
|
color: "色"
|
||||||
|
manageCustomEmojis: "カスタム絵文字の管理"
|
||||||
|
youCannotCreateAnymore: "これ以上作れなさそうや"
|
||||||
|
cannotPerformTemporary: "一時的に利用できへんで"
|
||||||
|
cannotPerformTemporaryDescription: "操作回数が制限を超えたから一時的に利用できへんくなったで。ちょっと時間置いてからもう一回やってやー。"
|
||||||
_role:
|
_role:
|
||||||
new: "ロールの作成"
|
new: "ロールの作成"
|
||||||
edit: "ロールの編集"
|
edit: "ロールの編集"
|
||||||
name: "ロール名"
|
name: "ロール名"
|
||||||
description: "ロールの説明"
|
description: "ロールの説明"
|
||||||
|
permission: "ロールの権限"
|
||||||
|
descriptionOfPermission: "<b>モデレーター</b>は基本的なモデレーションに関わる操作を行えるで。\n<b>管理者</b>はインスタンスの全ての設定を変更できるで。"
|
||||||
|
assignTarget: "アサインターゲット"
|
||||||
|
descriptionOfAssignTarget: "<b>マニュアル</b>は誰がこのロールに含まれてるかを手動で管理するで。\n<b>コンディショナル</b>は条件を設定して、それに合うユーザーが自動で含まれるようになるで。"
|
||||||
|
manual: "マニュアル"
|
||||||
|
conditional: "コンディショナル"
|
||||||
|
condition: "条件"
|
||||||
|
isConditionalRole: "これはコンディショナルロールやで"
|
||||||
isPublic: "ロールを公開"
|
isPublic: "ロールを公開"
|
||||||
descriptionOfIsPublic: "ロールにアサインされたユーザーを誰でも見ることができるで。そんで、ユーザーのプロフィールでこのロールが表示されるで。"
|
descriptionOfIsPublic: "ロールにアサインされたユーザーを誰でも見ることができるで。そんで、ユーザーのプロフィールでこのロールが表示されるで。"
|
||||||
options: "オプション"
|
options: "オプション"
|
||||||
|
policies: "ポリシー"
|
||||||
baseRole: "ベースロール"
|
baseRole: "ベースロール"
|
||||||
useBaseValue: "ベースロールの値を使用"
|
useBaseValue: "ベースロールの値を使用"
|
||||||
chooseRoleToAssign: "アサインするロールを選択"
|
chooseRoleToAssign: "アサインするロールを選択"
|
||||||
canEditMembersByModerator: "モデレーターのメンバー編集を許可"
|
canEditMembersByModerator: "モデレーターのメンバー編集を許可"
|
||||||
descriptionOfCanEditMembersByModerator: "オンにすると、管理者に加えてモデレーターもこのロールへユーザーをアサイン/アサイン解除できるようになるで。オフにすると管理者のみが行えるで。"
|
descriptionOfCanEditMembersByModerator: "オンにすると、管理者に加えてモデレーターもこのロールへユーザーをアサイン/アサイン解除できるようになるで。オフにすると管理者のみが行えるで。"
|
||||||
|
priority: "優先度"
|
||||||
|
_priority:
|
||||||
|
low: "低い"
|
||||||
|
middle: "中"
|
||||||
|
high: "高い"
|
||||||
_options:
|
_options:
|
||||||
gtlAvailable: "グローバルタイムラインの閲覧"
|
gtlAvailable: "グローバルタイムラインの閲覧"
|
||||||
ltlAvailable: "ローカルタイムラインの閲覧"
|
ltlAvailable: "ローカルタイムラインの閲覧"
|
||||||
canPublicNote: "パブリック投稿の許可"
|
canPublicNote: "パブリック投稿の許可"
|
||||||
|
canInvite: "インスタンス招待コードの発行"
|
||||||
|
canManageCustomEmojis: "カスタム絵文字の管理"
|
||||||
driveCapacity: "ドライブ容量"
|
driveCapacity: "ドライブ容量"
|
||||||
|
pinMax: "ノートのピン留めの最大数"
|
||||||
antennaMax: "アンテナの作成可能数"
|
antennaMax: "アンテナの作成可能数"
|
||||||
|
wordMuteMax: "ワードミュートの最大文字数"
|
||||||
|
webhookMax: "Webhockの作成可能数"
|
||||||
|
clipMax: "クリップの作成可能数"
|
||||||
|
noteEachClipsMax: "クリップ内のノートの最大数"
|
||||||
|
userListMax: "ユーザーリストの作成可能数"
|
||||||
|
userEachUserListsMax: "ユーザーリスト内のユーザーの最大数"
|
||||||
|
rateLimitFactor: "レートリミット"
|
||||||
|
descriptionOfRateLimitFactor: "ちっちゃいほど制限が緩くなって、大きいほど制限されるで。"
|
||||||
|
_condition:
|
||||||
|
isLocal: "ローカルユーザー"
|
||||||
|
isRemote: "リモートユーザー"
|
||||||
|
createdLessThan: "アカウント作成から~以内"
|
||||||
|
createdMoreThan: "アカウント作成から~経過"
|
||||||
|
followersLessThanOrEq: "フォロワー数が~以下"
|
||||||
|
followersMoreThanOrEq: "フォロワー数が~以上"
|
||||||
|
followingLessThanOrEq: "フォロー数が~以下"
|
||||||
|
followingMoreThanOrEq: "フォロー数が~以上"
|
||||||
|
and: "~かつ~"
|
||||||
|
or: "~または~"
|
||||||
|
not: "~ではない"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "機械学習を使って自動でセンシティブなメディアを検出して、モデレーションに役立てることができるで。サーバーの負荷が少し増えてまうなあ。"
|
description: "機械学習を使って自動でセンシティブなメディアを検出して、モデレーションに役立てることができるで。サーバーの負荷が少し増えてまうなあ。"
|
||||||
sensitivity: "検出感度やで"
|
sensitivity: "検出感度やで"
|
||||||
|
@@ -933,6 +933,8 @@ unassign: "할당 취소"
|
|||||||
color: "색"
|
color: "색"
|
||||||
manageCustomEmojis: "커스텀 이모지 관리"
|
manageCustomEmojis: "커스텀 이모지 관리"
|
||||||
youCannotCreateAnymore: "더 이상 생성할 수 없습니다."
|
youCannotCreateAnymore: "더 이상 생성할 수 없습니다."
|
||||||
|
cannotPerformTemporary: "일시적으로 사용할 수 없음"
|
||||||
|
cannotPerformTemporaryDescription: "조작 횟수 제한을 초과하여 일시적으로 사용이 불가합니다. 잠시 후 다시 시도해 주세요."
|
||||||
_role:
|
_role:
|
||||||
new: "새 역할 생성"
|
new: "새 역할 생성"
|
||||||
edit: "역할 수정"
|
edit: "역할 수정"
|
||||||
@@ -949,11 +951,17 @@ _role:
|
|||||||
isPublic: "공개 역할"
|
isPublic: "공개 역할"
|
||||||
descriptionOfIsPublic: "역할에 할당된 사용자를 누구나 볼 수 있습니다. 또한 사용자 프로필에 이 역할이 표시됩니다."
|
descriptionOfIsPublic: "역할에 할당된 사용자를 누구나 볼 수 있습니다. 또한 사용자 프로필에 이 역할이 표시됩니다."
|
||||||
options: "옵션"
|
options: "옵션"
|
||||||
|
policies: "정책"
|
||||||
baseRole: "기본 역할"
|
baseRole: "기본 역할"
|
||||||
useBaseValue: "기본값 사용"
|
useBaseValue: "기본값 사용"
|
||||||
chooseRoleToAssign: "할당할 역할 선택"
|
chooseRoleToAssign: "할당할 역할 선택"
|
||||||
canEditMembersByModerator: "모더레이터의 역할 수정 허용"
|
canEditMembersByModerator: "모더레이터의 역할 수정 허용"
|
||||||
descriptionOfCanEditMembersByModerator: "이 옵션을 켜면 모더레이터도 이 역할에 사용자를 추가하거나 삭제할 수 있습니다. 꺼져 있으면 관리자만 가능합니다."
|
descriptionOfCanEditMembersByModerator: "이 옵션을 켜면 모더레이터도 이 역할에 사용자를 추가하거나 삭제할 수 있습니다. 꺼져 있으면 관리자만 가능합니다."
|
||||||
|
priority: "우선순위"
|
||||||
|
_priority:
|
||||||
|
low: "낮음"
|
||||||
|
middle: "보통"
|
||||||
|
high: "높음"
|
||||||
_options:
|
_options:
|
||||||
gtlAvailable: "글로벌 타임라인 보이기"
|
gtlAvailable: "글로벌 타임라인 보이기"
|
||||||
ltlAvailable: "로컬 타임라인 보이기"
|
ltlAvailable: "로컬 타임라인 보이기"
|
||||||
@@ -969,6 +977,8 @@ _role:
|
|||||||
noteEachClipsMax: "각 클립에 추가할 수 있는 노트 수"
|
noteEachClipsMax: "각 클립에 추가할 수 있는 노트 수"
|
||||||
userListMax: "생성할 수 있는 리스트 수"
|
userListMax: "생성할 수 있는 리스트 수"
|
||||||
userEachUserListsMax: "리스트당 최대 사용자 수"
|
userEachUserListsMax: "리스트당 최대 사용자 수"
|
||||||
|
rateLimitFactor: "속도 제한"
|
||||||
|
descriptionOfRateLimitFactor: "작을수록 제한이 완화되고, 클수록 제한이 강화됩니다."
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "로컬 사용자"
|
isLocal: "로컬 사용자"
|
||||||
isRemote: "리모트 사용자"
|
isRemote: "리모트 사용자"
|
||||||
|
@@ -869,6 +869,12 @@ loggedInAsBot: "Jesteś obecnie zalogowany/a jako bot"
|
|||||||
like: "Polub"
|
like: "Polub"
|
||||||
show: "Wyświetlanie"
|
show: "Wyświetlanie"
|
||||||
color: "Kolor"
|
color: "Kolor"
|
||||||
|
_role:
|
||||||
|
priority: "Priorytet"
|
||||||
|
_priority:
|
||||||
|
low: "Niski"
|
||||||
|
middle: "Średnie"
|
||||||
|
high: "Wysoki"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Zmniejsza wysiłek związany z moderacją serwera dzięki automatycznemu rozpoznawaniu zawartości NSFW za pomocą uczenia maszynowego. To nieznacznie zwiększy obciążenie serwera."
|
description: "Zmniejsza wysiłek związany z moderacją serwera dzięki automatycznemu rozpoznawaniu zawartości NSFW za pomocą uczenia maszynowego. To nieznacznie zwiększy obciążenie serwera."
|
||||||
setSensitiveFlagAutomatically: "Oznacz jako NSFW"
|
setSensitiveFlagAutomatically: "Oznacz jako NSFW"
|
||||||
|
@@ -648,6 +648,9 @@ sent: "Trimite"
|
|||||||
searchByGoogle: "Caută"
|
searchByGoogle: "Caută"
|
||||||
file: "Fișiere"
|
file: "Fișiere"
|
||||||
show: "Arată"
|
show: "Arată"
|
||||||
|
_role:
|
||||||
|
_priority:
|
||||||
|
middle: "Mediu"
|
||||||
_email:
|
_email:
|
||||||
_follow:
|
_follow:
|
||||||
title: "te-a urmărit"
|
title: "te-a urmărit"
|
||||||
|
@@ -867,6 +867,12 @@ windowRestore: "Восстановить"
|
|||||||
like: "Нравится!"
|
like: "Нравится!"
|
||||||
show: "Отображение"
|
show: "Отображение"
|
||||||
color: "Цвет"
|
color: "Цвет"
|
||||||
|
_role:
|
||||||
|
priority: "Приоритет"
|
||||||
|
_priority:
|
||||||
|
low: "Низкий"
|
||||||
|
middle: "Средне"
|
||||||
|
high: "Высокий"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Машинное обучение может быть использовано для автоматического обнаружения чувствительных медиа для модерации. Нагрузка на сервер увеличивается незначительно."
|
description: "Машинное обучение может быть использовано для автоматического обнаружения чувствительных медиа для модерации. Нагрузка на сервер увеличивается незначительно."
|
||||||
setSensitiveFlagAutomatically: "Установить флаг NSFW"
|
setSensitiveFlagAutomatically: "Установить флаг NSFW"
|
||||||
|
@@ -918,6 +918,12 @@ remindMeLater: "Pripomenúť neskôr"
|
|||||||
didYouLikeMisskey: "Páči sa vám Misskey?"
|
didYouLikeMisskey: "Páči sa vám Misskey?"
|
||||||
pleaseDonate: "Misskey je bezplatný softvér, ktorý používa {host}. Prosím, prispejte, aby sme ho mohli ďalej rozvíjať!"
|
pleaseDonate: "Misskey je bezplatný softvér, ktorý používa {host}. Prosím, prispejte, aby sme ho mohli ďalej rozvíjať!"
|
||||||
color: "Farba"
|
color: "Farba"
|
||||||
|
_role:
|
||||||
|
priority: "Priorita"
|
||||||
|
_priority:
|
||||||
|
low: "Málo"
|
||||||
|
middle: "Stredné"
|
||||||
|
high: "Vysoká"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Strojové učenie sa použije na automatickú detekciu citlivých médií na účely ich moderovania. Mierne sa zvýši zaťaženie servera."
|
description: "Strojové učenie sa použije na automatickú detekciu citlivých médií na účely ich moderovania. Mierne sa zvýši zaťaženie servera."
|
||||||
sensitivity: "Citlivosť detekcie"
|
sensitivity: "Citlivosť detekcie"
|
||||||
|
@@ -953,6 +953,11 @@ _role:
|
|||||||
chooseRoleToAssign: "เลือกบทบาทที่ต้องการกำหนด"
|
chooseRoleToAssign: "เลือกบทบาทที่ต้องการกำหนด"
|
||||||
canEditMembersByModerator: "อนุญาตให้ผู้ดูแลแก้ไขสมาชิก"
|
canEditMembersByModerator: "อนุญาตให้ผู้ดูแลแก้ไขสมาชิก"
|
||||||
descriptionOfCanEditMembersByModerator: "เมื่อเปิดใช้ ผู้ดูแลนอกเหนือจากผู้ดูแลระบบแล้ว จะสามารถกำหนดและยกเลิกการมอบหมายบทบาทนี้ให้กับผู้ใช้ได้ เมื่อปิด เฉพาะผู้ดูแลระบบเท่านั้นที่จะสามารถกำหนดผู้ใช้ได้นะ"
|
descriptionOfCanEditMembersByModerator: "เมื่อเปิดใช้ ผู้ดูแลนอกเหนือจากผู้ดูแลระบบแล้ว จะสามารถกำหนดและยกเลิกการมอบหมายบทบาทนี้ให้กับผู้ใช้ได้ เมื่อปิด เฉพาะผู้ดูแลระบบเท่านั้นที่จะสามารถกำหนดผู้ใช้ได้นะ"
|
||||||
|
priority: "ลำดับความสำคัญ"
|
||||||
|
_priority:
|
||||||
|
low: "ต่ำ"
|
||||||
|
middle: "ปานกลาง"
|
||||||
|
high: "สูง"
|
||||||
_options:
|
_options:
|
||||||
gtlAvailable: "การดูไทม์ไลน์ทั่วโลก"
|
gtlAvailable: "การดูไทม์ไลน์ทั่วโลก"
|
||||||
ltlAvailable: "การดูไทม์ไลน์ในท้องถิ่น"
|
ltlAvailable: "การดูไทม์ไลน์ในท้องถิ่น"
|
||||||
|
@@ -895,6 +895,12 @@ caption: "Підпис"
|
|||||||
like: "Вподобати"
|
like: "Вподобати"
|
||||||
show: "Відображення"
|
show: "Відображення"
|
||||||
color: "Колір"
|
color: "Колір"
|
||||||
|
_role:
|
||||||
|
priority: "Пріоритет"
|
||||||
|
_priority:
|
||||||
|
low: "Низький"
|
||||||
|
middle: "Середній"
|
||||||
|
high: "Високий"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
sensitivity: "Чутливість детектування"
|
sensitivity: "Чутливість детектування"
|
||||||
setSensitiveFlagAutomatically: "Позначити як NSFW"
|
setSensitiveFlagAutomatically: "Позначити як NSFW"
|
||||||
|
@@ -897,6 +897,12 @@ move: "Di chuyển"
|
|||||||
like: "Thích"
|
like: "Thích"
|
||||||
show: "Hiển thị"
|
show: "Hiển thị"
|
||||||
color: "Màu sắc"
|
color: "Màu sắc"
|
||||||
|
_role:
|
||||||
|
priority: "Ưu tiên"
|
||||||
|
_priority:
|
||||||
|
low: "Thấp"
|
||||||
|
middle: "Vừa"
|
||||||
|
high: "Cao"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Giảm nỗ lực kiểm duyệt máy chủ thông qua việc tự động nhận dạng media NSFW thông qua học máy. Điều này sẽ làm tăng một chút áp lực trên máy chủ."
|
description: "Giảm nỗ lực kiểm duyệt máy chủ thông qua việc tự động nhận dạng media NSFW thông qua học máy. Điều này sẽ làm tăng một chút áp lực trên máy chủ."
|
||||||
sensitivity: "Phát hiện nhạy cảm"
|
sensitivity: "Phát hiện nhạy cảm"
|
||||||
|
@@ -933,6 +933,8 @@ unassign: "取消分配"
|
|||||||
color: "颜色"
|
color: "颜色"
|
||||||
manageCustomEmojis: "管理自定义表情符号"
|
manageCustomEmojis: "管理自定义表情符号"
|
||||||
youCannotCreateAnymore: "抱歉,您无法再创建更多了。"
|
youCannotCreateAnymore: "抱歉,您无法再创建更多了。"
|
||||||
|
cannotPerformTemporary: "暂时不可用"
|
||||||
|
cannotPerformTemporaryDescription: "因操作过于频繁,暂时不可用,请稍后再试。"
|
||||||
_role:
|
_role:
|
||||||
new: "创建角色"
|
new: "创建角色"
|
||||||
edit: "编辑角色"
|
edit: "编辑角色"
|
||||||
@@ -949,11 +951,17 @@ _role:
|
|||||||
isPublic: "角色公开"
|
isPublic: "角色公开"
|
||||||
descriptionOfIsPublic: "任何人都可以看到分配该角色的用户。而用户的个人资料也将显示该角色。"
|
descriptionOfIsPublic: "任何人都可以看到分配该角色的用户。而用户的个人资料也将显示该角色。"
|
||||||
options: "选项"
|
options: "选项"
|
||||||
|
policies: "策略"
|
||||||
baseRole: "基本角色"
|
baseRole: "基本角色"
|
||||||
useBaseValue: "使用基本角色的值"
|
useBaseValue: "使用基本角色的值"
|
||||||
chooseRoleToAssign: "选择要分配的角色"
|
chooseRoleToAssign: "选择要分配的角色"
|
||||||
canEditMembersByModerator: "允许监察者编辑成员"
|
canEditMembersByModerator: "允许监察者编辑成员"
|
||||||
descriptionOfCanEditMembersByModerator: "如果选中,监察者和管理员都能够为用户分配/取消分配角色。如果未选中,则只有管理员可以执行此操作。"
|
descriptionOfCanEditMembersByModerator: "如果选中,监察者和管理员都能够为用户分配/取消分配角色。如果未选中,则只有管理员可以执行此操作。"
|
||||||
|
priority: "优先级"
|
||||||
|
_priority:
|
||||||
|
low: "低"
|
||||||
|
middle: "中"
|
||||||
|
high: "高"
|
||||||
_options:
|
_options:
|
||||||
gtlAvailable: "查看全局时间线"
|
gtlAvailable: "查看全局时间线"
|
||||||
ltlAvailable: "查看本地时间线"
|
ltlAvailable: "查看本地时间线"
|
||||||
@@ -969,6 +977,8 @@ _role:
|
|||||||
noteEachClipsMax: "单个便签内的贴文数量限制"
|
noteEachClipsMax: "单个便签内的贴文数量限制"
|
||||||
userListMax: "用户列表创建数量限制"
|
userListMax: "用户列表创建数量限制"
|
||||||
userEachUserListsMax: "单个用户列表内用户数量限制"
|
userEachUserListsMax: "单个用户列表内用户数量限制"
|
||||||
|
rateLimitFactor: "速率限制"
|
||||||
|
descriptionOfRateLimitFactor: "值越小限制越少,值越大限制越多。"
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "是本地用户"
|
isLocal: "是本地用户"
|
||||||
isRemote: "是远程用户"
|
isRemote: "是远程用户"
|
||||||
|
@@ -932,6 +932,8 @@ assign: "指派"
|
|||||||
unassign: "取消指派"
|
unassign: "取消指派"
|
||||||
color: "顏色"
|
color: "顏色"
|
||||||
manageCustomEmojis: "管理自訂表情符號"
|
manageCustomEmojis: "管理自訂表情符號"
|
||||||
|
cannotPerformTemporary: "暫時無法進行"
|
||||||
|
cannotPerformTemporaryDescription: "由於超過操作次數限制,暫時無法進行。請過一段時間之後再嘗試。"
|
||||||
_role:
|
_role:
|
||||||
new: "建立角色"
|
new: "建立角色"
|
||||||
edit: "編輯角色"
|
edit: "編輯角色"
|
||||||
@@ -948,11 +950,17 @@ _role:
|
|||||||
isPublic: "角色為公開"
|
isPublic: "角色為公開"
|
||||||
descriptionOfIsPublic: "任何人都可以看到被指派了角色的使用者。此外,使用者的個人檔案將顯示這個角色。"
|
descriptionOfIsPublic: "任何人都可以看到被指派了角色的使用者。此外,使用者的個人檔案將顯示這個角色。"
|
||||||
options: "選項"
|
options: "選項"
|
||||||
|
policies: "政策"
|
||||||
baseRole: "基本角色"
|
baseRole: "基本角色"
|
||||||
useBaseValue: "使用基本角色的值"
|
useBaseValue: "使用基本角色的值"
|
||||||
chooseRoleToAssign: "選擇要指派的角色"
|
chooseRoleToAssign: "選擇要指派的角色"
|
||||||
canEditMembersByModerator: "允許編輯監察員的成員"
|
canEditMembersByModerator: "允許編輯監察員的成員"
|
||||||
descriptionOfCanEditMembersByModerator: "如果開啟,管理員與監察員都可以為使用者指派/解除指派該角色。如果關閉,則只有管理員可以執行。"
|
descriptionOfCanEditMembersByModerator: "如果開啟,管理員與監察員都可以為使用者指派/解除指派該角色。如果關閉,則只有管理員可以執行。"
|
||||||
|
priority: "優先級"
|
||||||
|
_priority:
|
||||||
|
low: "低"
|
||||||
|
middle: "中"
|
||||||
|
high: "高"
|
||||||
_options:
|
_options:
|
||||||
gtlAvailable: "瀏覽全域時間軸"
|
gtlAvailable: "瀏覽全域時間軸"
|
||||||
ltlAvailable: "瀏覽本地時間軸"
|
ltlAvailable: "瀏覽本地時間軸"
|
||||||
|
42
package.json
42
package.json
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "13.0.0-rc.7",
|
"version": "13.0.0-rc.10",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/misskey-dev/misskey.git"
|
"url": "https://github.com/misskey-dev/misskey.git"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@3.3.0",
|
"packageManager": "pnpm@7.24.3",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/frontend",
|
"packages/frontend",
|
||||||
"packages/backend",
|
"packages/backend",
|
||||||
@@ -15,27 +15,27 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build-pre": "node ./scripts/build-pre.js",
|
"build-pre": "node ./scripts/build-pre.js",
|
||||||
"build": "yarn build-pre && yarn workspaces foreach run build && yarn run gulp",
|
"build": "pnpm build-pre && pnpm -r build && pnpm gulp",
|
||||||
"start": "cd packages/backend && node ./built/boot/index.js",
|
"start": "cd packages/backend && node ./built/boot/index.js",
|
||||||
"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/index.js",
|
"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/index.js",
|
||||||
"init": "yarn migrate",
|
"init": "pnpm migrate",
|
||||||
"migrate": "cd packages/backend && yarn run typeorm migration:run -d ormconfig.js",
|
"migrate": "cd packages/backend && pnpm typeorm migration:run -d ormconfig.js",
|
||||||
"migrateandstart": "yarn migrate && yarn start",
|
"migrateandstart": "pnpm migrate && pnpm start",
|
||||||
"gulp": "gulp build",
|
"gulp": "pnpm exec gulp build",
|
||||||
"watch": "yarn dev",
|
"watch": "pnpm dev",
|
||||||
"dev": "node ./scripts/dev.js",
|
"dev": "node ./scripts/dev.js",
|
||||||
"lint": "yarn workspaces foreach run lint",
|
"lint": "pnpm -r lint",
|
||||||
"cy:open": "cypress open --browser --e2e --config-file=cypress.config.ts",
|
"cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts",
|
||||||
"cy:run": "cypress run",
|
"cy:run": "pnpm cypress run",
|
||||||
"e2e": "start-server-and-test start:test http://localhost:61812 cy:run",
|
"e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
|
||||||
"jest": "cd packages/backend && cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand",
|
"jest": "cd packages/backend && pnpm cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand",
|
||||||
"jest-and-coverage": "cd packages/backend && cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand",
|
"jest-and-coverage": "cd packages/backend && pnpm cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand",
|
||||||
"test": "yarn jest",
|
"test": "pnpm jest",
|
||||||
"test-and-coverage": "yarn jest-and-coverage",
|
"test-and-coverage": "pnpm jest-and-coverage",
|
||||||
"format": "gulp format",
|
"format": "pnpm exec gulp format",
|
||||||
"clean": "node ./scripts/clean.js",
|
"clean": "node ./scripts/clean.js",
|
||||||
"clean-all": "node ./scripts/clean-all.js",
|
"clean-all": "node ./scripts/clean-all.js",
|
||||||
"cleanall": "yarn clean-all"
|
"cleanall": "pnpm clean-all"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"chokidar": "^3.3.1",
|
"chokidar": "^3.3.1",
|
||||||
@@ -48,7 +48,8 @@
|
|||||||
"gulp-rename": "2.0.0",
|
"gulp-rename": "2.0.0",
|
||||||
"gulp-replace": "1.1.4",
|
"gulp-replace": "1.1.4",
|
||||||
"gulp-terser": "2.1.0",
|
"gulp-terser": "2.1.0",
|
||||||
"js-yaml": "4.1.0"
|
"js-yaml": "4.1.0",
|
||||||
|
"typescript": "4.9.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/gulp": "4.0.10",
|
"@types/gulp": "4.0.10",
|
||||||
@@ -58,8 +59,7 @@
|
|||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "12.3.0",
|
"cypress": "12.3.0",
|
||||||
"eslint": "^8.31.0",
|
"eslint": "^8.31.0",
|
||||||
"start-server-and-test": "1.15.2",
|
"start-server-and-test": "1.15.2"
|
||||||
"typescript": "4.9.4"
|
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@tensorflow/tfjs-core": "^4.2.0"
|
"@tensorflow/tfjs-core": "^4.2.0"
|
||||||
|
13
packages/backend/migration/1673783015567-Policies.js
Normal file
13
packages/backend/migration/1673783015567-Policies.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export class Policies1673783015567 {
|
||||||
|
name = 'Policies1673783015567'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "role" RENAME COLUMN "options" TO "policies"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "defaultRoleOverride" TO "policies"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "policies" TO "defaultRoleOverride"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "role" RENAME COLUMN "policies" TO "options"`);
|
||||||
|
}
|
||||||
|
}
|
11
packages/backend/migration/1673812883772-firstRetrievedAt.js
Normal file
11
packages/backend/migration/1673812883772-firstRetrievedAt.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export class firstRetrievedAt1673812883772 {
|
||||||
|
name = 'firstRetrievedAt1673812883772'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "instance" RENAME COLUMN "caughtAt" TO "firstRetrievedAt"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "instance" RENAME COLUMN "firstRetrievedAt" TO "caughtAt"`);
|
||||||
|
}
|
||||||
|
}
|
@@ -6,15 +6,15 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node ./built/index.js",
|
"start": "node ./built/index.js",
|
||||||
"start:test": "NODE_ENV=test node ./built/index.js",
|
"start:test": "NODE_ENV=test node ./built/index.js",
|
||||||
"migrate": "typeorm migration:run -d ormconfig.js",
|
"migrate": "pnpm typeorm migration:run -d ormconfig.js",
|
||||||
"build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json",
|
"build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json",
|
||||||
"watch": "node watch.mjs",
|
"watch": "node watch.mjs",
|
||||||
"lint": "tsc --noEmit && eslint --quiet \"src/**/*.ts\"",
|
"lint": "tsc --noEmit && eslint --quiet \"src/**/*.ts\"",
|
||||||
"jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand",
|
"jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand",
|
||||||
"jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand",
|
"jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand",
|
||||||
"jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache",
|
"jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache",
|
||||||
"test": "yarn jest",
|
"test": "pnpm jest",
|
||||||
"test-and-coverage": "yarn jest-and-coverage"
|
"test-and-coverage": "pnpm jest-and-coverage"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@tensorflow/tfjs": "^4.1.0",
|
"@tensorflow/tfjs": "^4.1.0",
|
||||||
@@ -116,6 +116,7 @@
|
|||||||
"tsconfig-paths": "4.1.2",
|
"tsconfig-paths": "4.1.2",
|
||||||
"twemoji-parser": "14.0.0",
|
"twemoji-parser": "14.0.0",
|
||||||
"typeorm": "0.3.11",
|
"typeorm": "0.3.11",
|
||||||
|
"typescript": "4.9.4",
|
||||||
"ulid": "2.3.0",
|
"ulid": "2.3.0",
|
||||||
"undici": "^5.15.0",
|
"undici": "^5.15.0",
|
||||||
"unzipper": "0.10.11",
|
"unzipper": "0.10.11",
|
||||||
@@ -180,7 +181,6 @@
|
|||||||
"execa": "6.1.0",
|
"execa": "6.1.0",
|
||||||
"jest": "29.3.1",
|
"jest": "29.3.1",
|
||||||
"jest-mock": "^29.3.1",
|
"jest-mock": "^29.3.1",
|
||||||
"node-fetch": "3.3.0",
|
"node-fetch": "3.3.0"
|
||||||
"typescript": "4.9.4"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -479,8 +479,8 @@ export class DriveService {
|
|||||||
if (user && !isLink) {
|
if (user && !isLink) {
|
||||||
const usage = await this.driveFileEntityService.calcDriveUsageOf(user);
|
const usage = await this.driveFileEntityService.calcDriveUsageOf(user);
|
||||||
|
|
||||||
const role = await this.roleService.getUserRoleOptions(user.id);
|
const policies = await this.roleService.getUserPolicies(user.id);
|
||||||
const driveCapacity = 1024 * 1024 * role.driveCapacityMb;
|
const driveCapacity = 1024 * 1024 * policies.driveCapacityMb;
|
||||||
this.registerLogger.debug('drive capacity override applied');
|
this.registerLogger.debug('drive capacity override applied');
|
||||||
this.registerLogger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`);
|
this.registerLogger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`);
|
||||||
|
|
||||||
|
@@ -34,7 +34,7 @@ export class FederatedInstanceService {
|
|||||||
const i = await this.instancesRepository.insert({
|
const i = await this.instancesRepository.insert({
|
||||||
id: this.idService.genId(),
|
id: this.idService.genId(),
|
||||||
host,
|
host,
|
||||||
caughtAt: new Date(),
|
firstRetrievedAt: new Date(),
|
||||||
}).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0]));
|
}).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
this.cache.set(host, i);
|
this.cache.set(host, i);
|
||||||
|
@@ -226,7 +226,7 @@ export class NoteCreateService {
|
|||||||
if (data.channel != null) data.localOnly = true;
|
if (data.channel != null) data.localOnly = true;
|
||||||
|
|
||||||
if (data.visibility === 'public' && data.channel == null) {
|
if (data.visibility === 'public' && data.channel == null) {
|
||||||
if ((await this.roleService.getUserRoleOptions(user.id)).canPublicNote === false) {
|
if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) {
|
||||||
data.visibility = 'home';
|
data.visibility = 'home';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -57,7 +57,7 @@ export class NotePiningService {
|
|||||||
|
|
||||||
const pinings = await this.userNotePiningsRepository.findBy({ userId: user.id });
|
const pinings = await this.userNotePiningsRepository.findBy({ userId: user.id });
|
||||||
|
|
||||||
if (pinings.length >= (await this.roleService.getUserRoleOptions(user.id)).pinLimit) {
|
if (pinings.length >= (await this.roleService.getUserPolicies(user.id)).pinLimit) {
|
||||||
throw new IdentifiableError('15a018eb-58e5-4da1-93be-330fcc5e4e1a', 'You can not pin notes any more.');
|
throw new IdentifiableError('15a018eb-58e5-4da1-93be-330fcc5e4e1a', 'You can not pin notes any more.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
|||||||
import { StreamMessages } from '@/server/api/stream/types.js';
|
import { StreamMessages } from '@/server/api/stream/types.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
|
||||||
export type RoleOptions = {
|
export type RolePolicies = {
|
||||||
gtlAvailable: boolean;
|
gtlAvailable: boolean;
|
||||||
ltlAvailable: boolean;
|
ltlAvailable: boolean;
|
||||||
canPublicNote: boolean;
|
canPublicNote: boolean;
|
||||||
@@ -28,9 +28,10 @@ export type RoleOptions = {
|
|||||||
noteEachClipsLimit: number;
|
noteEachClipsLimit: number;
|
||||||
userListLimit: number;
|
userListLimit: number;
|
||||||
userEachUserListsLimit: number;
|
userEachUserListsLimit: number;
|
||||||
|
rateLimitFactor: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_ROLE: RoleOptions = {
|
export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
gtlAvailable: true,
|
gtlAvailable: true,
|
||||||
ltlAvailable: true,
|
ltlAvailable: true,
|
||||||
canPublicNote: true,
|
canPublicNote: true,
|
||||||
@@ -45,6 +46,7 @@ export const DEFAULT_ROLE: RoleOptions = {
|
|||||||
noteEachClipsLimit: 200,
|
noteEachClipsLimit: 200,
|
||||||
userListLimit: 10,
|
userListLimit: 10,
|
||||||
userEachUserListsLimit: 50,
|
userEachUserListsLimit: 50,
|
||||||
|
rateLimitFactor: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -193,34 +195,44 @@ export class RoleService implements OnApplicationShutdown {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async getUserRoleOptions(userId: User['id'] | null): Promise<RoleOptions> {
|
public async getUserPolicies(userId: User['id'] | null): Promise<RolePolicies> {
|
||||||
const meta = await this.metaService.fetch();
|
const meta = await this.metaService.fetch();
|
||||||
const baseRoleOptions = { ...DEFAULT_ROLE, ...meta.defaultRoleOverride };
|
const basePolicies = { ...DEFAULT_POLICIES, ...meta.policies };
|
||||||
|
|
||||||
if (userId == null) return baseRoleOptions;
|
if (userId == null) return basePolicies;
|
||||||
|
|
||||||
const roles = await this.getUserRoles(userId);
|
const roles = await this.getUserRoles(userId);
|
||||||
|
|
||||||
function getOptionValues(option: keyof RoleOptions) {
|
function calc<T extends keyof RolePolicies>(name: T, aggregate: (values: RolePolicies[T][]) => RolePolicies[T]) {
|
||||||
if (roles.length === 0) return [baseRoleOptions[option]];
|
if (roles.length === 0) return basePolicies[name];
|
||||||
return roles.map(role => (role.options[option] && (role.options[option].useDefault !== true)) ? role.options[option].value : baseRoleOptions[option]);
|
|
||||||
|
const policies = roles.map(role => role.policies[name] ?? { priority: 0, useDefault: true });
|
||||||
|
|
||||||
|
const p2 = policies.filter(policy => policy.priority === 2);
|
||||||
|
if (p2.length > 0) return aggregate(p2.map(policy => policy.useDefault ? basePolicies[name] : policy.value));
|
||||||
|
|
||||||
|
const p1 = policies.filter(policy => policy.priority === 1);
|
||||||
|
if (p1.length > 0) return aggregate(p1.map(policy => policy.useDefault ? basePolicies[name] : policy.value));
|
||||||
|
|
||||||
|
return aggregate(policies.map(policy => policy.useDefault ? basePolicies[name] : policy.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
gtlAvailable: getOptionValues('gtlAvailable').some(x => x === true),
|
gtlAvailable: calc('gtlAvailable', vs => vs.some(v => v === true)),
|
||||||
ltlAvailable: getOptionValues('ltlAvailable').some(x => x === true),
|
ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)),
|
||||||
canPublicNote: getOptionValues('canPublicNote').some(x => x === true),
|
canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)),
|
||||||
canInvite: getOptionValues('canInvite').some(x => x === true),
|
canInvite: calc('canInvite', vs => vs.some(v => v === true)),
|
||||||
canManageCustomEmojis: getOptionValues('canManageCustomEmojis').some(x => x === true),
|
canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)),
|
||||||
driveCapacityMb: Math.max(...getOptionValues('driveCapacityMb')),
|
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
|
||||||
pinLimit: Math.max(...getOptionValues('pinLimit')),
|
pinLimit: calc('pinLimit', vs => Math.max(...vs)),
|
||||||
antennaLimit: Math.max(...getOptionValues('antennaLimit')),
|
antennaLimit: calc('antennaLimit', vs => Math.max(...vs)),
|
||||||
wordMuteLimit: Math.max(...getOptionValues('wordMuteLimit')),
|
wordMuteLimit: calc('wordMuteLimit', vs => Math.max(...vs)),
|
||||||
webhookLimit: Math.max(...getOptionValues('webhookLimit')),
|
webhookLimit: calc('webhookLimit', vs => Math.max(...vs)),
|
||||||
clipLimit: Math.max(...getOptionValues('clipLimit')),
|
clipLimit: calc('clipLimit', vs => Math.max(...vs)),
|
||||||
noteEachClipsLimit: Math.max(...getOptionValues('noteEachClipsLimit')),
|
noteEachClipsLimit: calc('noteEachClipsLimit', vs => Math.max(...vs)),
|
||||||
userListLimit: Math.max(...getOptionValues('userListLimit')),
|
userListLimit: calc('userListLimit', vs => Math.max(...vs)),
|
||||||
userEachUserListsLimit: Math.max(...getOptionValues('userEachUserListsLimit')),
|
userEachUserListsLimit: calc('userEachUserListsLimit', vs => Math.max(...vs)),
|
||||||
|
rateLimitFactor: calc('rateLimitFactor', vs => Math.max(...vs)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -35,7 +35,7 @@ export class UserListService {
|
|||||||
const currentCount = await this.userListJoiningsRepository.countBy({
|
const currentCount = await this.userListJoiningsRepository.countBy({
|
||||||
userListId: list.id,
|
userListId: list.id,
|
||||||
});
|
});
|
||||||
if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).userEachUserListsLimit) {
|
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
|
||||||
throw new Error('Too many users');
|
throw new Error('Too many users');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ export class InstanceEntityService {
|
|||||||
const meta = await this.metaService.fetch();
|
const meta = await this.metaService.fetch();
|
||||||
return {
|
return {
|
||||||
id: instance.id,
|
id: instance.id,
|
||||||
caughtAt: instance.caughtAt.toISOString(),
|
firstRetrievedAt: instance.firstRetrievedAt.toISOString(),
|
||||||
host: instance.host,
|
host: instance.host,
|
||||||
usersCount: instance.usersCount,
|
usersCount: instance.usersCount,
|
||||||
notesCount: instance.notesCount,
|
notesCount: instance.notesCount,
|
||||||
|
@@ -6,7 +6,7 @@ import type { Packed } from '@/misc/schema.js';
|
|||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import type { Role } from '@/models/entities/Role.js';
|
import type { Role } from '@/models/entities/Role.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { DEFAULT_ROLE } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -40,10 +40,11 @@ export class RoleEntityService {
|
|||||||
roleId: role.id,
|
roleId: role.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const roleOptions = { ...role.options };
|
const policies = { ...role.policies };
|
||||||
for (const [k, v] of Object.entries(DEFAULT_ROLE)) {
|
for (const [k, v] of Object.entries(DEFAULT_POLICIES)) {
|
||||||
if (roleOptions[k] == null) roleOptions[k] = {
|
if (policies[k] == null) policies[k] = {
|
||||||
useDefault: true,
|
useDefault: true,
|
||||||
|
priority: 0,
|
||||||
value: v,
|
value: v,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -61,7 +62,7 @@ export class RoleEntityService {
|
|||||||
isAdministrator: role.isAdministrator,
|
isAdministrator: role.isAdministrator,
|
||||||
isModerator: role.isModerator,
|
isModerator: role.isModerator,
|
||||||
canEditMembersByModerator: role.canEditMembersByModerator,
|
canEditMembersByModerator: role.canEditMembersByModerator,
|
||||||
options: roleOptions,
|
policies: policies,
|
||||||
usersCount: assigns.length,
|
usersCount: assigns.length,
|
||||||
...(opts.detail ? {
|
...(opts.detail ? {
|
||||||
users: this.userEntityService.packMany(assigns.map(x => x.userId), me),
|
users: this.userEntityService.packMany(assigns.map(x => x.userId), me),
|
||||||
|
@@ -423,7 +423,7 @@ export class UserEntityService implements OnModuleInit {
|
|||||||
bannerUrl: user.banner ? this.driveFileEntityService.getPublicUrl(user.banner, false) : null,
|
bannerUrl: user.banner ? this.driveFileEntityService.getPublicUrl(user.banner, false) : null,
|
||||||
bannerBlurhash: user.banner?.blurhash ?? null,
|
bannerBlurhash: user.banner?.blurhash ?? null,
|
||||||
isLocked: user.isLocked,
|
isLocked: user.isLocked,
|
||||||
isSilenced: this.roleService.getUserRoleOptions(user.id).then(r => !r.canPublicNote),
|
isSilenced: this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote),
|
||||||
isSuspended: user.isSuspended ?? falsy,
|
isSuspended: user.isSuspended ?? falsy,
|
||||||
description: profile!.description,
|
description: profile!.description,
|
||||||
location: profile!.location,
|
location: profile!.location,
|
||||||
@@ -496,7 +496,7 @@ export class UserEntityService implements OnModuleInit {
|
|||||||
} : {}),
|
} : {}),
|
||||||
|
|
||||||
...(opts.includeSecrets ? {
|
...(opts.includeSecrets ? {
|
||||||
role: this.roleService.getUserRoleOptions(user.id),
|
policies: this.roleService.getUserPolicies(user.id),
|
||||||
email: profile!.email,
|
email: profile!.email,
|
||||||
emailVerified: profile!.emailVerified,
|
emailVerified: profile!.emailVerified,
|
||||||
securityKeysList: profile!.twoFactorEnabled
|
securityKeysList: profile!.twoFactorEnabled
|
||||||
|
@@ -13,7 +13,7 @@ export class Instance {
|
|||||||
@Column('timestamp with time zone', {
|
@Column('timestamp with time zone', {
|
||||||
comment: 'The caught date of the Instance.',
|
comment: 'The caught date of the Instance.',
|
||||||
})
|
})
|
||||||
public caughtAt: Date;
|
public firstRetrievedAt: Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ホスト
|
* ホスト
|
||||||
|
@@ -458,5 +458,5 @@ export class Meta {
|
|||||||
@Column('jsonb', {
|
@Column('jsonb', {
|
||||||
default: { },
|
default: { },
|
||||||
})
|
})
|
||||||
public defaultRoleOverride: Record<string, any>;
|
public policies: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
@@ -136,8 +136,9 @@ export class Role {
|
|||||||
@Column('jsonb', {
|
@Column('jsonb', {
|
||||||
default: { },
|
default: { },
|
||||||
})
|
})
|
||||||
public options: Record<string, {
|
public policies: Record<string, {
|
||||||
useDefault: boolean;
|
useDefault: boolean;
|
||||||
|
priority: number;
|
||||||
value: any;
|
value: any;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
@@ -232,6 +232,6 @@ export type CacheableUser = CacheableLocalUser | CacheableRemoteUser;
|
|||||||
export const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const;
|
export const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const;
|
||||||
export const passwordSchema = { type: 'string', minLength: 1 } as const;
|
export const passwordSchema = { type: 'string', minLength: 1 } as const;
|
||||||
export const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
|
export const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
|
||||||
export const descriptionSchema = { type: 'string', minLength: 1, maxLength: 500 } as const;
|
export const descriptionSchema = { type: 'string', minLength: 1, maxLength: 1500 } as const;
|
||||||
export const locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
|
export const locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
|
||||||
export const birthdaySchema = { type: 'string', pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1) } as const;
|
export const birthdaySchema = { type: 'string', pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1) } as const;
|
||||||
|
@@ -6,7 +6,7 @@ export const packedFederationInstanceSchema = {
|
|||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
format: 'id',
|
format: 'id',
|
||||||
},
|
},
|
||||||
caughtAt: {
|
firstRetrievedAt: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
format: 'date-time',
|
format: 'date-time',
|
||||||
|
@@ -10,7 +10,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
|||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import NotesChart from '@/core/chart/charts/notes.js';
|
import NotesChart from '@/core/chart/charts/notes.js';
|
||||||
import UsersChart from '@/core/chart/charts/users.js';
|
import UsersChart from '@/core/chart/charts/users.js';
|
||||||
import { DEFAULT_ROLE } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
||||||
|
|
||||||
const nodeinfo2_1path = '/nodeinfo/2.1';
|
const nodeinfo2_1path = '/nodeinfo/2.1';
|
||||||
@@ -74,7 +74,7 @@ export class NodeinfoServerService {
|
|||||||
|
|
||||||
const proxyAccount = meta.proxyAccountId ? await this.userEntityService.pack(meta.proxyAccountId).catch(() => null) : null;
|
const proxyAccount = meta.proxyAccountId ? await this.userEntityService.pack(meta.proxyAccountId).catch(() => null) : null;
|
||||||
|
|
||||||
const baseRoleOptions = { ...DEFAULT_ROLE, ...meta.defaultRoleOverride };
|
const basePolicies = { ...DEFAULT_POLICIES, ...meta.policies };
|
||||||
|
|
||||||
return {
|
return {
|
||||||
software: {
|
software: {
|
||||||
@@ -105,8 +105,8 @@ export class NodeinfoServerService {
|
|||||||
repositoryUrl: meta.repositoryUrl,
|
repositoryUrl: meta.repositoryUrl,
|
||||||
feedbackUrl: meta.feedbackUrl,
|
feedbackUrl: meta.feedbackUrl,
|
||||||
disableRegistration: meta.disableRegistration,
|
disableRegistration: meta.disableRegistration,
|
||||||
disableLocalTimeline: !baseRoleOptions.ltlAvailable,
|
disableLocalTimeline: !basePolicies.ltlAvailable,
|
||||||
disableGlobalTimeline: !baseRoleOptions.gtlAvailable,
|
disableGlobalTimeline: !basePolicies.gtlAvailable,
|
||||||
emailRequiredForSignup: meta.emailRequiredForSignup,
|
emailRequiredForSignup: meta.emailRequiredForSignup,
|
||||||
enableHcaptcha: meta.enableHcaptcha,
|
enableHcaptcha: meta.enableHcaptcha,
|
||||||
enableRecaptcha: meta.enableRecaptcha,
|
enableRecaptcha: meta.enableRecaptcha,
|
||||||
|
@@ -224,8 +224,11 @@ export class ApiCallService implements OnApplicationShutdown {
|
|||||||
limit.key = ep.name;
|
limit.key = ep.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: 毎リクエスト計算するのもあれだしキャッシュしたい
|
||||||
|
const factor = user ? (await this.roleService.getUserPolicies(user.id)).rateLimitFactor : 1;
|
||||||
|
|
||||||
// Rate limit
|
// Rate limit
|
||||||
await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable<string> }, limitActor).catch(err => {
|
await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable<string> }, limitActor, factor).catch(err => {
|
||||||
throw new ApiError({
|
throw new ApiError({
|
||||||
message: 'Rate limit exceeded. Please try again later.',
|
message: 'Rate limit exceeded. Please try again later.',
|
||||||
code: 'RATE_LIMIT_EXCEEDED',
|
code: 'RATE_LIMIT_EXCEEDED',
|
||||||
@@ -271,9 +274,9 @@ export class ApiCallService implements OnApplicationShutdown {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ep.meta.requireRoleOption != null && !user!.isRoot) {
|
if (ep.meta.requireRolePolicy != null && !user!.isRoot) {
|
||||||
const myRole = await this.roleService.getUserRoleOptions(user!.id);
|
const policies = await this.roleService.getUserPolicies(user!.id);
|
||||||
if (!myRole[ep.meta.requireRoleOption]) {
|
if (!policies[ep.meta.requireRolePolicy]) {
|
||||||
throw new ApiError({
|
throw new ApiError({
|
||||||
message: 'You are not assigned to a required role.',
|
message: 'You are not assigned to a required role.',
|
||||||
code: 'ROLE_PERMISSION_DENIED',
|
code: 'ROLE_PERMISSION_DENIED',
|
||||||
|
@@ -65,7 +65,7 @@ import * as ep___admin_roles_show from './endpoints/admin/roles/show.js';
|
|||||||
import * as ep___admin_roles_update from './endpoints/admin/roles/update.js';
|
import * as ep___admin_roles_update from './endpoints/admin/roles/update.js';
|
||||||
import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
|
import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
|
||||||
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
|
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
|
||||||
import * as ep___admin_roles_updateDefaultRoleOverride from './endpoints/admin/roles/update-default-role-override.js';
|
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
|
||||||
import * as ep___announcements from './endpoints/announcements.js';
|
import * as ep___announcements from './endpoints/announcements.js';
|
||||||
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
||||||
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
||||||
@@ -399,7 +399,7 @@ const $admin_roles_show: Provider = { provide: 'ep:admin/roles/show', useClass:
|
|||||||
const $admin_roles_update: Provider = { provide: 'ep:admin/roles/update', useClass: ep___admin_roles_update.default };
|
const $admin_roles_update: Provider = { provide: 'ep:admin/roles/update', useClass: ep___admin_roles_update.default };
|
||||||
const $admin_roles_assign: Provider = { provide: 'ep:admin/roles/assign', useClass: ep___admin_roles_assign.default };
|
const $admin_roles_assign: Provider = { provide: 'ep:admin/roles/assign', useClass: ep___admin_roles_assign.default };
|
||||||
const $admin_roles_unassign: Provider = { provide: 'ep:admin/roles/unassign', useClass: ep___admin_roles_unassign.default };
|
const $admin_roles_unassign: Provider = { provide: 'ep:admin/roles/unassign', useClass: ep___admin_roles_unassign.default };
|
||||||
const $admin_roles_updateDefaultRoleOverride: Provider = { provide: 'ep:admin/roles/update-default-role-override', useClass: ep___admin_roles_updateDefaultRoleOverride.default };
|
const $admin_roles_updateDefaultPolicies: Provider = { provide: 'ep:admin/roles/update-default-policies', useClass: ep___admin_roles_updateDefaultPolicies.default };
|
||||||
const $announcements: Provider = { provide: 'ep:announcements', useClass: ep___announcements.default };
|
const $announcements: Provider = { provide: 'ep:announcements', useClass: ep___announcements.default };
|
||||||
const $antennas_create: Provider = { provide: 'ep:antennas/create', useClass: ep___antennas_create.default };
|
const $antennas_create: Provider = { provide: 'ep:antennas/create', useClass: ep___antennas_create.default };
|
||||||
const $antennas_delete: Provider = { provide: 'ep:antennas/delete', useClass: ep___antennas_delete.default };
|
const $antennas_delete: Provider = { provide: 'ep:antennas/delete', useClass: ep___antennas_delete.default };
|
||||||
@@ -737,7 +737,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||||||
$admin_roles_update,
|
$admin_roles_update,
|
||||||
$admin_roles_assign,
|
$admin_roles_assign,
|
||||||
$admin_roles_unassign,
|
$admin_roles_unassign,
|
||||||
$admin_roles_updateDefaultRoleOverride,
|
$admin_roles_updateDefaultPolicies,
|
||||||
$announcements,
|
$announcements,
|
||||||
$antennas_create,
|
$antennas_create,
|
||||||
$antennas_delete,
|
$antennas_delete,
|
||||||
@@ -1069,7 +1069,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||||||
$admin_roles_update,
|
$admin_roles_update,
|
||||||
$admin_roles_assign,
|
$admin_roles_assign,
|
||||||
$admin_roles_unassign,
|
$admin_roles_unassign,
|
||||||
$admin_roles_updateDefaultRoleOverride,
|
$admin_roles_updateDefaultPolicies,
|
||||||
$announcements,
|
$announcements,
|
||||||
$antennas_create,
|
$antennas_create,
|
||||||
$antennas_delete,
|
$antennas_delete,
|
||||||
|
@@ -26,7 +26,7 @@ export class RateLimiterService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable<string> }, actor: string) {
|
public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable<string> }, actor: string, factor = 1) {
|
||||||
return new Promise<void>((ok, reject) => {
|
return new Promise<void>((ok, reject) => {
|
||||||
if (this.disabled) ok();
|
if (this.disabled) ok();
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ export class RateLimiterService {
|
|||||||
const min = (): void => {
|
const min = (): void => {
|
||||||
const minIntervalLimiter = new Limiter({
|
const minIntervalLimiter = new Limiter({
|
||||||
id: `${actor}:${limitation.key}:min`,
|
id: `${actor}:${limitation.key}:min`,
|
||||||
duration: limitation.minInterval,
|
duration: limitation.minInterval * factor,
|
||||||
max: 1,
|
max: 1,
|
||||||
db: this.redisClient,
|
db: this.redisClient,
|
||||||
});
|
});
|
||||||
@@ -62,8 +62,8 @@ export class RateLimiterService {
|
|||||||
const max = (): void => {
|
const max = (): void => {
|
||||||
const limiter = new Limiter({
|
const limiter = new Limiter({
|
||||||
id: `${actor}:${limitation.key}`,
|
id: `${actor}:${limitation.key}`,
|
||||||
duration: limitation.duration,
|
duration: limitation.duration * factor,
|
||||||
max: limitation.max,
|
max: limitation.max / factor,
|
||||||
db: this.redisClient,
|
db: this.redisClient,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -64,7 +64,7 @@ import * as ep___admin_roles_show from './endpoints/admin/roles/show.js';
|
|||||||
import * as ep___admin_roles_update from './endpoints/admin/roles/update.js';
|
import * as ep___admin_roles_update from './endpoints/admin/roles/update.js';
|
||||||
import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
|
import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
|
||||||
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
|
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
|
||||||
import * as ep___admin_roles_updateDefaultRoleOverride from './endpoints/admin/roles/update-default-role-override.js';
|
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
|
||||||
import * as ep___announcements from './endpoints/announcements.js';
|
import * as ep___announcements from './endpoints/announcements.js';
|
||||||
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
||||||
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
||||||
@@ -396,7 +396,7 @@ const eps = [
|
|||||||
['admin/roles/update', ep___admin_roles_update],
|
['admin/roles/update', ep___admin_roles_update],
|
||||||
['admin/roles/assign', ep___admin_roles_assign],
|
['admin/roles/assign', ep___admin_roles_assign],
|
||||||
['admin/roles/unassign', ep___admin_roles_unassign],
|
['admin/roles/unassign', ep___admin_roles_unassign],
|
||||||
['admin/roles/update-default-role-override', ep___admin_roles_updateDefaultRoleOverride],
|
['admin/roles/update-default-policies', ep___admin_roles_updateDefaultPolicies],
|
||||||
['announcements', ep___announcements],
|
['announcements', ep___announcements],
|
||||||
['antennas/create', ep___antennas_create],
|
['antennas/create', ep___antennas_create],
|
||||||
['antennas/delete', ep___antennas_delete],
|
['antennas/delete', ep___antennas_delete],
|
||||||
@@ -695,7 +695,7 @@ export interface IEndpointMeta {
|
|||||||
*/
|
*/
|
||||||
readonly requireAdmin?: boolean;
|
readonly requireAdmin?: boolean;
|
||||||
|
|
||||||
readonly requireRoleOption?: string;
|
readonly requireRolePolicy?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* エンドポイントのリミテーションに関するやつ
|
* エンドポイントのリミテーションに関するやつ
|
||||||
|
@@ -8,7 +8,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@@ -14,7 +14,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchFile: {
|
noSuchFile: {
|
||||||
|
@@ -14,7 +14,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchEmoji: {
|
noSuchEmoji: {
|
||||||
|
@@ -9,7 +9,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@@ -10,7 +10,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchEmoji: {
|
noSuchEmoji: {
|
||||||
|
@@ -5,7 +5,7 @@ import { QueueService } from '@/core/QueueService.js';
|
|||||||
export const meta = {
|
export const meta = {
|
||||||
secure: true,
|
secure: true,
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@@ -11,7 +11,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
@@ -11,7 +11,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
@@ -8,7 +8,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@@ -8,7 +8,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@@ -8,7 +8,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@@ -9,7 +9,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchEmoji: {
|
noSuchEmoji: {
|
||||||
|
@@ -4,7 +4,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
|
|||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { DEFAULT_ROLE } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
@@ -440,7 +440,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
deeplIsPro: instance.deeplIsPro,
|
deeplIsPro: instance.deeplIsPro,
|
||||||
enableIpLogging: instance.enableIpLogging,
|
enableIpLogging: instance.enableIpLogging,
|
||||||
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
||||||
baseRole: { ...DEFAULT_ROLE, ...instance.defaultRoleOverride },
|
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ export const paramDef = {
|
|||||||
isModerator: { type: 'boolean' },
|
isModerator: { type: 'boolean' },
|
||||||
isAdministrator: { type: 'boolean' },
|
isAdministrator: { type: 'boolean' },
|
||||||
canEditMembersByModerator: { type: 'boolean' },
|
canEditMembersByModerator: { type: 'boolean' },
|
||||||
options: {
|
policies: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -39,7 +39,7 @@ export const paramDef = {
|
|||||||
'isModerator',
|
'isModerator',
|
||||||
'isAdministrator',
|
'isAdministrator',
|
||||||
'canEditMembersByModerator',
|
'canEditMembersByModerator',
|
||||||
'options',
|
'policies',
|
||||||
],
|
],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
isAdministrator: ps.isAdministrator,
|
isAdministrator: ps.isAdministrator,
|
||||||
isModerator: ps.isModerator,
|
isModerator: ps.isModerator,
|
||||||
canEditMembersByModerator: ps.canEditMembersByModerator,
|
canEditMembersByModerator: ps.canEditMembersByModerator,
|
||||||
options: ps.options,
|
policies: ps.policies,
|
||||||
}).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0]));
|
}).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
this.globalEventService.publishInternalEvent('roleCreated', created);
|
this.globalEventService.publishInternalEvent('roleCreated', created);
|
||||||
|
@@ -16,12 +16,12 @@ export const meta = {
|
|||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
options: {
|
policies: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
required: [
|
required: [
|
||||||
'options',
|
'policies',
|
||||||
],
|
],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@@ -34,9 +34,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps) => {
|
super(meta, paramDef, async (ps) => {
|
||||||
await this.metaService.update({
|
await this.metaService.update({
|
||||||
defaultRoleOverride: ps.options,
|
policies: ps.policies,
|
||||||
});
|
});
|
||||||
this.globalEventService.publishInternalEvent('defaultRoleOverrideUpdated', ps.options);
|
this.globalEventService.publishInternalEvent('policiesUpdated', ps.policies);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -33,7 +33,7 @@ export const paramDef = {
|
|||||||
isModerator: { type: 'boolean' },
|
isModerator: { type: 'boolean' },
|
||||||
isAdministrator: { type: 'boolean' },
|
isAdministrator: { type: 'boolean' },
|
||||||
canEditMembersByModerator: { type: 'boolean' },
|
canEditMembersByModerator: { type: 'boolean' },
|
||||||
options: {
|
policies: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -48,7 +48,7 @@ export const paramDef = {
|
|||||||
'isModerator',
|
'isModerator',
|
||||||
'isAdministrator',
|
'isAdministrator',
|
||||||
'canEditMembersByModerator',
|
'canEditMembersByModerator',
|
||||||
'options',
|
'policies',
|
||||||
],
|
],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
isModerator: ps.isModerator,
|
isModerator: ps.isModerator,
|
||||||
isAdministrator: ps.isAdministrator,
|
isAdministrator: ps.isAdministrator,
|
||||||
canEditMembersByModerator: ps.canEditMembersByModerator,
|
canEditMembersByModerator: ps.canEditMembersByModerator,
|
||||||
options: ps.options,
|
policies: ps.policies,
|
||||||
});
|
});
|
||||||
const updated = await this.rolesRepository.findOneByOrFail({ id: ps.roleId });
|
const updated = await this.rolesRepository.findOneByOrFail({ id: ps.roleId });
|
||||||
this.globalEventService.publishInternalEvent('roleUpdated', updated);
|
this.globalEventService.publishInternalEvent('roleUpdated', updated);
|
||||||
|
@@ -52,7 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isModerator = await this.roleService.isModerator(user);
|
const isModerator = await this.roleService.isModerator(user);
|
||||||
const isSilenced = !(await this.roleService.getUserRoleOptions(user.id)).canPublicNote;
|
const isSilenced = !(await this.roleService.getUserPolicies(user.id)).canPublicNote;
|
||||||
|
|
||||||
const _me = await this.usersRepository.findOneByOrFail({ id: me.id });
|
const _me = await this.usersRepository.findOneByOrFail({ id: me.id });
|
||||||
if (!await this.roleService.isAdministrator(_me) && await this.roleService.isAdministrator(user)) {
|
if (!await this.roleService.isAdministrator(_me) && await this.roleService.isAdministrator(user)) {
|
||||||
@@ -94,6 +94,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
lastActiveDate: user.lastActiveDate,
|
lastActiveDate: user.lastActiveDate,
|
||||||
moderationNote: profile.moderationNote,
|
moderationNote: profile.moderationNote,
|
||||||
signins,
|
signins,
|
||||||
|
policies: await this.roleService.getUserPolicies(user.id),
|
||||||
roles: await this.roleEntityService.packMany(roles, me, { detail: false }),
|
roles: await this.roleEntityService.packMany(roles, me, { detail: false }),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@@ -92,7 +92,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
const currentAntennasCount = await this.antennasRepository.countBy({
|
const currentAntennasCount = await this.antennasRepository.countBy({
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
});
|
});
|
||||||
if (currentAntennasCount > (await this.roleService.getUserRoleOptions(me.id)).antennaLimit) {
|
if (currentAntennasCount > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyAntennas);
|
throw new ApiError(meta.errors.tooManyAntennas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -97,7 +97,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
const currentCount = await this.clipNotesRepository.countBy({
|
const currentCount = await this.clipNotesRepository.countBy({
|
||||||
clipId: clip.id,
|
clipId: clip.id,
|
||||||
});
|
});
|
||||||
if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).noteEachClipsLimit) {
|
if (currentCount > (await this.roleService.getUserPolicies(me.id)).noteEachClipsLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyClipNotes);
|
throw new ApiError(meta.errors.tooManyClipNotes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
const currentCount = await this.clipsRepository.countBy({
|
const currentCount = await this.clipsRepository.countBy({
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
});
|
});
|
||||||
if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).clipLimit) {
|
if (currentCount > (await this.roleService.getUserPolicies(me.id)).clipLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyClips);
|
throw new ApiError(meta.errors.tooManyClips);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -47,10 +47,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
// Calculate drive usage
|
// Calculate drive usage
|
||||||
const usage = await this.driveFileEntityService.calcDriveUsageOf(me.id);
|
const usage = await this.driveFileEntityService.calcDriveUsageOf(me.id);
|
||||||
|
|
||||||
const myRole = await this.roleService.getUserRoleOptions(me.id);
|
const policies = await this.roleService.getUserPolicies(me.id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
capacity: 1024 * 1024 * myRole.driveCapacityMb,
|
capacity: 1024 * 1024 * policies.driveCapacityMb,
|
||||||
usage: usage,
|
usage: usage,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@@ -63,8 +63,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
case '-following': query.orderBy('instance.followingCount', 'ASC'); break;
|
case '-following': query.orderBy('instance.followingCount', 'ASC'); break;
|
||||||
case '+followers': query.orderBy('instance.followersCount', 'DESC'); break;
|
case '+followers': query.orderBy('instance.followersCount', 'DESC'); break;
|
||||||
case '-followers': query.orderBy('instance.followersCount', 'ASC'); break;
|
case '-followers': query.orderBy('instance.followersCount', 'ASC'); break;
|
||||||
case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break;
|
case '+firstRetrievedAt': query.orderBy('instance.firstRetrievedAt', 'DESC'); break;
|
||||||
case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break;
|
case '-firstRetrievedAt': query.orderBy('instance.firstRetrievedAt', 'ASC'); break;
|
||||||
case '+latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'DESC', 'NULLS LAST'); break;
|
case '+latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'DESC', 'NULLS LAST'); break;
|
||||||
case '-latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'ASC', 'NULLS FIRST'); break;
|
case '-latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'ASC', 'NULLS FIRST'); break;
|
||||||
|
|
||||||
|
@@ -173,7 +173,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
if (ps.mutedWords !== undefined) {
|
if (ps.mutedWords !== undefined) {
|
||||||
// TODO: ちゃんと数える
|
// TODO: ちゃんと数える
|
||||||
const length = JSON.stringify(ps.mutedWords).length;
|
const length = JSON.stringify(ps.mutedWords).length;
|
||||||
if (length > (await this.roleService.getUserRoleOptions(user.id)).wordMuteLimit) {
|
if (length > (await this.roleService.getUserPolicies(user.id)).wordMuteLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyMutedWords);
|
throw new ApiError(meta.errors.tooManyMutedWords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
const currentWebhooksCount = await this.webhooksRepository.countBy({
|
const currentWebhooksCount = await this.webhooksRepository.countBy({
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
});
|
});
|
||||||
if (currentWebhooksCount > (await this.roleService.getUserRoleOptions(me.id)).webhookLimit) {
|
if (currentWebhooksCount > (await this.roleService.getUserPolicies(me.id)).webhookLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyWebhooks);
|
throw new ApiError(meta.errors.tooManyWebhooks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@ export const meta = {
|
|||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canInvite',
|
requireRolePolicy: 'canInvite',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
@@ -7,7 +7,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
|||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { DEFAULT_ROLE } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
@@ -334,7 +334,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
|
|
||||||
translatorAvailable: instance.deeplAuthKey != null,
|
translatorAvailable: instance.deeplAuthKey != null,
|
||||||
|
|
||||||
baseRole: { ...DEFAULT_ROLE, ...instance.defaultRoleOverride },
|
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||||
|
|
||||||
...(ps.detail ? {
|
...(ps.detail ? {
|
||||||
pinnedPages: instance.pinnedPages,
|
pinnedPages: instance.pinnedPages,
|
||||||
|
@@ -62,8 +62,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
private activeUsersChart: ActiveUsersChart,
|
private activeUsersChart: ActiveUsersChart,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const role = await this.roleService.getUserRoleOptions(me ? me.id : null);
|
const policies = await this.roleService.getUserPolicies(me ? me.id : null);
|
||||||
if (!role.gtlAvailable) {
|
if (!policies.gtlAvailable) {
|
||||||
throw new ApiError(meta.errors.gtlDisabled);
|
throw new ApiError(meta.errors.gtlDisabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -71,8 +71,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
private activeUsersChart: ActiveUsersChart,
|
private activeUsersChart: ActiveUsersChart,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const role = await this.roleService.getUserRoleOptions(me.id);
|
const policies = await this.roleService.getUserPolicies(me.id);
|
||||||
if (!role.ltlAvailable) {
|
if (!policies.ltlAvailable) {
|
||||||
throw new ApiError(meta.errors.stlDisabled);
|
throw new ApiError(meta.errors.stlDisabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -67,8 +67,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
private activeUsersChart: ActiveUsersChart,
|
private activeUsersChart: ActiveUsersChart,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const role = await this.roleService.getUserRoleOptions(me ? me.id : null);
|
const policies = await this.roleService.getUserPolicies(me ? me.id : null);
|
||||||
if (!role.ltlAvailable) {
|
if (!policies.ltlAvailable) {
|
||||||
throw new ApiError(meta.errors.ltlDisabled);
|
throw new ApiError(meta.errors.ltlDisabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -55,7 +55,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
const currentCount = await this.userListsRepository.countBy({
|
const currentCount = await this.userListsRepository.countBy({
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
});
|
});
|
||||||
if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).userListLimit) {
|
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyUserLists);
|
throw new ApiError(meta.errors.tooManyUserLists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,8 +29,8 @@ class GlobalTimelineChannel extends Channel {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async init(params: any) {
|
public async init(params: any) {
|
||||||
const role = await this.roleService.getUserRoleOptions(this.user ? this.user.id : null);
|
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
|
||||||
if (!role.gtlAvailable) return;
|
if (!policies.gtlAvailable) return;
|
||||||
|
|
||||||
// Subscribe events
|
// Subscribe events
|
||||||
this.subscriber.on('notesStream', this.onNote);
|
this.subscriber.on('notesStream', this.onNote);
|
||||||
|
@@ -30,8 +30,8 @@ class HybridTimelineChannel extends Channel {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async init(params: any): Promise<void> {
|
public async init(params: any): Promise<void> {
|
||||||
const role = await this.roleService.getUserRoleOptions(this.user ? this.user.id : null);
|
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
|
||||||
if (!role.ltlAvailable) return;
|
if (!policies.ltlAvailable) return;
|
||||||
|
|
||||||
// Subscribe events
|
// Subscribe events
|
||||||
this.subscriber.on('notesStream', this.onNote);
|
this.subscriber.on('notesStream', this.onNote);
|
||||||
|
@@ -28,8 +28,8 @@ class LocalTimelineChannel extends Channel {
|
|||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async init(params: any) {
|
public async init(params: any) {
|
||||||
const role = await this.roleService.getUserRoleOptions(this.user ? this.user.id : null);
|
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
|
||||||
if (!role.ltlAvailable) return;
|
if (!policies.ltlAvailable) return;
|
||||||
|
|
||||||
// Subscribe events
|
// Subscribe events
|
||||||
this.subscriber.on('notesStream', this.onNote);
|
this.subscriber.on('notesStream', this.onNote);
|
||||||
|
@@ -30,7 +30,7 @@ export interface InternalStreamTypes {
|
|||||||
remoteUserUpdated: Serialized<{ id: User['id']; }>;
|
remoteUserUpdated: Serialized<{ id: User['id']; }>;
|
||||||
follow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>;
|
follow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>;
|
||||||
unfollow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>;
|
unfollow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>;
|
||||||
defaultRoleOverrideUpdated: Serialized<Role['options']>;
|
policiesUpdated: Serialized<Role['options']>;
|
||||||
roleCreated: Serialized<Role>;
|
roleCreated: Serialized<Role>;
|
||||||
roleDeleted: Serialized<Role>;
|
roleDeleted: Serialized<Role>;
|
||||||
roleUpdated: Serialized<Role>;
|
roleUpdated: Serialized<Role>;
|
||||||
|
@@ -73,6 +73,7 @@
|
|||||||
"@types/gulp": "4.0.10",
|
"@types/gulp": "4.0.10",
|
||||||
"@types/gulp-rename": "2.0.1",
|
"@types/gulp-rename": "2.0.1",
|
||||||
"@types/matter-js": "0.18.2",
|
"@types/matter-js": "0.18.2",
|
||||||
|
"@types/node": "^18.11.18",
|
||||||
"@types/punycode": "2.1.0",
|
"@types/punycode": "2.1.0",
|
||||||
"@types/sanitize-html": "^2.8.0",
|
"@types/sanitize-html": "^2.8.0",
|
||||||
"@types/seedrandom": "3.0.4",
|
"@types/seedrandom": "3.0.4",
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
@leave="leave"
|
@leave="leave"
|
||||||
@after-leave="afterLeave"
|
@after-leave="afterLeave"
|
||||||
>
|
>
|
||||||
<div v-show="showBody" ref="content" :class="[$style.content, { omitted }]">
|
<div v-show="showBody" ref="content" :class="[$style.content, { [$style.omitted]: omitted }]">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<button v-if="omitted" :class="$style.fade" class="_button" @click="() => { ignoreOmit = true; omitted = false; }">
|
<button v-if="omitted" :class="$style.fade" class="_button" @click="() => { ignoreOmit = true; omitted = false; }">
|
||||||
<span :class="$style.fadeLabel">{{ $ts.showMore }}</span>
|
<span :class="$style.fadeLabel">{{ $ts.showMore }}</span>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user