diff --git a/.config/example.yml b/.config/example.yml index df423c2c83..7fea929374 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -2,6 +2,63 @@ # Misskey configuration #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# ┌──────────────────────────────┐ +#───┘ a boring but important thing └──────────────────────────── + +# +# First of all, let me tell you a story that may possibly be +# boring to you and possibly important to you. +# +# Misskey is licensed under the AGPLv3 license. This license is +# known to be often misunderstood. Please read the following +# instructions carefully and select the appropriate option so +# that you do not negligently cause a license violation. +# + +# -------- +# Option 1: If you host Misskey AS-IS (without any changes to +# the source code. forks are not included). +# +# Step 1: Congratulations! You don't need to do anything. + +# -------- +# Option 2: If you have made changes to the source code (forks +# are included) and publish a Git repository of source +# code. There should be no access restrictions on +# this repository. Strictly speaking, it doesn't have +# to be a Git repository, but you'll probably use Git! +# +# Step 1: Build and run the Misskey server first. +# Step 2: Open in +# your browser with the administrator account. +# Step 3: Enter the URL of your Git repository in the +# "Repository URL" field. + +# -------- +# Option 3: If neither of the above applies to you. +# (In this case, the source code should be published +# on the Misskey interface. IT IS NOT ENOUGH TO +# DISCLOSE THE SOURCE CODE WEHN A USER REQUESTS IT BY +# E-MAIL OR OTHER MEANS. If you are not satisfied +# with this, it is recommended that you read the +# license again carefully. Anyway, enabling this +# option will automatically generate and publish a +# tarball at build time, protecting you from +# inadvertent license violations. (There is no legal +# guarantee, of course.) The tarball will generated +# from the root directory of your codebase. So it is +# also recommended to check directory +# once after building and before activating the server +# to avoid ACCIDENTAL LEAKING OF SENSITIVE INFORMATION. +# To prevent certain files from being included in the +# tarball, add a glob pattern after line 15 in +# . DO NOT FORGET TO BUILD AFTER +# ENABLING THIS OPTION!) +# +# Step 1: Uncomment the following line. +# +# publishTarballInsteadOfProvideRepositoryUrl: true + # ┌─────┐ #───┘ URL └───────────────────────────────────────────────────── @@ -118,7 +175,7 @@ redis: # ┌───────────────────────────┐ #───┘ MeiliSearch configuration └───────────────────────────── -# You can set scope to local (default value) or global +# You can set scope to local (default value) or global # (include notes from remote). #meilisearch: @@ -160,14 +217,14 @@ id: 'aidx' # Job concurrency per worker #deliverJobConcurrency: 128 #inboxJobConcurrency: 16 -#relashionshipJobConcurrency: 16 -# What's relashionshipJob?: +#relationshipJobConcurrency: 16 +# What's relationshipJob?: # Follow, unfollow, block and unblock(ings) while following-imports, etc. or account migrations. # Job rate limiter #deliverJobPerSec: 128 #inboxJobPerSec: 32 -#relashionshipJobPerSec: 64 +#relationshipJobPerSec: 64 # Job attempts #deliverJobMaxAttempts: 12 @@ -214,7 +271,7 @@ proxyRemoteFiles: true signToActivityPubGet: true # For security reasons, uploading attachments from the intranet is prohibited, -# but exceptions can be made from the following settings. Default value is "undefined". +# but exceptions can be made from the following settings. Default value is "undefined". # Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)). #allowedPrivateNetworks: [ # '127.0.0.1/32' diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml index e52cbc33e4..1b7b68b14f 100644 --- a/.github/workflows/api-misskey-js.yml +++ b/.github/workflows/api-misskey-js.yml @@ -20,7 +20,7 @@ jobs: - run: corepack enable - name: Setup Node.js - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.2 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/changelog-check.yml b/.github/workflows/changelog-check.yml index d4cdf64f70..f254af0d1f 100644 --- a/.github/workflows/changelog-check.yml +++ b/.github/workflows/changelog-check.yml @@ -14,7 +14,7 @@ jobs: - name: Checkout head uses: actions/checkout@v4.1.1 - name: Setup Node.js - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.2 with: node-version-file: '.node-version' diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml index 545b215756..8fad129115 100644 --- a/.github/workflows/check-misskey-js-autogen.yml +++ b/.github/workflows/check-misskey-js-autogen.yml @@ -19,19 +19,19 @@ jobs: steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.1 with: submodules: true ref: ${{ github.event.pull_request.head.sha }} - name: setup pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: version: 8 - name: setup node id: setup-node - uses: actions/setup-node@v4 + uses: actions/setup-node@v4.0.2 with: node-version-file: '.node-version' cache: pnpm @@ -48,7 +48,7 @@ jobs: wait-interval: 30 - name: Download artifact - uses: actions/github-script@v7 + uses: actions/github-script@v7.0.1 with: script: | const fs = require('fs'); diff --git a/.github/workflows/check-misskey-js-version.yml b/.github/workflows/check-misskey-js-version.yml new file mode 100644 index 0000000000..325a893605 --- /dev/null +++ b/.github/workflows/check-misskey-js-version.yml @@ -0,0 +1,28 @@ +name: Check Misskey JS version + +on: + push: + branches: [ develop ] + paths: + - packages/misskey-js/package.json + - package.json + pull_request: + branches: [ develop ] + paths: + - packages/misskey-js/package.json + - package.json + +jobs: + check-version: + # ルートの package.json と packages/misskey-js/package.json のバージョンが一致しているかを確認する + name: Check version + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + - name: Check version + run: | + if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then + echo "Version mismatch!" + exit 1 + fi diff --git a/.github/workflows/deploy-test-environment.yml b/.github/workflows/deploy-test-environment.yml new file mode 100644 index 0000000000..77cdcfaf88 --- /dev/null +++ b/.github/workflows/deploy-test-environment.yml @@ -0,0 +1,87 @@ +name: deploy-test-environment + +on: + issue_comment: + types: [created] + workflow_dispatch: + inputs: + repository: + description: 'Repository to deploy (optional, use the repository where this workflow is stored by default)' + required: false + default: '' + branch_or_hash: + description: 'Branch or Commit hash to deploy (optional, use the branch where this workflow is stored by default)' + required: false + default: '' + wait_time: + description: 'Time to wait in seconds (optional, 1800 seconds by default)' + required: false + default: '' + +jobs: + get-pr-ref: + runs-on: ubuntu-latest + if: github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/preview') + outputs: + is-allowed-user: ${{ steps.check-allowed-users.outputs.is-allowed-user }} + pr-ref: ${{ steps.get-ref.outputs.pr-ref }} + wait_time: ${{ steps.get-wait-time.outputs.wait_time }} + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + + - name: Check allowed users + id: check-allowed-users + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ORG_ID: ${{ github.repository_owner_id }} + COMMENT_AUTHOR: ${{ github.event.comment.user.login }} + run: | + MEMBERSHIP_STATUS=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/organizations/$ORG_ID/public_members/$COMMENT_AUTHOR" \ + -o /dev/null -w '%{http_code}\n' -s) + if [ "$MEMBERSHIP_STATUS" -eq 204 ]; then + echo "is-allowed-user=true" > $GITHUB_OUTPUT + else + echo "is-allowed-user=false" > $GITHUB_OUTPUT + fi + + - name: Get PR ref + id: get-ref + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(jq --raw-output .issue.number $GITHUB_EVENT_PATH) + PR_REF=$(gh pr view $PR_NUMBER --json headRefName -q '.headRefName') + echo "pr-ref=$PR_REF" > $GITHUB_OUTPUT + + - name: Extract wait time + id: get-wait-time + env: + COMMENT_BODY: ${{ github.event.comment.body }} + run: | + WAIT_TIME=$(echo "$COMMENT_BODY" | grep -oP '(?<=/preview\s)\d+' || echo "1800") + echo "wait_time=$WAIT_TIME" > $GITHUB_OUTPUT + + deploy-test-environment-pr-comment: + needs: get-pr-ref + if: needs.get-pr-ref.outputs.is-allowed-user == 'true' + uses: joinmisskey/misskey-tga/.github/workflows/deploy-test-environment.yml@main + with: + repository: ${{ github.repository }} + branch_or_hash: ${{ needs.get-pr-ref.outputs.pr-ref }} + wait_time: ${{ needs.get-pr-ref.outputs.wait_time }} + secrets: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + + deploy-test-environment-wd: + if: github.event_name == 'workflow_dispatch' + uses: joinmisskey/misskey-tga/.github/workflows/deploy-test-environment.yml@main + with: + repository: ${{ inputs.repository || github.repository }} + branch_or_hash: ${{ inputs.branch_or_hash || github.ref_name }} + wait_time: ${{ inputs.wait_time || '1800' }} + secrets: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} diff --git a/.github/workflows/docker-develop.yml b/.github/workflows/docker-develop.yml index a43789b754..cb84849580 100644 --- a/.github/workflows/docker-develop.yml +++ b/.github/workflows/docker-develop.yml @@ -6,38 +6,83 @@ on: - develop workflow_dispatch: +env: + REGISTRY_IMAGE: misskey/misskey + jobs: - push_to_registry: - name: Push Docker image to Docker Hub + # see https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners + build: + name: Build runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm64 if: github.repository == 'misskey-dev/misskey' steps: + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV - name: Check out the repo uses: actions/checkout@v4.1.1 - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3.0.0 - with: - platforms: linux/amd64,linux/arm64 - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: misskey/misskey + uses: docker/setup-buildx-action@v3 - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Build and Push to Docker Hub + - name: Build and push by digest + id: build uses: docker/build-push-action@v5 with: - builder: ${{ steps.buildx.outputs.name }} context: . push: true - platforms: ${{ steps.buildx.outputs.platforms }} + platforms: ${{ matrix.platform }} provenance: false - tags: misskey/misskey:develop labels: develop cache-from: type=gha cache-to: type=gha,mode=max + outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + needs: + - build + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create --tag ${{ env.REGISTRY_IMAGE }}:develop \ + $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:develop diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 08cb91c2d0..23c1bdbc16 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -5,45 +5,101 @@ on: types: [published] workflow_dispatch: -jobs: - push_to_registry: - name: Push Docker image to Docker Hub - runs-on: ubuntu-latest +env: + REGISTRY_IMAGE: misskey/misskey + TAGS: | + type=edge + type=ref,event=pr + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} +jobs: + # see https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners + build: + name: Build + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm64 steps: + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV - name: Check out the repo uses: actions/checkout@v4.1.1 - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3.0.0 - with: - platforms: linux/amd64,linux/arm64 + uses: docker/setup-buildx-action@v3 - name: Docker meta id: meta uses: docker/metadata-action@v5 with: - images: misskey/misskey - tags: | - type=edge - type=ref,event=pr - type=ref,event=branch - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} + images: ${{ env.REGISTRY_IMAGE }} + tags: ${{ env.TAGS }} - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and Push to Docker Hub + id: build uses: docker/build-push-action@v5 with: - builder: ${{ steps.buildx.outputs.name }} context: . push: true - platforms: ${{ steps.buildx.outputs.platforms }} + platforms: ${{ matrix.platform }} provenance: false - tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + needs: + - build + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY_IMAGE }} + tags: ${{ env.TAGS }} + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml index bf92e701b2..e737b89b42 100644 --- a/.github/workflows/get-api-diff.yml +++ b/.github/workflows/get-api-diff.yml @@ -32,12 +32,12 @@ jobs: ref: ${{ matrix.ref }} submodules: true - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.2 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 86fca995d2..31e974edaa 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,11 +27,11 @@ jobs: with: fetch-depth: 0 submodules: true - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v3 with: version: 8 run_install: false - - uses: actions/setup-node@v4.0.1 + - uses: actions/setup-node@v4.0.2 with: node-version-file: '.node-version' cache: 'pnpm' @@ -54,11 +54,11 @@ jobs: with: fetch-depth: 0 submodules: true - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v3 with: version: 7 run_install: false - - uses: actions/setup-node@v4.0.1 + - uses: actions/setup-node@v4.0.2 with: node-version-file: '.node-version' cache: 'pnpm' @@ -80,11 +80,11 @@ jobs: with: fetch-depth: 0 submodules: true - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v3 with: version: 7 run_install: false - - uses: actions/setup-node@v4.0.1 + - uses: actions/setup-node@v4.0.2 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/ok-to-test.yml b/.github/workflows/ok-to-test.yml index c02b980e4d..8362c006eb 100644 --- a/.github/workflows/ok-to-test.yml +++ b/.github/workflows/ok-to-test.yml @@ -23,7 +23,7 @@ jobs: private_key: ${{ secrets.DEPLOYBOT_PRIVATE_KEY }} - name: Slash Command Dispatch - uses: peter-evans/slash-command-dispatch@v3 + uses: peter-evans/slash-command-dispatch@v4 env: TOKEN: ${{ steps.generate_token.outputs.token }} with: diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml index 3cc0e5007b..069534bd53 100644 --- a/.github/workflows/on-release-created.yml +++ b/.github/workflows/on-release-created.yml @@ -20,16 +20,16 @@ jobs: node-version: [20.10.0] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4.1.1 with: submodules: true - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v4.0.2 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/pr-preview-deploy.yml b/.github/workflows/pr-preview-deploy.yml index cb9a4ebfc8..964d24c3d7 100644 --- a/.github/workflows/pr-preview-deploy.yml +++ b/.github/workflows/pr-preview-deploy.yml @@ -13,7 +13,7 @@ jobs: github.event.client_payload.slash_command.sha != '' && contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha) steps: - - uses: actions/github-script@v7 + - uses: actions/github-script@v7.0.1 id: check-id env: number: ${{ github.event.client_payload.pull_request.number }} @@ -37,7 +37,7 @@ jobs: return check[0].id; - - uses: actions/github-script@v7 + - uses: actions/github-script@v7.0.1 env: check_id: ${{ steps.check-id.outputs.result }} details_url: ${{ github.server_url }}/${{ github.repository }}/runs/${{ github.run_id }} @@ -72,7 +72,7 @@ jobs: timeout: 15m # Update check run called "integration-fork" - - uses: actions/github-script@v7 + - uses: actions/github-script@v7.0.1 id: update-check-run if: ${{ always() }} env: diff --git a/.github/workflows/pr-preview-destroy.yml b/.github/workflows/pr-preview-destroy.yml index 47d9eb313a..8967eb2f94 100644 --- a/.github/workflows/pr-preview-destroy.yml +++ b/.github/workflows/pr-preview-destroy.yml @@ -10,7 +10,7 @@ jobs: destroy-preview-environment: runs-on: ubuntu-latest steps: - - uses: actions/github-script@v7 + - uses: actions/github-script@v7.0.1 id: check-conclusion env: number: ${{ github.event.number }} diff --git a/.github/workflows/release-edit-with-push.yml b/.github/workflows/release-edit-with-push.yml new file mode 100644 index 0000000000..944b98eb7c --- /dev/null +++ b/.github/workflows/release-edit-with-push.yml @@ -0,0 +1,40 @@ +name: "Release Manager: sync changelog with PR" + +on: + push: + branches: + - release/** + paths: + - 'CHANGELOG.md' + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +permissions: + contents: write + issues: write + pull-requests: write + +jobs: + edit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + # headがrelease/かつopenのPRを1つ取得 + - name: Get PR + run: | + echo "pr_number=$(gh pr list --limit 1 --head "${{ github.ref_name }}" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT + id: get_pr + - name: Get target version + uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v1 + id: v + # CHANGELOG.mdの内容を取得 + - name: Get changelog + uses: misskey-dev/release-manager-actions/.github/actions/get-changelog@v1 + with: + version: ${{ steps.v.outputs.target_version }} + id: changelog + # PRのnotesを更新 + - name: Update PR + run: | + gh pr edit ${{ steps.get_pr.outputs.pr_number }} --body "${{ steps.changelog.outputs.changelog }}" diff --git a/.github/workflows/release-with-dispatch.yml b/.github/workflows/release-with-dispatch.yml new file mode 100644 index 0000000000..1a954739d9 --- /dev/null +++ b/.github/workflows/release-with-dispatch.yml @@ -0,0 +1,122 @@ +name: "Release Manager [Dispatch]" + +on: + workflow_dispatch: + inputs: + ## Specify the type of the next release. + #version_increment_type: + # type: choice + # description: 'VERSION INCREMENT TYPE' + # default: 'patch' + # required: false + # options: + # - 'major' + # - 'minor' + # - 'patch' + merge: + type: boolean + description: 'MERGE RELEASE BRANCH TO MAIN' + default: false + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +permissions: + contents: write + issues: write + pull-requests: write + +jobs: + get-pr: + runs-on: ubuntu-latest + outputs: + pr_number: ${{ steps.get_pr.outputs.pr_number }} + steps: + - uses: actions/checkout@v4 + # headがrelease/かつopenのPRを1つ取得 + - name: Get PRs + run: | + echo "pr_number=$(gh pr list --limit 1 --search "head:release/ is:open" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT + id: get_pr + + merge: + uses: misskey-dev/release-manager-actions/.github/workflows/merge.yml@v1 + needs: get-pr + if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge == true }} + with: + pr_number: ${{ needs.get-pr.outputs.pr_number }} + package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }} + # Text to prepend to the changelog + # The first line must be `## Unreleased` + changes_template: | + ## Unreleased + + ### General + - + + ### Client + - + + ### Server + - + + use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }} + secrets: + RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }} + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }} + RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }} + + create-prerelease: + uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1 + needs: get-pr + if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge != true }} + with: + pr_number: ${{ needs.get-pr.outputs.pr_number }} + package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }} + use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }} + secrets: + RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }} + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + + create-target: + uses: misskey-dev/release-manager-actions/.github/workflows/create-target.yml@v1 + needs: get-pr + if: ${{ needs.get-pr.outputs.pr_number == '' }} + with: + # The script for version increment. + # process.env.CURRENT_VERSION: The current version. + # + # Misskey calender versioning (yyyy.MM.patch) example + version_increment_script: | + const now = new Date(); + const year = now.toLocaleDateString('en-US', { year: 'numeric', timeZone: 'Asia/Tokyo' }); + const month = now.toLocaleDateString('en-US', { month: 'numeric', timeZone: 'Asia/Tokyo' }); + const [major, minor, _patch] = process.env.CURRENT_VERSION.split('.'); + const patch = Number(_patch.split('-')[0]); + if (Number.isNaN(patch)) { + console.error('Invalid patch version', year, month, process.env.CURRENT_VERSION, major, minor, _patch); + throw new Error('Invalid patch version'); + } + if (year !== major || month !== minor) { + return `${year}.${month}.0`; + } else { + return `${major}.${minor}.${patch + 1}`; + } + ##Semver example + #version_increment_script: | + # const [major, minor, patch] = process.env.CURRENT_VERSION.split('.'); + # if ("${{ inputs.version_increment_type }}" === "major") { + # return `${Number(major) + 1}.0.0`; + # } else if ("${{ inputs.version_increment_type }}" === "minor") { + # return `${major}.${Number(minor) + 1}.0`; + # } else { + # return `${major}.${minor}.${Number(patch) + 1}`; + # } + package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }} + use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }} + secrets: + RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }} + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }} + RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/release-with-ready.yml b/.github/workflows/release-with-ready.yml new file mode 100644 index 0000000000..b64ed20791 --- /dev/null +++ b/.github/workflows/release-with-ready.yml @@ -0,0 +1,38 @@ +name: "Release Manager: release RC when ready for review" + +on: + pull_request: + types: [ready_for_review] + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +permissions: + contents: write + issues: write + pull-requests: write + +jobs: + check: + runs-on: ubuntu-latest + outputs: + ref: ${{ steps.get_pr.outputs.ref }} + steps: + - uses: actions/checkout@v4 + # PR情報を取得 + - name: Get PR + run: | + pr_json=$(gh pr view ${{ github.event.pull_request.number }} --json isDraft,headRefName) + echo "ref=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT + id: get_pr + release: + uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1 + needs: check + if: startsWith(needs.check.outputs.ref, 'release/') + with: + pr_number: ${{ github.event.pull_request.number }} + package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }} + use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }} + secrets: + RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }} + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} diff --git a/.github/workflows/report-api-diff.yml b/.github/workflows/report-api-diff.yml index 54da8b4a83..df9cc279e8 100644 --- a/.github/workflows/report-api-diff.yml +++ b/.github/workflows/report-api-diff.yml @@ -16,7 +16,7 @@ jobs: # api-artifact steps: - name: Download artifact - uses: actions/github-script@v7 + uses: actions/github-script@v7.0.1 with: script: | const fs = require('fs'); diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml new file mode 100644 index 0000000000..87481b12cf --- /dev/null +++ b/.github/workflows/storybook.yml @@ -0,0 +1,113 @@ +name: Storybook + +on: + push: + branches: + - master + - develop + - dev/storybook8 # for testing + pull_request_target: + +jobs: + build: + runs-on: ubuntu-latest + + env: + NODE_OPTIONS: "--max_old_space_size=7168" + + steps: + - uses: actions/checkout@v4.1.1 + if: github.event_name != 'pull_request_target' + with: + fetch-depth: 0 + submodules: true + - uses: actions/checkout@v4.1.1 + if: github.event_name == 'pull_request_target' + with: + fetch-depth: 0 + submodules: true + ref: "refs/pull/${{ github.event.number }}/merge" + - name: Checkout actual HEAD + if: github.event_name == 'pull_request_target' + id: rev + run: | + echo "base=$(git rev-list --parents -n1 HEAD | cut -d" " -f2)" >> $GITHUB_OUTPUT + git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3) + - name: Install pnpm + uses: pnpm/action-setup@v3 + with: + version: 8 + run_install: false + - name: Use Node.js 20.x + uses: actions/setup-node@v4.0.2 + with: + node-version-file: '.node-version' + cache: 'pnpm' + - run: corepack enable + - run: pnpm i --frozen-lockfile + - name: Check pnpm-lock.yaml + run: git diff --exit-code pnpm-lock.yaml + - name: Build misskey-js + run: pnpm --filter misskey-js build + - name: Build storybook + run: pnpm --filter frontend build-storybook + - name: Publish to Chromatic + if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/master' + run: pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static + env: + CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + - name: Publish to Chromatic + if: github.event_name != 'pull_request_target' && github.ref != 'refs/heads/master' + id: chromatic_push + run: | + DIFF="${{ github.event.before }} HEAD" + if [ "$DIFF" = "0000000000000000000000000000000000000000 HEAD" ]; then + DIFF="HEAD" + fi + CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff-tree --no-commit-id --name-only -r $(echo "$DIFF") | xargs))" + if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then + echo "skip=true" >> $GITHUB_OUTPUT + fi + if pnpm --filter frontend chromatic -d storybook-static $(echo "$CHROMATIC_PARAMETER"); then + echo "success=true" >> $GITHUB_OUTPUT + else + echo "success=false" >> $GITHUB_OUTPUT + fi + env: + CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + - name: Publish to Chromatic + if: github.event_name == 'pull_request_target' + id: chromatic_pull_request + run: | + DIFF="${{ steps.rev.outputs.base }} HEAD" + if [ "$DIFF" = "0000000000000000000000000000000000000000 HEAD" ]; then + DIFF="HEAD" + fi + CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff-tree --no-commit-id --name-only -r $(echo "$DIFF") | xargs))" + if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then + echo "skip=true" >> $GITHUB_OUTPUT + fi + BRANCH="${{ github.event.pull_request.head.user.login }}:${{ github.event.pull_request.head.ref }}" + if [ "$BRANCH" = "misskey-dev:${{ github.event.pull_request.head.ref }}" ]; then + BRANCH="${{ github.event.pull_request.head.ref }}" + fi + pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name $BRANCH $(echo "$CHROMATIC_PARAMETER") + env: + CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + - name: Notify that Chromatic detects changes + uses: actions/github-script@v7.0.1 + if: github.event_name != 'pull_request_target' && steps.chromatic_push.outputs.success == 'false' + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.repos.createCommitComment({ + owner: context.repo.owner, + repo: context.repo.repo, + commit_sha: context.sha, + body: 'Chromatic detects changes. Please [review the changes on Chromatic](https://www.chromatic.com/builds?appId=6428f7d7b962f0b79f97d6e4).' + }) + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: storybook + path: packages/frontend/storybook-static diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index a6c12e2824..49a6a39805 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -41,12 +41,12 @@ jobs: with: submodules: true - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.2 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -61,7 +61,7 @@ jobs: - name: Test run: pnpm --filter backend test-and-coverage - name: Upload to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/backend/coverage/coverage-final.json @@ -91,12 +91,12 @@ jobs: with: submodules: true - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.2 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -111,7 +111,7 @@ jobs: - name: Test run: pnpm --filter backend test-and-coverage:e2e - name: Upload to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/backend/coverage/coverage-final.json diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index 3fb880fac2..1e020b7368 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -33,12 +33,12 @@ jobs: with: submodules: true - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.2 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -53,7 +53,7 @@ jobs: - name: Test run: pnpm --filter frontend test-and-coverage - name: Upload Coverage - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/frontend/coverage/coverage-final.json @@ -91,12 +91,12 @@ jobs: #- uses: browser-actions/setup-firefox@latest # if: ${{ matrix.browser == 'firefox' }} - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: version: 7 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.2 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -115,6 +115,7 @@ jobs: run: pnpm exec cypress install - name: Cypress run uses: cypress-io/github-action@v6 + timeout-minutes: 15 with: install: false start: pnpm start:test diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml index 5aed385df9..f73bd0b08f 100644 --- a/.github/workflows/test-misskey-js.yml +++ b/.github/workflows/test-misskey-js.yml @@ -30,7 +30,7 @@ jobs: - run: corepack enable - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.2 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -50,21 +50,7 @@ jobs: CI: true - name: Upload Coverage - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/misskey-js/coverage/coverage-final.json - - check-version: - # ルートの package.json と packages/misskey-js/package.json のバージョンが一致しているかを確認する - name: Check version - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4.1.1 - - name: Check version - run: | - if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then - echo "Version mismatch!" - exit 1 - fi diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml index 9e02c0d8f8..77af08b6fe 100644 --- a/.github/workflows/test-production.yml +++ b/.github/workflows/test-production.yml @@ -23,12 +23,12 @@ jobs: with: submodules: true - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.2 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml index 93c4cf4cd1..36ed8d273f 100644 --- a/.github/workflows/validate-api-json.yml +++ b/.github/workflows/validate-api-json.yml @@ -24,12 +24,12 @@ jobs: with: submodules: true - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v3 with: version: 8 run_install: false - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.2 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/CHANGELOG.md b/CHANGELOG.md index cff0fc07cd..bafee277d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,15 +12,75 @@ --> -## 202x.x.x (Unreleased) +## 2024.3.1 + +### General +- + +### Client +- Fix: 絵文字関係の不具合を修正 (#13485) + - 履歴に残っている or ピン留めされた絵文字がコントロールパネルより削除されていた際にリアクションデッキが表示できなくなる + - Unicode絵文字が履歴に残っている or ピン留めされているとリアクションデッキが表示できなくなる +- Fix: カスタム絵文字の画像読み込みに失敗した際はテキストではなくダミー画像を表示 #13487 + +### Server +- + +## 2024.3.0 + +### General +- Enhance: 投稿者のロールに応じて、一つのノートに含むことのできるメンションとダイレクト投稿の宛先の人数に上限を設定できるように + * デフォルトのメンション上限は20アカウントに設定されます。(管理者はベースロールの設定で変更可能です。) + * 連合の問い合わせに応答しないサーバーのリモートユーザーへのメンションは、上限の人数に含めない実装になっています。 +- Enhance: 通知がミュート、凍結を考慮するようになりました +- Enhance: サーバーごとにモデレーションノートを残せるように +- Enhance: コンディショナルロールの条件に「マニュアルロールへのアサイン」を追加 +- Enhance: 通知の受信設定に「フォロー中またはフォロワー」を追加 +- Enhance: 通知の履歴をリセットできるように +- Fix: ダイレクトなノートに対してはダイレクトでしか返信できないように + +### Client +- Enhance: ノート作成画面のファイル添付メニューの区切り線の位置を調整 +- Fix: syuilo/misskeyの時代からあるインスタンスが改変されたバージョンであると誤認識される問題 +- Fix: MFMのオートコンプリートが出るべき状況で出ないことがある問題を修正 +- Fix: チャートのラベルが消えている問題を修正 +- Fix: 画面表示後最初の音声再生が爆音になることがある問題を修正 +- Fix: 設定のバックアップ作成時に名前を入力しなかった場合、ローカライゼーションがおかしくなる問題を修正 +- Fix: ページ`/admin/emojis`の絵文字編集ダイアログで「リアクションとして使えるロール」を追加する際に何も選択せずOKを押下すると画面が固まる問題を修正 +- Fix: 絵文字サジェストの順位で、絵文字自体の名前が同じものよりもタグで一致しているものが優先されてしまう問題を修正 +- Fix: ユーザの情報のポップアップが消えなくなることがある問題を修正 + +### Server +- Enhance: エンドポイント`flash/update`の`flashId`以外のパラメータは必須ではなくなりました +- Fix: nodeinfoにenableMcaptchaとenableTurnstileが無いのを修正 +- Fix: 破損した通知をクライアントに送信しないように + * 通知欄が無限にリロードされる問題が改善する可能性があります +- Fix: 禁止キーワードを含むノートがDelayed Queueに追加されて再処理される問題を修正 +- Fix: 自分がフォローしていないアカウントのフォロワー限定ノートが閲覧できることがある問題を修正 +- Fix: タイムラインのオプションで「リノートを表示」を無効にしている際、投票のみの引用リノートが流れてこない問題を修正 +- Fix: エンドポイント`admin/emoji/update`の各種修正 + - 必須パラメータを`id`または`name`のいずれかのみに + - `id`の代わりに`name`で絵文字を指定可能に(`id`・`name`両指定時は従来通り`name`を変更する挙動) + - `category`および`licence`が指定なしの時勝手にnullに上書きされる挙動を修正 +- Fix: 通知の受信設定で「相互フォロー」が正しく動作しない問題を修正 + +## 2024.2.0 ### Note -- 外部サイトからプラグインをインストールする場合のパスが`/install-extentions`から`/install-extensions`に変わります。現時点では以前のパスも利用できますが、非推奨です。 +- 外部サイトからプラグインをインストールする場合のパスが`/install-extentions`から`/install-extensions`に変わります。以前のパスからは自動でリダイレクトされるようになっていますが、新しいパスに変更することをお勧めします。 ### General - Feat: [mCaptcha](https://github.com/mCaptcha/mCaptcha)のサポートを追加 -- Fix: リストライムラインの「リノートを表示」が正しく機能しない問題を修正 - Feat: Add support for TrueMail +- Feat: AGPLv3ライセンスに誤って違反するのを防止する機能を追加 + - 管理者がrepositoryUrlを変更したり、またはソースコードを直接頒布することを選択できるようになります + - 本体のソースコードに改変を加えた際に、ライセンスに基づく適切な案内を表示します +- Enhance: モデレーターはすべてのユーザーのリアクション一覧を見られるように +- Fix: リストライムラインの「リノートを表示」が正しく機能しない問題を修正 +- Fix: リモートユーザーのリアクション一覧がすべて見えてしまうのを修正 + * すべてのリモートユーザーのリアクション一覧を見えないようにします +- Fix: 特定のキーワード及び正規表現にマッチする文字列を含むノートが投稿された際、エラーに出来るような設定項目を追加 #13207 + * デフォルトは空欄なので適用前と同等の動作になります ### Client - Feat: 新しいゲームを追加 @@ -45,26 +105,52 @@ - Enhance: ノート作成画面のファイル添付メニューから直接ファイルを削除できるように - Enhance: MFMの属性でオートコンプリートが使用できるように #12735 - Enhance: 絵文字編集ダイアログをモーダルではなくウィンドウで表示するように +- Enhance: リモートのユーザーはメニューから直接リモートで表示できるように +- Enhance: リモートへの引用リノートと同一のリンクにはリンクプレビューを表示しないように +- Enhance: コードのシンタックスハイライトにテーマを適用できるように +- Enhance: リアクション権限がない場合、ハートにフォールバックするのではなくリアクションピッカーなどから打てないように + - リモートのユーザーにローカルのみのカスタム絵文字をリアクションしようとした場合 + - センシティブなリアクションを認めていないユーザーにセンシティブなカスタム絵文字をリアクションしようとした場合 + - ロールが必要な絵文字をリアクションしようとした場合 +- Enhance: ページ遷移時にPlayerを閉じるように +- Enhance: 通報ページのユーザをクリックした際にユーザをウィンドウで開くように +- Enhance: ノートの通報時にリモートのノートであっても自インスタンスにおけるノートのリンクを含むように +- Enhance: オフライン表示のデザインを改善・多言語対応 - Fix: ネイティブモードの絵文字がモノクロにならないように - Fix: v2023.12.0で追加された「モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能」が管理画面上で正しく表示されていない問題を修正 - Fix: AiScriptの`readline`関数が不正な値を返すことがある問題のv2023.12.0時点での修正がPlay以外に適用されていないのを修正 - Fix: v2023.12.1で追加された`$[clickable ...]`および`onClickEv`が正しく機能していないのを修正 -- Enhance: ページ遷移時にPlayerを閉じるように +- Fix: Renoteのキーボードショートカットが機能していなかった問題を修正 +- Fix: 投稿フォームでアンケートの日時指定をした状態で再読み込みをすると期日が復元されない問題を修正 +- Fix: アンケートを設定したノートを「削除して編集」をするとアンケートの期日が引き継がれず、リセットされてしまう問題を修正 +- Fix: デッキのプロファイル作成時に名前を空にできる問題を修正 +- Fix: テーマ作成時に名称が空欄でも作成できてしまう問題を修正 +- Fix: プラグインで`Plugin:register_note_post_interruptor`を使用すると、ノートが投稿できなくなる問題を修正 +- Fix: iOSで大きな画像を変換してアップロードできない問題を修正 +- Fix: 「アニメーション画像を再生しない」もしくは「データセーバー(アイコン)」を有効にしていても、アイコンデコレーションのアニメーションが停止されない問題を修正 +- Fix: 画像をクロップするとクロップ後の解像度が異様に低くなる問題の修正 +- Fix: 画像をクロップ時、正常に完了できない問題の修正 +- Fix: キャプションが空の画像をクロップするとキャプションにnullという文字列が入ってしまう問題の修正 +- Fix: プロフィールを編集してもリロードするまで反映されない問題を修正 +- Fix: エラー画像URLを設定した後解除すると,デフォルトの画像が表示されない問題の修正 +- Fix: MkCodeEditorで行がずれていってしまう問題の修正 +- Fix: Summaly proxy利用時にプレイヤーが動作しないことがあるのを修正 #13196 ### Server -- Enhance: 連合先のレートリミットに引っかかった際にリトライするようになりました +- Enhance: 連合先のレートリミットを超過した際にリトライするようになりました - Enhance: ActivityPub Deliver queueでBodyを事前処理するように (#12916) - Enhance: クリップをエクスポートできるように - Enhance: `/files`のファイルに対してHTTP Rangeリクエストを行えるように - Enhance: `api.json`のOpenAPI Specificationを3.1.0に更新 +- Enhance: 連合向けのノート配信を軽量化 #13192 - Fix: `drive/files/update`でファイル名のバリデーションが機能していない問題を修正 - Fix: `notes/create`で、`text`が空白文字のみで構成されているか`null`であって、かつ`text`だけであるリクエストに対するレスポンスが400になるように変更 - Fix: `notes/create`で、`text`が空白文字のみで構成されていてかつリノート、ファイルまたは投票を含んでいるリクエストに対するレスポンスの`text`が`""`から`null`になるように変更 - Fix: ipv4とipv6の両方が利用可能な環境でallowedPrivateNetworksが設定されていた場合プライベートipの検証ができていなかった問題を修正 - Fix: properly handle cc followers - -### Service Worker -- Enhance: オフライン表示のデザインを改善・多言語対応 +- Fix: ジョブに関する設定の名前を修正 relashionshipJobPerSec -> relationshipJobPerSec +- Fix: コントロールパネル->モデレーション->「誰でも新規登録できるようにする」の初期値をONからOFFに変更 #13122 +- Fix: リモートユーザーが復活してもキャッシュにより該当ユーザーのActivityが受け入れられないのを修正 #13273 ## 2023.12.2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7f6c1f4f82..a3263bf6aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -122,6 +122,19 @@ command. If you have not changed it from the default, it will be "http://localhost:3000". If "port" in .config/default.yml is set to something other than 3000, you need to change the proxy settings in packages/frontend/vite.config.local-dev.ts. +### `MK_DEV_PREFER=backend pnpm dev` +pnpm dev has another mode with `MK_DEV_PREFER=backend`. + +``` +MK_DEV_PREFER=backend pnpm dev +``` + +- This mode is closer to the production environment than the default mode. +- Vite runs behind the backend (the backend will proxy Vite at /vite). +- You can see Misskey by accessing `http://localhost:3000` (Replace `3000` with the port configured with `port` in .config/default.yml). +- To change the port of Vite, specify with `VITE_PORT` environment variable. +- HMR may not work in some environments such as Windows. + ### Dev Container Instead of running `pnpm` locally, you can use Dev Container to set up your development environment. To use Dev Container, open the project directory on VSCode with Dev Containers installed. @@ -286,18 +299,17 @@ export const argTypes = { min: 1, max: 4, }, + }, }; ``` Also, you can use msw to mock API requests in the storybook. Creating a `MyComponent.stories.msw.ts` file to define the mock handlers. ```ts -import { rest } from 'msw'; +import { HttpResponse, http } from 'msw'; export const handlers = [ - rest.post('/api/notes/timeline', (req, res, ctx) => { - return res( - ctx.json([]), - ); + http.post('/api/notes/timeline', ({ request }) => { + return HttpResponse.json([]); }), ]; ``` diff --git a/Dockerfile b/Dockerfile index a8d3dbcd89..ee3a30a3c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,13 +27,13 @@ COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"] COPY --link ["packages/misskey-reversi/package.json", "./packages/misskey-reversi/"] COPY --link ["packages/misskey-bubble-game/package.json", "./packages/misskey-bubble-game/"] +ARG NODE_ENV=production + RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ pnpm i --frozen-lockfile --aggregate-output COPY --link . ./ -ARG NODE_ENV=production - RUN git submodule update --init RUN pnpm build RUN rm -rf .git/ @@ -57,6 +57,8 @@ COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"] COPY --link ["packages/misskey-reversi/package.json", "./packages/misskey-reversi/"] COPY --link ["packages/misskey-bubble-game/package.json", "./packages/misskey-bubble-game/"] +ARG NODE_ENV=production + RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ pnpm i --frozen-lockfile --aggregate-output diff --git a/README.md b/README.md index 6fa804f1fa..24013a7bd8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@
- Misskey logo + Misskey logo -**🌎 **[Misskey](https://misskey-hub.net/)** is an open source, decentralized social media platform that's free forever! 🚀** +**🌎 **Misskey** is an open source, federated social media platform that's free forever! 🚀** + +[Learn more](https://misskey-hub.net/) --- @@ -22,41 +24,6 @@ become a patron ---- - -[![codecov](https://codecov.io/gh/misskey-dev/misskey/branch/develop/graph/badge.svg?token=R6IQZ3QJOL)](https://codecov.io/gh/misskey-dev/misskey) - -
- -
- - - -## ✨ Features -- **ActivityPub support**\ -Not on Misskey? No problem! Not only can Misskey instances talk to each other, but you can make friends with people on other networks like Mastodon and Pixelfed! -- **Reactions**\ -You can add emoji reactions to any post! No longer are you bound by a like button, show everyone exactly how you feel with the tap of a button. -- **Drive**\ -With Misskey's built in drive, you get cloud storage right in your social media, where you can upload any files, make folders, and find media from posts you've made! -- **Rich Web UI**\ - Misskey has a rich and easy to use Web UI! - It is highly customizable, from changing the layout and adding widgets to making custom themes. - Furthermore, plugins can be created using AiScript, an original programming language. -- And much more... - -
- -
- -## Documentation - -Misskey Documentation can be found at [Misskey Hub](https://misskey-hub.net/docs/), some of the links and graphics above also lead to specific portions of it. - -## Sponsors - -
- RSS3
## Thanks diff --git a/cypress/e2e/basic.cy.js b/cypress/e2e/basic.cy.js index d20b28c49f..604241d13c 100644 --- a/cypress/e2e/basic.cy.js +++ b/cypress/e2e/basic.cy.js @@ -162,12 +162,12 @@ describe('After user signed in', () => { it('successfully loads', () => { // 表示に時間がかかるのでデフォルト秒数だとタイムアウトする - cy.get('[data-cy-user-setup-continue]', { timeout: 12000 }).should('be.visible'); + cy.get('[data-cy-user-setup-continue]', { timeout: 30000 }).should('be.visible'); }); it('account setup wizard', () => { // 表示に時間がかかるのでデフォルト秒数だとタイムアウトする - cy.get('[data-cy-user-setup-continue]', { timeout: 12000 }).click(); + cy.get('[data-cy-user-setup-continue]', { timeout: 30000 }).click(); cy.get('[data-cy-user-setup-user-name] input').type('ありす'); cy.get('[data-cy-user-setup-user-description] textarea').type('ほげ'); @@ -205,7 +205,7 @@ describe('After user setup', () => { // アカウント初期設定ウィザード // 表示に時間がかかるのでデフォルト秒数だとタイムアウトする - cy.get('[data-cy-user-setup] [data-cy-modal-window-close]', { timeout: 12000 }).click(); + cy.get('[data-cy-user-setup] [data-cy-modal-window-close]', { timeout: 30000 }).click(); cy.get('[data-cy-modal-dialog-ok]').click(); }); diff --git a/cypress/e2e/router.cy.js b/cypress/e2e/router.cy.js new file mode 100644 index 0000000000..6de27be5f4 --- /dev/null +++ b/cypress/e2e/router.cy.js @@ -0,0 +1,30 @@ +describe('Router transition', () => { + describe('Redirect', () => { + // サーバの初期化。ルートのテストに関しては各describeごとに1度だけ実行で十分だと思う(使いまわした方が早い) + before(() => { + cy.resetState(); + + // インスタンス初期セットアップ + cy.registerUser('admin', 'pass', true); + + // ユーザー作成 + cy.registerUser('alice', 'alice1234'); + + cy.login('alice', 'alice1234'); + + // アカウント初期設定ウィザード + // 表示に時間がかかるのでデフォルト秒数だとタイムアウトする + cy.get('[data-cy-user-setup] [data-cy-modal-window-close]', { timeout: 30000 }).click(); + cy.wait(500); + cy.get('[data-cy-modal-dialog-ok]').click(); + }); + + it('redirect to user profile', () => { + // テストのためだけに用意されたリダイレクト用ルートに飛ぶ + cy.visit('/redirect-test'); + + // プロフィールページのURLであることを確認する + cy.url().should('include', '/@alice') + }); + }); +}); diff --git a/healthcheck.sh b/healthcheck.sh index 0a36394836..d6d416c7a1 100644 --- a/healthcheck.sh +++ b/healthcheck.sh @@ -1,6 +1,6 @@ #!/bin/bash -# SPDX-FileCopyrightText: syuilo and other misskey contributors +# SPDX-FileCopyrightText: syuilo and misskey-project # SPDX-License-Identifier: AGPL-3.0-only PORT=$(grep '^port:' /misskey/.config/default.yml | awk 'NR==1{print $2; exit}') diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 47f131032a..17c8f24fa5 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -1011,8 +1011,10 @@ expired: "منتهية صلاحيته" icon: "الصورة الرمزية" replies: "رد" renotes: "أعد النشر" +sourceCode: "الشفرة المصدرية" flip: "اقلب" lastNDays: "آخر {n} أيام" +surrender: "ألغِ" _initialAccountSetting: accountCreated: "نجح إنشاء حسابك!" letsStartAccountSetup: "إذا كنت جديدًا لنعدّ حسابك الشخصي." diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index 42edad1fd0..2a23cda06b 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -855,6 +855,7 @@ youFollowing: "অনুসরণ করা হচ্ছে" icon: "প্রোফাইল ছবি" replies: "জবাব" renotes: "রিনোট" +sourceCode: "সোর্স কোড" flip: "উল্টান" _role: priority: "অগ্রাধিকার" diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index b2b0ee0d5a..2ea6bd9309 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -130,6 +130,7 @@ overwriteFromPinnedEmojis: "Sobreescriu des dels emojis fixats" reactionSettingDescription2: "Arrossega per reordenar, fes clic per suprimir, prem \"+\" per afegir." rememberNoteVisibility: "Recorda la configuració de visibilitat de les notes" attachCancel: "Eliminar el fitxer adjunt" +deleteFile: "Esborrar l'arxiu " markAsSensitive: "Marcar com a NSFW" unmarkAsSensitive: "Deixar de marcar com a sensible" enterFileName: "Defineix nom del fitxer" @@ -1039,6 +1040,15 @@ rolesAssignedToMe: "Rols assignats " resetPasswordConfirm: "Vols canviar la teva contrasenya?" sensitiveWords: "Paraules sensibles" sensitiveWordsDescription: "La visibilitat de totes les notes que continguin qualsevol de les paraules configurades seran, automàticament, afegides a \"Inici\". Pots llistar diferents paraules separant les per línies noves." +sensitiveWordsDescription2: "Fent servir espais crearà expressions AND si l'expressió s'envolta amb barres inclinades es converteix en una expressió regular." +prohibitedWords: "Paraules prohibides" +prohibitedWordsDescription: "Quan intenteu publicar una Nota que conté una paraula prohibida, feu que es converteixi en un error. Es poden dividir i establir múltiples línies." +prohibitedWordsDescription2: "Fent servir espais crearà expressions AND si l'expressió s'envolta amb barres inclinades es converteix en una expressió regular." +hiddenTags: "Etiquetes ocultes" +hiddenTagsDescription: "La visibilitat de totes les notes que continguin qualsevol de les paraules configurades seran, automàticament, afegides a \"Inici\". Pots llistar diferents paraules separant les per línies noves." +notesSearchNotAvailable: "La cerca de notes no es troba disponible." +license: "Llicència" +unfavoriteConfirm: "Esborrar dels favorits?" myClips: "Els meus retalls" drivecleaner: "Netejador de Disc" retryAllQueuesNow: "Prova de nou d'executar totes les cues" @@ -1048,6 +1058,14 @@ enableChartsForRemoteUser: "Generar gràfiques d'usuaris remots" enableChartsForFederatedInstances: "Generar gràfiques d'instàncies remotes" showClipButtonInNoteFooter: "Afegir \"Retall\" al menú d'acció de la nota" reactionsDisplaySize: "Mida de les reaccions" +limitWidthOfReaction: "Limitar l'amplada màxima de la reacció i mostrar-les en una mida reduïda " +noteIdOrUrl: "ID o URL de la nota" +video: "Vídeo" +videos: "Vídeos " +audio: "So" +audioFiles: "So" +dataSaver: "Economitzador de dades" +accountMigration: "Migració del compte" accountMoved: "Aquest usuari té un compte nou:" accountMovedShort: "Aquest compte ha sigut migrat" operationForbidden: "Operació no permesa " @@ -1098,10 +1116,58 @@ branding: "Marca" enableServerMachineStats: "Publicar estadístiques del maquinari del servidor" enableIdenticonGeneration: "Activar la generació d'icones d'identificació " turnOffToImprovePerformance: "Desactivant aquesta opció es pot millorar el rendiment." +createInviteCode: "Crear codi d'invitació " +createWithOptions: "Crear invitació amb opcions" +createCount: "Comptador d'invitacions " +inviteCodeCreated: "Invitació creada" +inviteLimitExceeded: "Has sobrepassat el límit d'invitacions que pots crear." +createLimitRemaining: "Et queden {limit} invitacions restants" +inviteLimitResetCycle: "Cada {time} {limit} invitacions." +expirationDate: "Data de venciment" +noExpirationDate: "Sense data de venciment" +inviteCodeUsedAt: "Codi d'invitació fet servir el" +registeredUserUsingInviteCode: "Codi d'invitació fet servir per l'usuari " +waitingForMailAuth: "Esperant la verificació per correu electrònic " +inviteCodeCreator: "Invitació creada per" +usedAt: "Utilitzada el" +unused: "Sense utilitzar" +used: "Utilitzada" +expired: "Caducat" +doYouAgree: "Estàs d'acord?" +beSureToReadThisAsItIsImportant: "Llegeix això perquè és molt important." +iHaveReadXCarefullyAndAgree: "He llegit {x} i estic d'acord." +dialog: "Diàleg " icon: "Icona" +forYou: "Per a tu" +currentAnnouncements: "Informes actuals" +pastAnnouncements: "Informes passats" +youHaveUnreadAnnouncements: "Tens informes per llegir." +useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey." replies: "Respondre" renotes: "Impulsa" +loadReplies: "Mostrar les respostes" +loadConversation: "Mostrar la conversació " +pinnedList: "Llista fixada" +keepScreenOn: "Mantenir la pantalla encesa" +verifiedLink: "La propietat de l'enllaç ha sigut verificada" +notifyNotes: "Notificar quan hi hagi notes noves" +unnotifyNotes: "Deixar de notificar quan hi hagi notes noves" +authentication: "Autenticació " +authenticationRequiredToContinue: "Si us plau autentificat per continuar" +dateAndTime: "Data i hora" +showRenotes: "Mostrar impulsos" +edited: "Editat" +notificationRecieveConfig: "Paràmetres de notificacions" +mutualFollow: "Seguidor mutu" +fileAttachedOnly: "Només notes amb adjunts" +showRepliesToOthersInTimeline: "Mostrar les respostes a altres a la línia de temps" +hideRepliesToOthersInTimeline: "Amagar les respostes a altres a la línia de temps" +showRepliesToOthersInTimelineAll: "Mostrar les respostes a altres a usuaris que segueixes a la línia de temps" +hideRepliesToOthersInTimelineAll: "Ocultar les teves respostes a tots els usuaris que segueixes a la línia de temps" +confirmShowRepliesAll: "Aquesta opció no té marxa enrere. Vols mostrar les teves respostes a tots els que segueixes a la teva línia de temps?" +confirmHideRepliesAll: "Aquesta opció no té marxa enrere. Vols ocultar les teves respostes a tots els usuaris que segueixes a la línia de temps?" externalServices: "Serveis externs" +sourceCode: "Codi font" impressum: "Impressum" impressumUrl: "Adreça URL impressum" impressumDescription: "A països, com Alemanya, la inclusió de la informació de contacte de l'operador (un Impressum) és requereix de manera legal per llocs comercials." @@ -1131,7 +1197,26 @@ seasonalScreenEffect: "Efectes de pantalla segons les estacions" decorate: "Decorar" addMfmFunction: "Afegeix funcions MFM" enableQuickAddMfmFunction: "Activar accés ràpid per afegir funcions MFM" +bubbleGame: "Bubble Game" +sfx: "Efectes de so" +soundWillBePlayed: "Es reproduiran efectes de so" +showReplay: "Veure reproducció" +replay: "Reproduir" +replaying: "Reproduint" +ranking: "Classificació" lastNDays: "Últims {n} dies" +backToTitle: "Torna al títol" +hemisphere: "Geolocalització" +withSensitive: "Incloure notes amb fitxers sensibles" +userSaysSomethingSensitive: "La publicació de {name} conte material sensible" +enableHorizontalSwipe: "Lliscar per canviar de pestanya" +surrender: "Cancel·lar " +_bubbleGame: + howToPlay: "Com es juga" + _howToPlay: + section1: "Ajusta la posició i deixa caure l'objecte dintre la caixa." + section2: "Quan dos objectes del mateix tipus es toquen, canviaran en un objecte diferent i guanyares punts." + section3: "El joc s'acabarà quan els objectes sobresurtin de la caixa. Intenta aconseguir la puntuació més gran possible fusionant objectes mentre impedeixes que sobresurtin de la caixa!" _announcement: forExistingUsers: "Anunci per usuaris registrats" forExistingUsersDescription: "Aquest avís només es mostrarà als usuaris existents fins al moment de la publicació. Si no també es mostrarà als usuaris que es registrin després de la publicació." @@ -1153,38 +1238,781 @@ _initialAccountSetting: privacySetting: "Configuració de seguretat" theseSettingsCanEditLater: "Aquests ajustos es poden canviar més tard." youCanEditMoreSettingsInSettingsPageLater: "A més d'això, es poden fer diferents configuracions a través de la pàgina de configuració. Assegureu-vos de comprovar-ho més tard." + followUsers: "Prova de seguir usuaris que t'interessin per construir la teva línia de temps." + pushNotificationDescription: "Activant les notificacions emergents et permetrà rebre notificacions de {name} directament al teu dispositiu." + initialAccountSettingCompleted: "Configuració del perfil completada!" + haveFun: "Disfruta {name}!" + youCanContinueTutorial: "Pots continuar amb un tutorial per aprendre a Fer servir {name} (MissKey) o tu pots estalviar i començar a fer-lo servir ja." + startTutorial: "Començar el tutorial" + skipAreYouSure: "Et vols saltar la configuració del perfil?" + laterAreYouSure: "Vols continuar la configuració del perfil més tard?" +_initialTutorial: + launchTutorial: "Començar tutorial" + title: "Tutorial" + wellDone: "Ben fet!" + skipAreYouSure: "Sortir del tutorial?" + _landing: + title: "Benvingut al tutorial" + description: "Aquí aprendràs el bàsic per poder fer servir Misskey i les seves característiques." + _note: + title: "Què és una Nota?" + description: "Les publicacions a Misskey es diuen 'Notes'. Les Notes s'ordenen cronològicament a la línia de temps i s'actualitzen de forma automàtica." + reply: "Fes clic en aquest botó per contestar a un missatge. També és possible contestar a una contestació, continuant la conversació en forma de fil." + renote: "Pots compartir una Nota a la teva pròpia línia de temps. Inclús pots citar-les amb els teus comentaris." + reaction: "Pots afegir reaccions a les Notes. Entrarem més en detall a la pròxima pàgina." + menu: "Pots veure els detalls de les Notes, copiar enllaços i fer diferents accions." + _reaction: + title: "Què són les Reaccions?" + description: "Es poden reaccionar a les Notes amb diferents emoticones. Les reaccions et permeten expressar matisos que hi són més enllà d'un simple m'agrada." + letsTryReacting: "Es poden afegir reaccions fent clic al botó '+'. Prova reaccionant a aquesta nota!" + reactToContinue: "Afegeix una reacció per continuar." + reactNotification: "Rebràs notificacions en temps real quan un usuari reaccioni a les teves notes." + reactDone: "Pots desfer una reacció fent clic al botó '-'." + _timeline: + title: "El concepte de les línies de temps" + description1: "Misskey mostra diferents línies de temps basades en l'ús (algunes poden no estar disponibles depenent de la política del servidor)" + home: "Pots veure notes dels comptes que segueixes" + local: "Pots veure les notes dels usuaris del servidor." + social: "Es mostren les notes de les línies de temps d'Inici i Local." + global: "Pots veure les notes de tots els servidors connectats." + description2: "Pots canviar la línia de temps en qualsevol moment fent servir la barra de la pantalla superior." + description3: "A més hi ha línies de temps per llistes i per canals. Si vols saber més {link}." + _postNote: + title: "Configuració de la publicació de les notes" + description1: "Quan públiques una nota a Misskey hi ha diferents opcions disponibles. El formulari de publicació es veu així" + _visibility: + description: "Pots limitar qui pot veure les teves notes." + public: "La teva nota serà visible per a tots els usuaris." + home: "Publicar només a línia de temps d'Inici. La gent que visiti el teu perfil o mitjançant les remotes també la podran veure." + followers: "Només visible per a seguidors. Només els teus seguidors la podran veure i ningú més. Ningú més podrà fer renotes." + direct: "Només visible per a alguns seguidors, el destinatari rebre una notificació. Es pot fer servir com una alternativa als missatges directes." + doNotSendConfidencialOnDirect1: "Tingues cura quan enviïs informació sensible." + doNotSendConfidencialOnDirect2: "Els administradors del servidor poden veure tot el que escrius. Ves compte quan enviïs informació sensible en enviar notes directes a altres usuaris en servidors de poca confiança." + localOnly: "Publicar amb aquesta opció activada farà que la nota no federi amb altres servidors. Els usuaris d'altres servidors no podran veure la nota directament, sense importar les opcions de visualització." + _cw: + title: "Avís de Contingut (CW)" + description: "En comptes del cos de la nota es mostrarà el que s'escrigui al camp de 'comentaris'. Fent clic a 'Llegir més' es mostrarà el cos." + _exampleNote: + cw: "Això et farà venir gana!" + note: "Acabo de menjar-me un donut de xocolata 🍩😋" + useCases: "Això es fa servir per seguir normes del servidor sobre certes notes o per ocultar contingut sensible O revelador." + _howToMakeAttachmentsSensitive: + title: "Com marcar adjunts com a contingut sensible?" + description: "Per adjunts que sigui requerit per les normes del servidor o que puguin contenir material sensible, s'ha d'afegir l'opció 'sensible'." + tryThisFile: "Prova de marcar la imatge adjunta en aquest formulari com a sensible!" + _exampleNote: + note: "Oops! L'he fet bona en obrir la tapa de Nocilla..." + method: "Per marcar un adjunt com a sensible, fes clic a la miniatura de l'adjunt, obre el menú i fes clic a 'Marcar com a sensible'." + sensitiveSucceeded: "Quan adjuntis fitxers si us plau marca la sensibilitat seguint les normes del servidor." + doItToContinue: "Marca el fitxer adjunt com a sensible per poder continuar." + _done: + title: "Has completat el tutorial 🎉" + description: "Les funcions explicades aquí és una petita mostra. Per una explicació més detallada de com fer servir MissKey consulta {link}." +_timelineDescription: + home: "A la línia de temps d'Inici pots veure les notes dels usuaris que segueixes." + local: "A la línia de temps Local pots veure les notes de tots els usuaris d'aquest servidor." + social: "La línia de temps Social mostren les notes de les línies de temps d'Inici i Local." + global: "A la línia de temps Global pots veure les notes de tots els servidors connectats." +_serverRules: + description: "Un conjunt de regles que seran mostrades abans de registrar-se. Es recomanable configurar un resum dels termes d'ús." +_serverSettings: + iconUrl: "URL de la icona" + appIconDescription: "Especifica la icona que es mostrarà quan el {host} es mostri en una aplicació." + appIconUsageExample: "Per exemple com a PWA, o quan es mostri com un favorit a la pàgina d'inici del telèfon mòbil" + appIconStyleRecommendation: "Com la icona pot ser retallada com un cercle o un quadrat, es recomana fer servir una icona amb un marge acolorit que l'envolti." + appIconResolutionMustBe: "La resolució mínima és {resolution}." + manifestJsonOverride: "Sobreescriure manifest.json" + shortName: "Nom curt" + shortNameDescription: "Una abreviatura del nom de la instància que es poguí mostrar en cas que el nom oficial sigui massa llarg" + fanoutTimelineDescription: "Quan es troba activat millora bastant el rendiment quan es recuperen les línies de temps i redueix la carrega de la base de dades. Com a contrapunt, l'ús de memòria de Redis es veurà incrementada. Considera d'estabilitat aquesta opció en cas de tenir un servidor amb poca memòria o si tens problemes de inestabilitat." + fanoutTimelineDbFallback: "Carregar de la base de dades" + fanoutTimelineDbFallbackDescription: "Quan s'activa, la línia de temps fa servir la base de dades per consultes adicionals si la línia de temps no es troba a la memòria cau. Si és desactiva la càrrega del servidor és veure reduïda, però també és reduirà el nombre de línies de temps que és poden obtenir." +_accountMigration: + moveFrom: "Migrar un altre compte a aquest" + moveFromSub: "Crear un àlies per un altre compte" + moveFromLabel: "Compte original #{n}" + moveFromDescription: "Has de crear un àlies del compte que vols migrar en aquest compte.\nFes servir aquest format per posar el compte que vols migrar: @nomusuari@servidor.exemple.com\nPer esborrar l'àlies deixa el camp en blanc (no és recomanable de fer)" + moveTo: "Migrar aquest compte a un altre" + moveToLabel: "Compte al qual es vol migrar:" + moveCannotBeUndone: "Les migracions dels comptes no es poden desfer." + moveAccountDescription: "Això migrarà la teva compte a un altre diferent.\n ・Els seguidors d'aquest compte és passaran al compte nou de forma automàtica\n ・Es deixaran de seguir a tots els usuaris que es segueixen actualment en aquest compte\n ・No es poden crear notes noves, etc. en aquest compte\n\nSi bé la migració de seguidors es automàtica, has de preparar alguns pasos manualment per migrar la llista d'usuaris que segueixes. Per fer això has d'exportar els seguidors que després importaraes al compte nou mitjançant el menú de configuració. El mateix procediment s'ha de seguir per less teves llistes i els teus usuaris silenciats i bloquejats.\n\n(Aquesta explicació s'aplica a Misskey v13.12.0 i posteriors. Altres aplicacions, com Mastodon, poden funcionar diferent.)" + moveAccountHowTo: "Per fer la migració, primer has de crear un àlies per aquest compte al compte al qual vols migrar.\nDesprés de crear l'àlies, introdueix el compte al qual vols migrar amb el format següent: @nomusuari@servidor.exemple.com" + startMigration: "Migrar" + migrationConfirm: "Vols migrar aquest compte a {account}? Una vegada comenci la migració no es podrà parar O fer marxa enrere i no podràs tornar a fer servir aquest compte mai més." + movedAndCannotBeUndone: "Aquest compte ha migrat.\nLes migracions no es poden desfer." + postMigrationNote: "Aquest compte deixarà de seguir tots els comptes que segueix 24 hores després de germinar la migració.\nEl nombre de seguidors i seguits passarà a ser de zero. Per evitar que els teus seguidors no puguin veure les publicacions marcades com a només seguidors continuaren seguint aquest compte." + movedTo: "Nou compte:" +_achievements: + earnedAt: "Desbloquejat el" + _types: + _notes1: + title: "Aquí, configurant el meu msky" + description: "Publica la teva primera Nota" + flavor: "Passa-t'ho bé fent servir Miskey!" + _notes10: + title: "Algunes notes" + description: "Publica 10 notes" + _notes100: + title: "Un piló de notes" + description: "Publica 100 notes" + _notes500: + title: "Cobert de notes" + description: "Publica 500 notes" + _notes1000: + title: "Un piló de notes" + description: "1 000 notes publicades" + _notes5000: + title: "Desbordament de notes" + description: "5 000 notes publicades" + _notes10000: + title: "Supernota" + description: "10 000 notes publicades" + _notes20000: + title: "Necessito... Més... Notes!" + description: "20 000 notes publicades" + _notes30000: + title: "Notes notes notes!" + description: "30 000 notes publicades" + _notes40000: + title: "Fàbrica de notes" + description: "40 000 notes publicades" + _notes50000: + title: "Planeta de notes" + description: "50 000 notes publicades" + _notes60000: + title: "Quàsar de notes" + description: "60 000 notes publicades" + _notes70000: + title: "Forat negre de notes" + description: "70 000 notes publicades" + _notes80000: + title: "Galàxia de notes" + description: "80 000 notes publicades" + _notes90000: + title: "Univers de notes" + description: "90 000 notes publicades" + _notes100000: + title: "ALL YOUR NOTE ARE BELONG TO US" + description: "100 000 notes publicades" + flavor: "Segur que tens moltes coses a dir?" + _login3: + title: "Principiant I" + description: "Vas iniciar sessió fa tres dies" + flavor: "Des d'avui diguem Misskist" + _login7: + title: "Principiant II" + description: "Vas iniciar sessió fa set dies" + flavor: "Ja saps com va funcionant tot?" + _login15: + title: "Principiant III" + description: "Vas iniciar sessió fa quinze dies" + _login30: + title: "Misskist I" + description: "Vas iniciar sessió fa trenta dies" + _login60: + title: "Misskist II" + description: "Vas iniciar sessió fa seixanta dies" + _login100: + title: "Misskist III" + description: "Vas iniciar sessió fa cent dies" + flavor: "Misskist violent" + _login200: + title: "Regular I" + description: "Vas iniciar sessió fa dos-cents dies" + _login300: + title: "Regular II" + description: "Vas iniciar sessió fa tres-cents dies" + _login400: + title: "Regular III" + description: "Vas iniciar sessió fa quatre-cents dies" + _login500: + title: "Expert I" + description: "Vas iniciar sessió fa cinc-cents dies" + flavor: "Amics, he dit massa vegades que soc un amant de les notes" + _login600: + title: "Expert II" + description: "Vas iniciar sessió fa sis-cents dies" + _login700: + title: "Expert III" + description: "Vas iniciar sessió fa set-cents dies" + _login800: + title: "Mestre de les Notes I" + description: "Vas iniciar sessió fa vuit-cents dies " + _login900: + title: "Mestre de les Notes II" + description: "Vas iniciar sessió fa nou-cents dies" + _login1000: + title: "Mestre de les Notes III" + description: "Vas iniciar sessió fa mil dies" + flavor: "Gràcies per fer servir MissKey!" + _noteClipped1: + title: "He de retallar-te!" + description: "Retalla la teva primera nota" + _noteFavorited1: + title: "Quan miro les estrelles" + description: "La primera vegada que vaig registrar el meu favorit" + _myNoteFavorited1: + title: "Vull una estrella" + description: "La meva nota va ser registrada com favorita per una de les altres persones" + _profileFilled: + title: "Estic a punt" + description: "Vaig fer la configuració de perfil" + _markedAsCat: + title: "Soc un gat" + description: "He establert el meu compte com si fos un Gat" + flavor: "Encara no tinc nom" + _following1: + title: "És el meu primer seguiment" + description: "És la primera vegada que et segueixo" + _following10: + title: "Segueix-me... Segueix-me..." + description: "Seguir 10 usuaris" + _following50: + title: "Molts amics" + description: "Seguir 50 comptes" + _following100: + title: "100 amics" + description: "Segueixes 100 comptes" + _following300: + title: "Sobrecàrrega d'amics" + description: "Segueixes 300 comptes" + _followers1: + title: "Primer seguidor" + description: "1 seguidor guanyat" + _followers10: + title: "Segueix-me!" + description: "10 seguidors guanyats" + _followers50: + title: "Venen en manada" + description: "50 seguidors guanyats" + _followers100: + title: "Popular" + description: "100 seguidors guanyats" + _followers300: + title: "Si us plau, d'un en un!" + description: "300 seguidors guanyats" + _followers500: + title: "Torre de ràdio" + description: "500 seguidors guanyats" + _followers1000: + title: "Influenciador" + description: "1 000 seguidors guanyats" + _collectAchievements30: + title: "Col·leccionista d'èxits " + description: "Desbloqueja 30 assoliments" + _viewAchievements3min: + title: "M'agraden els èxits " + description: "Mira la teva llista d'assoliments durant més de 3 minuts" + _iLoveMisskey: + title: "Estimo Misskey" + description: "Publica \"I ❤ #Misskey\"" + flavor: "L'equip de desenvolupament de Misskey agraeix el vostre suport!" + _foundTreasure: + title: "A la Recerca del Tresor" + description: "Has trobat el tresor amagat" + _client30min: + title: "Parem una estona" + description: "Mantingues obert Misskey per 30 minuts" + _client60min: + title: "A totes amb Misskey" + description: "Mantingues Misskey obert per 60 minuts" + _noteDeletedWithin1min: + title: "No et preocupis" + description: "Esborra una nota al minut de publicar-la" + _postedAtLateNight: + title: "Nocturn" + description: "Publica una nota a altes hores de la nit " + flavor: "És hora d'anar a dormir." + _postedAt0min0sec: + title: "Rellotge xerraire" + description: "Publica una nota a les 0:00" + flavor: "Tic tac, tic tac, tic tac, DING!" + _selfQuote: + title: "Autoreferència " + description: "Cita una nota teva" + _htl20npm: + title: "Línia de temps fluida" + description: "La teva línia de temps va a més de 20npm (notes per minut)" + _viewInstanceChart: + title: "Analista " + description: "Mira els gràfics de la teva instància " + _outputHelloWorldOnScratchpad: + title: "Hola, món!" + description: "Escriu \"hola, món\" al bloc de notes" + _open3windows: + title: "Multi finestres" + description: "I va obrir més de tres finestres" + _driveFolderCircularReference: + title: "Consulteu la secció de bucle" + description: "Intenta crear carpetes recursives al Disc" + _reactWithoutRead: + title: "De veritat has llegit això?" + description: "Reaccions a una nota de més de 100 caràcters publicada fa menys de 3 segons " + _clickedClickHere: + title: "Fer clic" + description: "Has fet clic aquí " + _justPlainLucky: + title: "Ha sigut sort" + description: "Oportunitat de guanyar-lo amb una probabilitat d'un 0.005% cada 10 segons" + _setNameToSyuilo: + title: "soc millor" + description: "Posat \"siuylo\" com a nom" + _passedSinceAccountCreated1: + title: "Primer aniversari" + description: "Ja ha passat un any d'ençà que vas crear el teu compte" + _passedSinceAccountCreated2: + title: "Segon aniversari" + description: "Ja han passat dos anys d'ençà que vas crear el teu compte" + _passedSinceAccountCreated3: + title: "Tres anys" + description: "Ja han passat tres anys d'ençà que vas crear el teu compte" + _loggedInOnBirthday: + title: "Felicitats!" + description: "T'has identificat el dia del teu aniversari" + _loggedInOnNewYearsDay: + title: "Bon any nou!" + description: "T'has identificat el primer dia de l'any " + flavor: "A per un altre any memorable a la teva instància " + _cookieClicked: + title: "Un joc en què fas clic a les galetes" + description: "Pica galetes" + flavor: "Espera, ets al lloc web correcte?" + _brainDiver: + title: "Busseja Ments" + description: "Publica un enllaç al Busseja Ments" + flavor: "Misskey-Misskey La-Tu-Ma" + _smashTestNotificationButton: + title: "Sobrecàrrega de proves" + description: "Envia moltes notificacions de prova en un període de temps molt curt" + _tutorialCompleted: + title: "Diploma del Curs Elemental de Misskey" + description: "Has completat el tutorial" + _bubbleGameExplodingHead: + title: "🤯" + description: "L'objecte més gran del joc de la bombolla " + _bubbleGameDoubleExplodingHead: + title: "Doble 🤯" + description: "Dos dels objectes més grans del joc de la bombolla al mateix temps" + flavor: "Pots emplenar una carmanyola com aquesta 🤯🤯 una mica" _role: + new: "Nou rol" + edit: "Editar el rol" + name: "Nom del rol" + description: "Descripció del rol" + permission: "Permisos de rol" + descriptionOfPermission: "Els Moderadors poden fer operacions bàsiques de moderació.\nEls Administradors poden canviar tots els ajustos del servidor." assignTarget: "Assignar " + descriptionOfAssignTarget: "Manual per canviar manualment qui és part d'aquest rol i qui no.\nCondicional per afegir o eliminar de manera automàtica els usuaris d'aquest rol basat en una determinada condició." + manual: "Manual" + manualRoles: "Rols manuals" + conditional: "Condicional" + conditionalRoles: "Rols condicionals" + condition: "Condició" + isConditionalRole: "Aquest és un rol condicional" + isPublic: "Rol públic" + descriptionOfIsPublic: "Aquest rol es mostrarà al perfil dels usuaris al que se'ls assigni." + options: "Opcions" + policies: "Polítiques" + baseRole: "Plantilla de rols" + useBaseValue: "Fer servir els valors de la plantilla de rols" + chooseRoleToAssign: "Selecciona els rols a assignar" + iconUrl: "URL de la icona " + asBadge: "Mostrar com a insígnia " + descriptionOfAsBadge: "La icona d'aquest rol es mostrarà al costat dels noms d'usuaris que tinguin assignats aquest rol." + isExplorable: "Fer el rol explorable" + descriptionOfIsExplorable: "La línia de temps d'aquest rol i la llista d'usuaris seran públics si s'activa." + displayOrder: "Posició " + descriptionOfDisplayOrder: "Com més gran és el número, més dalt la seva posició a la interfície." + canEditMembersByModerator: "Permetre que els moderadors editin la llista d'usuaris en aquest rol" + descriptionOfCanEditMembersByModerator: "Quan s'activa, els moderadors, així com els administradors, podran afegir i treure usuaris d'aquest rol. Si es troba desactivat, només els administradors poden assignar usuaris." priority: "Prioritat" _priority: low: "Baixa" middle: "Mitjà" high: "Alta" _options: + gtlAvailable: "Pot veure la línia de temps global" + ltlAvailable: "Pot veure la línia de temps local" + canPublicNote: "Pot enviar notes públiques" + canInvite: "Pot crear invitacions a la instància " + inviteLimit: "Límit d'invitacions " + inviteLimitCycle: "Temps de refresc de les invitacions" + inviteExpirationTime: "Interval de caducitat de les invitacions" canManageCustomEmojis: "Gestiona els emojis personalitzats" canManageAvatarDecorations: "Gestiona les decoracions dels avatars " + driveCapacity: "Capacitat del disc" + alwaysMarkNsfw: "Marca sempre els fitxers com a sensibles" + pinMax: "Nombre màxim de notes fixades" antennaMax: "Nombre màxim d'antenes" + wordMuteMax: "Nombre màxim de caràcters permesos a les paraules silenciades" + webhookMax: "Nombre màxim de Webhooks" + clipMax: "Nombre màxim de clips" + noteEachClipsMax: "Nombre màxim de notes dintre d'un clip" + userListMax: "Nombre màxim de llistes d'usuaris " + userEachUserListsMax: "Nombre màxim d'usuaris dintre d'una llista d'usuaris " + rateLimitFactor: "Limitador" + descriptionOfRateLimitFactor: "Límits baixos són menys restrictius, límits alts són més restrictius." + canHideAds: "Pot amagar els anuncis" + canSearchNotes: "Pot cercar notes" + canUseTranslator: "Pot fer servir el traductor" + avatarDecorationLimit: "Nombre màxim de decoracions que es poden aplicar els avatars" + _condition: + isLocal: "Usuari local" + isRemote: "Usuari remot" + createdLessThan: "Han passat menys de X a passat des de la creació del compte" + createdMoreThan: "Han passat més de X des de la creació del compte" + followersLessThanOrEq: "Té menys de X seguidors" + followersMoreThanOrEq: "Té X o més seguidors" + followingLessThanOrEq: "Segueix X o menys comptes" + followingMoreThanOrEq: "Segueix a X o més comptes" + notesLessThanOrEq: "Les publicacions són menys o igual a " + notesMoreThanOrEq: "Les publicacions són més o igual a " + and: "AND condicional " + or: "OR condicional" + not: "NOT condicional" +_sensitiveMediaDetection: + description: "Redueix els esforços de moderació gràcies al reconeixement automàtic dels fitxers amb contingut sensible mitjançant Machine Learing. Això augmentarà la càrrega del servidor." + sensitivity: "Sensibilitat de la detecció " + sensitivityDescription: "Reduint la sensibilitat provocarà menys falsos positius. D'altra banda incrementant-ho generarà més falsos negatius." + setSensitiveFlagAutomatically: "Marcar com a sensible" + setSensitiveFlagAutomaticallyDescription: "Els resultats de la detecció interna seran desats, inclòs si aquesta opció es troba desactivada." + analyzeVideos: "Activar anàlisis de vídeos " + analyzeVideosDescription: "Analitzar els vídeos a més de les imatges. Això incrementarà lleugerament la càrrega del servidor." +_emailUnavailable: + used: "Aquest correu electrònic ja s'està fent servir" + format: "El format del correu electrònic és invàlid " + disposable: "No es poden fer servir adreces de correu electrònic d'un sol ús " + mx: "Aquest servidor de correu electrònic no és vàlid " + smtp: "Aquest servidor de correu electrònic no respon" + banned: "No pots registrar-te amb aquesta adreça de correu electrònic " _ffVisibility: public: "Publicar" + followers: "Visible només per a seguidors " + private: "Privat" +_signup: + almostThere: "Ja quasi estem" + emailAddressInfo: "Si us plau, escriu la teva adreça de correu electrònic. No es farà pública." + emailSent: "S'ha enviat un correu de confirmació a ({email}). Si us plau, fes clic a l'enllaç per completar el registre." +_accountDelete: + accountDelete: "Eliminar el compte" + mayTakeTime: "Com l'eliminació d'un compte consumeix bastants recursos, pot trigar un temps perquè es completi l'esborrat, depenent si tens molt contingut i la quantitat de fitxer que hagis pujat." + sendEmail: "Una vegada hagi finalitzat l'esborrat del compte rebràs un correu electrònic a l'adreça que tinguis registrada en aquest compte." + requestAccountDelete: "Demanar l'eliminació del compte" + started: "Ha començat l'esborrat del compte." + inProgress: "L'esborrat es troba en procés " _ad: back: "Tornar" + reduceFrequencyOfThisAd: "Mostrar menys aquest anunci" + hide: "No mostrar mai" + timezoneinfo: "El dia de la setmana ve determinat del fus horari del servidor." + adsSettings: "Configuració d'anuncis " + notesPerOneAd: "Interval d'emplaçament d'anuncis en temps real (Notes per anuncis)" + setZeroToDisable: "Ajusta aquest valor a 0 per deshabilitar l'actualització d'anuncis en temps real" + adsTooClose: "L'interval actual pot fer que l'experiència de l'usuari sigui dolenta perquè l'interval és molt baix." +_forgotPassword: + enterEmail: "Escriu l'adreça de correu electrònic amb la que et vas registrar. S'enviarà un correu electrònic amb un enllaç perquè puguis canviar-la." + ifNoEmail: "Si no vas fer servir una adreça de correu electrònic per registrar-te, si us plau posa't en contacte amb l'administrador." + contactAdmin: "Aquesta instància no suporta registrar-se amb correu electrònic. Si us plau, contacta amb l'administrador del servidor." +_gallery: + my: "La meva Galeria " + liked: "Publicacions que t'han agradat" + like: "M'agrada " + unlike: "Ja no m'agrada" _email: _follow: title: "t'ha seguit" + _receiveFollowRequest: + title: "Has rebut una sol·licitud de seguiment" +_plugin: + install: "Instal·lar un afegit " + installWarn: "Si us plau, no instal·lis afegits que no siguin de confiança." + manage: "Gestionar els afegits" + viewSource: "Veure l'origen " +_preferencesBackups: + list: "Llista de còpies de seguretat" + saveNew: "Fer una còpia de seguretat nova" + loadFile: "Carregar des d'un fitxer" + apply: "Aplicar en aquest dispositiu" + save: "Desar els canvis" + inputName: "Escriu un nom per aquesta còpia de seguretat" + cannotSave: "No s'ha pogut desar" + nameAlreadyExists: "Ja existeix una còpia de seguretat anomenada \"{name}\". Escriu un nom diferent." + applyConfirm: "Vols aplicar la còpia de seguretat \"{name}\" a aquest dispositiu? La configuració actual del dispositiu serà esborrada." + saveConfirm: "Desar còpia de seguretat com {name}?" + deleteConfirm: "Esborrar la còpia de seguretat {name}?" + renameConfirm: "Vols canvia el nom de la còpia de seguretat de \"{old}\" a \"{new}\"?" + noBackups: "No hi ha còpies de seguretat. Pots fer una còpia de seguretat de la configuració d'aquest dispositiu al servidor fent servir \"Crear nova còpia de seguretat\"" + createdAt: "Creat el: {date} {time}" + updatedAt: "Actualitzat el: {date} {time}" + cannotLoad: "Hi ha hagut un error al carregar" + invalidFile: "Format del fitxer no vàlid " +_registry: + scope: "Àmbit " + key: "Clau" + keys: "Claus" + domain: "Domini" + createKey: "Crear una clau" +_aboutMisskey: + about: "Misskey és un programa de codi obert desenvolupar per syuilo des de 2014" + contributors: "Col·laboradors principals" + allContributors: "Tots els col·laboradors " + source: "Codi font" + translation: "Tradueix Misskey" + donate: "Fes un donatiu a Misskey" + morePatrons: "També agraïm el suport d'altres col·laboradors que no surten en aquesta llista. Gràcies! 🥰" + patrons: "Patrocinadors" + projectMembers: "Membres del projecte" +_displayOfSensitiveMedia: + respect: "Ocultar imatges o vídeos marcats com a sensibles" + ignore: "Mostrar imatges o vídeos marcats com a sensibles" + force: "Ocultar totes les imatges o vídeos " +_instanceTicker: + none: "No mostrar mai" + remote: "Mostrar per usuaris remots" + always: "Mostrar sempre" +_serverDisconnectedBehavior: + reload: "Recarregar automàticament " + dialog: "Mostrar finestres de confirmació " + quiet: "Mostrar un avís que no molesti" +_channel: + create: "Crear un canal" + edit: "Editar canal" + setBanner: "Estableix el bàner " + removeBanner: "Eliminar el.bàner" + featured: "Popular" + owned: "Propietat" + following: "Seguin" + usersCount: "{n} Participants" + notesCount: "{n} Notes" + nameAndDescription: "Nom i descripció " + nameOnly: "Nom només " + allowRenoteToExternal: "Permet la citació i l'impuls fora del canal" +_menuDisplay: + sideFull: "Horitzontal " + sideIcon: "Horitzontal (icones)" + top: "A dalt" + hide: "Amagar" +_wordMute: + muteWords: "Paraules silenciades" + muteWordsDescription: "Separar amb espais per la condició AND o amb salts de línia per la condició OR." + muteWordsDescription2: "Envolta les paraules amb barres per fer servir expressions regulars." _instanceMute: instanceMuteDescription: "Silencia tots els impulsos dels servidors seleccionats, també els usuaris que responen a altres d'un servidor silenciat." + instanceMuteDescription2: "Separar amb salts de línia" + title: "Ocultar notes de les instàncies en la llista." + heading: "Llista d'instàncies a silenciar" _theme: + explore: "Explorar els temes " + install: "Instal·lar un tema" + manage: "Gestionar els temes " + code: "Codi del tema" description: "Descripció" + installed: "{name} Instal·lat " + installedThemes: "Temes instal·lats " + builtinThemes: "Temes integrats" + alreadyInstalled: "Aquest tema ja es troba instal·lat " + invalid: "El format d'aquest tema no és correcte" + make: "Crear un tema" + base: "Base" + addConstant: "Afegir constant " + constant: "Constant" + defaultValue: "Valor per defecte" + color: "Color" + refProp: "Referència a una propietat" + refConst: "Referència a una constant " + key: "Clau" + func: "Funcions" + funcKind: "Tipus de funció " + argument: "Argument" + basedProp: "Propietat referenciada" + alpha: "Opacitat" + darken: "Enfosquir " + lighten: "Brillantor" + inputConstantName: "Escriu un nom per aquesta constant" + importInfo: "Si escrius el codi del tema aquí, el podràs importar a l'editor del tema" + deleteConstantConfirm: "Vols esborrar la constant {const}?" keys: + accent: "Accent" + bg: "Fons" + fg: "Text" + focus: "Enfocament" + indicator: "Indicador" + panel: "Taulell " + shadow: "Ombra" + header: "Capçalera" + navBg: "Fons de la barra lateral" + navFg: "Text de la barra lateral" + navHoverFg: "Text barra lateral (en passar per sobre)" + navActive: "Text barra lateral (actiu)" + navIndicator: "Indicador barra lateral" + link: "Enllaç" + hashtag: "Etiqueta" mention: "Menció" + mentionMe: "Mencions (jo)" renote: "Renotar" + modalBg: "Fons del modal" divider: "Divisor" + scrollbarHandle: "Maneta de la barra de desplaçament" + scrollbarHandleHover: "Maneta de la barra de desplaçament (en passar-hi per sobre)" + dateLabelFg: "Text de l'etiqueta de la data" + infoBg: "Fons d'informació " + infoFg: "Text d'informació " + infoWarnBg: "Fons avís " + infoWarnFg: "Text avís " + toastBg: "Fons notificació " + toastFg: "Text notificació " + buttonBg: "Fons botó " + buttonHoverBg: "Fons botó (en passar-hi per sobre)" + inputBorder: "Contorn del cap d'introducció " + listItemHoverBg: "Fons dels elements d'una llista" + driveFolderBg: "Fons de la carpeta Disc" + wallpaperOverlay: "Superposició del fons de pantalla " + badge: "Insígnia " + messageBg: "Fons del xat" + accentDarken: "Accent (fosc)" + accentLighten: "Accent (clar)" + fgHighlighted: "Text ressaltat" _sfx: note: "Notes" + noteMy: "Nota (per mi)" notification: "Notificacions" antenna: "Antenes" + channel: "Notificacions dels canals" + reaction: "Quan se selecciona una reacció " +_soundSettings: + driveFile: "Fer servir un fitxer d'àudio del disc" + driveFileWarn: "Seleccionar un fitxer d'àudio del disc" + driveFileTypeWarn: "Fitxer no suportat " + driveFileTypeWarnDescription: "Seleccionar un fitxer d'àudio " + driveFileDurationWarn: "L'àudio és massa llarg" + driveFileDurationWarnDescription: "Els àudios molt llargs pot interrompre l'ús de Misskey. Vols continuar?" +_ago: + future: "Futur " + justNow: "Ara mateix" + secondsAgo: "Fa {n} segons" + minutesAgo: "Fa {n} minuts" + hoursAgo: "Fa {n} hores" + daysAgo: "Fa {n} dies" + weeksAgo: "Fa {n} setmanes" + monthsAgo: "Fa {n} mesos" + yearsAgo: "Fa {n} anys" + invalid: "Res" +_timeIn: + seconds: "En {n} segons" + minutes: "En {n} minuts" + hours: "En {n} hores" + days: "En {n} dies" + weeks: "En {n} setmanes" + months: "En {n} mesos" + years: "En {n} anys" +_time: + second: "Segon(s)" + minute: "Minut(s)" + hour: "Hor(a)(es)" + day: "Di(a)(es)" _2fa: + alreadyRegistered: "J has registrat un dispositiu d'autenticació de doble factor." + registerTOTP: "Registrar una aplicació autenticadora" + step1: "Primer instal·la una aplicació autenticadora (com {a} o {b}) al teu dispositiu." + step2: "Després escaneja el codi QR que es mostra en aquesta pantalla." + step2Click: "Fent clic en aquest codi QR et permetrà registrar l'autenticació de doble factor a la teva clau de seguretat o en l'aplicació d'autenticació del teu dispositiu." + step2Uri: "Escriu la següent URI si estàs fent servir una aplicació d'escriptori " + step3Title: "Escriu un codi d'autenticació" + step3: "Escriu el codi d'autenticació (token) que es mostra a la teva aplicació per finalitzar la configuració." + setupCompleted: "Configuració terminada" + step4: "D'ara endavant quan accedeixis se't demanarà el token que has introduït." + securityKeyNotSupported: "El teu navegador no suporta claus de seguretat" + registerTOTPBeforeKey: "Configura una aplicació d'autenticació per registrar una clau de seguretat o una clau de pas." + securityKeyInfo: "A més de l'empremta digital o PIN per autenticar-te, pots configurar autenticació mitjançant maquinari que suporti claus de seguretat FIDO2, per protegir encara més el teu compte." + registerSecurityKey: "Registrar una clau de seguretat o clau de pas" + securityKeyName: "Escriu un nom per la clau" + tapSecurityKey: "Seguiu les instruccions del navegador i registrar les claus de seguretat o la clau de pas" + removeKey: "Esborrar la clau de seguretat" + removeKeyConfirm: "Esborrar la còpia de seguretat {name}?" + whyTOTPOnlyRenew: "L'aplicació d'autenticació no es pot eliminar mentre hi hagi una clau de seguretat registrada." + renewTOTP: "Reconfigurar l'aplicació d'autenticació " + renewTOTPConfirm: "Això farà que els codis de validació de l'antiga aplicació deixin de funcionar" + renewTOTPOk: "Reconfigurar" renewTOTPCancel: "No, gràcies" + checkBackupCodesBeforeCloseThisWizard: "Abans de tancar aquesta finestra, comprova el següent codi de seguretat." + backupCodes: "Codi de seguretat." + backupCodesDescription: "Si l'aplicació d'autenticació no es pot utilitzar, es pot accedir al compte utilitzant els següents codis de còpia de seguretat. Assegura't de mantenir aquests codis en un lloc segur. Cada codi es pot utilitzar només una vegada." + backupCodeUsedWarning: "Es va utilitzar un codi de còpia de seguretat. Si l'aplicació de certificació està disponible, reconfigura l'aplicació d'autenticació tan aviat com sigui possible." + backupCodesExhaustedWarning: "Es van utilitzar tots els codis de còpia de seguretat. Si no es pot utilitzar l'aplicació d'autenticació, ja no es pot accedir al compte. Torna a registrar l'aplicació d'autenticació." +_permissions: + "read:account": "Veure la informació del compte." + "write:account": "Editar la informació del compte." + "read:blocks": "Veure la llista d'usuaris bloquejats" + "write:blocks": "Editar la llista d'usuaris blocats" + "read:drive": "Accedeix als teus fitxers i carpetes del Disc" + "write:drive": "Editar o eliminar els teus fitxers i carpetes al Disc" + "read:favorites": "Veure la teva llista de favorits" + "write:favorites": "Editar la teva llista de favorits" + "read:following": "Veure informació de qui segueixes" + "write:following": "Segueix o deixa de seguir altres comptes" + "read:messaging": "Veure els teus xats" + "write:messaging": "Crear o esborrar missatges de xat" + "read:mutes": "Veure la teva llista d'usuaris silenciats" + "write:mutes": "Editar la teva llista d'usuaris silenciats" + "write:notes": "Crear o esborrar notes" + "read:notifications": "Veure les teves notificacions" + "write:notifications": "Gestionar les teves notificacions" + "read:reactions": "Veure les teves reaccions" + "write:reactions": "Editar les teves reaccions" + "write:votes": "Votar en una enquesta" + "read:pages": "Veure les teves pàgines " + "write:pages": "Editar o esborrar les teves pàgines " + "read:page-likes": "Veure la llista de les pàgines que t'han agradat" + "write:page-likes": "Editar la llista de les pàgines que t'han agradat" + "read:user-groups": "Veure els teus grups d'usuaris " + "write:user-groups": "Editar o esborrar els teus grups d'usuaris " + "read:channels": "Veure els teus canals" + "write:channels": "Editar els teus canals" + "read:gallery": "Veure la teva galeria " + "write:gallery": "Editar la teva galeria" + "read:gallery-likes": "Veure la llista de publicacions de galeries que t'han agradat" + "write:gallery-likes": "Editar la llista de publicacions de galeries que t'han agradat" + "read:flash": "Veure reproduccions" + "write:flash": "Editar reproduccions" + "read:flash-likes": "Veure la llista de reproduccions que t'han agradat" + "write:flash-likes": "Editar la llista de reproduccions que t'han agradat" + "read:admin:abuse-user-reports": "Veure informes d'usuaris " + "write:admin:delete-account": "Esborrar compte d'usuari " + "write:admin:delete-all-files-of-a-user": "Esborrar tots els fitxers d'un usuari" + "read:admin:index-stats": "Veure l'índex de la base de dades" + "read:admin:table-stats": "Veure la informació de les taules a la base de dades" + "read:admin:user-ips": "Veure adreça IP de l'usuari " + "read:admin:meta": "Veure meta-informació del servidor" + "write:admin:reset-password": "Reiniciar contrasenya d'usuari " + "write:admin:resolve-abuse-user-report": "Resoldre informes d'usuaris " + "write:admin:send-email": "Enviar correu electrònic " + "read:admin:server-info": "Veure informació del servidor" + "read:admin:show-moderation-log": "Veure registre de moderació " + "read:admin:show-user": "Veure informació privada de l'usuari " + "read:admin:show-users": "Veure informació privada de l'usuari " + "write:admin:suspend-user": "Suspendre usuari" + "write:admin:unset-user-avatar": "Esborrar avatar d'usuari " + "write:admin:unset-user-banner": "Esborrar bàner de l'usuari " + "write:admin:unsuspend-user": "Treure la suspensió d'un usuari" + "write:admin:meta": "Gestionar les metadades de la instància" + "write:admin:user-note": "Gestionar les notes de moderació " + "write:admin:roles": "Gestionar rols" + "read:admin:roles": "Veure rols" + "write:admin:relays": "Gestionar relé" + "read:admin:relays": "Veure relés" + "write:admin:invite-codes": "Gestionar codis d'invitació " + "read:admin:invite-codes": "Veure codis d'invitació " + "write:admin:announcements": "Gestionar anuncis" + "read:admin:announcements": "Veure anuncis" + "write:admin:avatar-decorations": "Gestionar la decoració dels avatars" + "read:admin:avatar-decorations": "Veure les decoracions dels avatars" + "write:admin:federation": "Gestionar la federació d'instàncies " + "write:admin:account": "Gestionar els comptes d'usuaris " + "read:admin:account": "Veure els comptes d'usuaris " + "write:admin:emoji": "Edició d'emojis" + "read:admin:emoji": "Veure emojis" + "write:admin:queue": "Gestionar la cua de feines" + "read:admin:queue": "Veure la cua de feines" _antennaSources: all: "Totes les publicacions" homeTimeline: "Publicacions dels usuaris seguits" @@ -1197,17 +2025,73 @@ _widgets: timeline: "Línia de temps" activity: "Activitat" federation: "Federació" + button: "Botó " jobQueue: "Cua de tasques" _userList: chooseList: "Tria una llista" _cw: + hide: "Amagar" show: "Carregar més" + chars: "{count} caràcters " + files: "{count} fitxer(s)" +_poll: + noOnlyOneChoice: "Es necessita escollir dues opcions com a mínim " + choiceN: "Opció {n}" + noMore: "No pots afegir més opcions" + canMultipleVote: "Permetre escollir diferents opcions" + expiration: "Finalitza el" + infinite: "Mai" + at: "Finalitza en..." + after: "Finalitza després..." + deadlineDate: "Data de finalització " + deadlineTime: "Hor(a)(es)" + duration: "Duració " + votesCount: "{n} vots" + totalVotes: "{n} vots en total" + vote: "Votar en una enquesta" + showResult: "Veure resultats" + voted: "Has votat" + closed: "Finalitzada" + remainingDays: "Queden {d} dies i {h} hores per finalitzar" + remainingHours: "Queden {h} hores i {m} minuts" + remainingMinutes: "Queden {m} minuts i {s} segons" + remainingSeconds: "Queden {s} segons" _visibility: + public: "Públic " + publicDescription: "La teva nota la podrà veure tothom " home: "Inici" + homeDescription: "Publicar només a la línia de temps d'Inici " followers: "Seguidors" + followersDescription: "Fes només visible per als teus seguidors" + specified: "Directe" + specifiedDescription: "Fer visible només per alguns usuaris" + disableFederation: "Sense federar" + disableFederationDescription: "No enviar a altres servidors" +_postForm: + replyPlaceholder: "Contestar..." + quotePlaceholder: "Citar..." + channelPlaceholder: "Publicar a un canal..." + _placeholders: + a: "Que vols dir?..." + b: "Alguna cosa interessant al teu voltant?..." + c: "Què et passa pel cap?..." + d: "Què vols dir?..." + e: "Escriu alguna cosa..." + f: "Esperant que escriguis qualsevol cosa..." _profile: name: "Nom" username: "Nom d'usuari" + description: "Biografia " + youCanIncludeHashtags: "Pots posar etiquetes a la teva biografia " + metadata: "Informació adicional " + metadataEdit: "Editar la informació adicional " + metadataDescription: "Amb això podràs mostrar camps d'informació adicional al teu perfil." + metadataLabel: "Etiqueta " + metadataContent: "Contingut" + changeAvatar: "Canviar l'avatar " + changeBanner: "Canviar el bàner " + verifiedLinkDescription: "Escrivint una adreça URL que enllaci a aquest perfil, una icona de propietat verificada es mostrarà al costat del camp." + avatarDecorationMax: "Pot afegir un màxim de {max} decoracions." _exportOrImport: allNotes: "Totes les publicacions" clips: "Retalls" @@ -1223,19 +2107,74 @@ _timelines: social: "Social" global: "Global" _play: + viewSource: "Veure l'origen " + featured: "Popular" + title: "Títol " script: "Script" summary: "Descripció" _pages: + viewSource: "Veure l'origen " + viewPage: "Veure les teves pàgines " + like: "M'agrada " + unlike: "Treure m'agrada " + my: "Les meves pàgines " + liked: "Pàgines que m'agraden " + featured: "Popular" + inspector: "Inspeccionar" contents: "Contingut" + content: "Bloquejar la pàgina " + variables: "Variables" + title: "Títol " + url: "URL de la pàgina " + summary: "Resum de la pàgina " + alignCenter: "Centrar elements" + hideTitleWhenPinned: "Amagar el títol de la pàgina quan estigui fixada al perfil" + font: "Lletra tipogràfica" + fontSerif: "Serif" + fontSansSerif: "Sans Serif" + eyeCatchingImageSet: "Escull una miniatura" + eyeCatchingImageRemove: "Esborrar la miniatura" + chooseBlock: "Afegeix un bloc" + selectType: "Seleccionar tipus" + contentBlocks: "Contingut" + inputBlocks: "Entrada " + specialBlocks: "Especial" blocks: + text: "Text" + textarea: "Àrea de text" + section: "Secció " image: "Imatges" + button: "Botó " + note: "Incorporar una Nota" _note: id: "ID de la publicació" + idDescription: "Alternativament pots enganxar l'adreça URL de la nota aquí." detailed: "Mostra els detalls" +_relayStatus: + requesting: "Pendent" + accepted: "Acceptat" + rejected: "Rebutjat" _notification: + fileUploaded: "Fitxer pujat sense cap problema" + youGotMention: "{name} t'ha mencionat" + youGotReply: "{name} t'ha contestat" + youGotQuote: "{name} t'ha citat" youRenoted: "Impulsat per {name}" youWereFollowed: "t'ha seguit" + youReceivedFollowRequest: "Has rebut una petició de seguiment" + yourFollowRequestAccepted: "La teva petició de seguiment ha sigut acceptada" + pollEnded: "Ja pots veure els resultats de l'enquesta " + newNote: "Nota nova" unreadAntennaNote: "Antena {name}" + roleAssigned: "Rol assignat " + emptyPushNotificationMessage: "Les notificacions han sigut actualitzades" + achievementEarned: "Aconseguiment desblocat" + testNotification: "Notificació de prova" + checkNotificationBehavior: "Comprova el comportament de la notificació " + sendTestNotification: "Enviar notificació de prova" + notificationWillBeDisplayedLikeThis: "Les notificacions és veure'n així " + reactedBySomeUsers: "Han reaccionat {n} usuaris" + renotedBySomeUsers: "L'han impulsat {n} usuaris" _types: all: "Tots" follow: "Seguint" @@ -1274,6 +2213,46 @@ _webhookSettings: _moderationLogTypes: suspend: "Suspèn" resetPassword: "Restableix la contrasenya" + suspendRemoteInstance: "Servidor remot suspès " + unsuspendRemoteInstance: "S'ha tret la suspensió del servidor remot" + markSensitiveDriveFile: "Fitxer marcat com a sensible" + unmarkSensitiveDriveFile: "S'ha tret la marca de sensible del fitxer" + resolveAbuseReport: "Informe resolt" + createInvitation: "Crear codi d'invitació " + createAd: "Anunci creat" + deleteAd: "Anunci esborrat" + updateAd: "Anunci actualitzat" + createAvatarDecoration: "Decoració de l'avatar creada" + updateAvatarDecoration: "S'ha actualitzat la decoració de l'avatar " + deleteAvatarDecoration: "S'ha esborrat la decoració de l'avatar " + unsetUserAvatar: "Esborrar l'avatar d'aquest usuari" + unsetUserBanner: "Esborrar el bàner d'aquest usuari" +_fileViewer: + title: "Detall del fitxer" + type: "Tipus de fitxer" + size: "Mida" + url: "URL" + uploadedAt: "Pujat el" + attachedNotes: "Notes amb aquest fitxer" + thisPageCanBeSeenFromTheAuthor: "Aquesta pàgina només la pot veure l'usuari que ha pujat aquest fitxer." +_externalResourceInstaller: + title: "Instal·lar des d'un lloc extern" + checkVendorBeforeInstall: "Assegura't que qui distribueix aquest recurs és fiable abans d'instal·lar-ho." + _plugin: + title: "Vols instal·lar aquest afegit?" + metaTitle: "Informació de l'afegit " + _theme: + title: "Vols instal·lar aquest tema?" + metaTitle: "Informació del tema" + _meta: + base: "Paleta de colors base" + _vendorInfo: + title: "Informació del distribuïdor " + endpoint: "Punt final referenciat" + hashVerify: "Verificació d'integritat " + _errors: + _invalidParams: + title: "Paràmetres no vàlids " _reversi: total: "Total" diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index 8620a1207c..cbf5c33c18 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -1005,6 +1005,7 @@ resetPasswordConfirm: "Opravdu chcete resetovat heslo?" sensitiveWords: "Citlivá slova" sensitiveWordsDescription: "Viditelnost všech poznámek obsahujících některé z nakonfigurovaných slov bude automaticky nastavena na \"Domů\". Můžete jich uvést více tak, že je oddělíte pomocí řádků." sensitiveWordsDescription2: "Použití mezer vytvoří výrazy AND a obklopení klíčových slov lomítky je změní na regulární výraz." +prohibitedWordsDescription2: "Použití mezer vytvoří výrazy AND a obklopení klíčových slov lomítky je změní na regulární výraz." notesSearchNotAvailable: "Vyhledávání poznámek je nedostupné." license: "Licence" unfavoriteConfirm: "Opravdu chcete odstranit z oblíbených?" @@ -1094,8 +1095,10 @@ iHaveReadXCarefullyAndAgree: "Přečetl jsem si text \"{x}\" a souhlasím s ním icon: "Avatar" replies: "Odpovědět" renotes: "Přeposlat" +sourceCode: "Zdrojový kód" flip: "Otočit" lastNDays: "Posledních {n} dnů" +surrender: "Zrušit" _initialAccountSetting: accountCreated: "Váš účet byl úspěšně vytvořen!" letsStartAccountSetup: "Pro začátek si nastavte svůj profil." diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 45e20d8541..9a22a7b445 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -122,7 +122,10 @@ add: "Hinzufügen" reaction: "Reaktionen" reactions: "Reaktionen" emojiPicker: "Emoji auswählen" -pinnedEmojisForReactionSettingDescription: "Wähle die Emojis aus, um sie an zu pinnen" +pinnedEmojisForReactionSettingDescription: "Lege Emojis fest, die angepinnt werden sollen, um sie beim Reagieren als Erstes anzuzeigen." +pinnedEmojisSettingDescription: "Lege Emojis fest, die angepinnt werden sollen, um sie in der Emoji-Auswahl als Erstes anzuzeigen" +overwriteFromPinnedEmojisForReaction: "Überschreiben mit den Reaktions-Einstellungen" +overwriteFromPinnedEmojis: "Überschreiben mit den allgemeinen Einstellungen" reactionSettingDescription2: "Ziehe um Anzuordnen, klicke um zu löschen, drücke „+“ um hinzuzufügen" rememberNoteVisibility: "Notizsichtbarkeit merken" attachCancel: "Anhang entfernen" @@ -181,7 +184,7 @@ searchWith: "Suchen: {q}" youHaveNoLists: "Du hast keine Listen" followConfirm: "Möchtest du {name} wirklich folgen?" proxyAccount: "Proxy-Benutzerkonto" -proxyAccountDescription: "Ein Proxy-Benutzerkonto ist ein Benutzerkonto, das sich für Nutzer unter bestimmten Konditionen wie ein Follower aus einer fremden Instanz verhält. Zum Beispiel wird die Aktivität eines Nutzers aus einer fremden Instanz nicht an diese Instanz übermittelt, falls es keinen Benutzer dieser Instanz gibt, der diesem Nutzer aus fremder Instanz folgt. In diesem Fall folgt stattdessen das Proxy-Benutzerkonto." +proxyAccountDescription: "Ein Proxy-Konto ist ein Benutzerkonto, das unter bestimmten Bedingungen als Follower für Benutzer fremder Instanzen fungiert. Wenn zum Beispiel ein Benutzer einen Benutzer einer fremden Instanz zu einer Liste hinzufügt, werden die Aktivitäten des entfernten Benutzers nicht an die Instanz übermittelt, wenn kein lokaler Benutzer diesem Benutzer folgt; stattdessen folgt das Proxy-Konto." host: "Hostname" selectUser: "Benutzer auswählen" recipient: "Empfänger" @@ -263,6 +266,7 @@ removed: "Erfolgreich gelöscht" removeAreYouSure: "Möchtest du „{x}“ wirklich entfernen?" deleteAreYouSure: "Möchtest du „{x}“ wirklich löschen?" resetAreYouSure: "Wirklich zurücksetzen?" +areYouSure: "Bist du sicher?" saved: "Erfolgreich gespeichert" messaging: "Chat" upload: "Hochladen" @@ -357,7 +361,7 @@ enableLocalTimeline: "Lokale Chronik aktivieren" enableGlobalTimeline: "Globale Chronik aktivieren" disablingTimelinesInfo: "Administratoren und Moderatoren haben immer Zugriff auf alle Chroniken, auch wenn diese deaktiviert sind." registration: "Registrieren" -enableRegistration: "Registration neuer Benutzer erlauben" +enableRegistration: "Registrierung neuer Benutzer erlauben" invite: "Einladen" driveCapacityPerLocalAccount: "Drive-Kapazität pro lokalem Benutzerkonto" driveCapacityPerRemoteAccount: "Drive-Kapazität pro Benutzer fremder Instanzen" @@ -375,8 +379,11 @@ hcaptcha: "hCaptcha" enableHcaptcha: "hCaptcha aktivieren" hcaptchaSiteKey: "Site key" hcaptchaSecretKey: "Secret key" +mcaptcha: "mCaptcha" +enableMcaptcha: "mCaptcha aktivieren" mcaptchaSiteKey: "Site key" mcaptchaSecretKey: "Secret key" +mcaptchaInstanceUrl: "mCaptcha Instanz-URL" recaptcha: "reCAPTCHA" enableRecaptcha: "reCAPTCHA aktivieren" recaptchaSiteKey: "Site key" @@ -434,7 +441,7 @@ lastUsed: "Zuletzt benutzt" lastUsedAt: "Zuletzt verwendet: {t}" unregister: "Deaktivieren" passwordLessLogin: "Passwortloses Anmelden" -passwordLessLoginDescription: "Ermöglicht passwortfreies Einloggen, nur via Security-Token oder Passkey" +passwordLessLoginDescription: "Ermöglicht passwortloses Einloggen mit einem Security-Token oder Passkey" resetPassword: "Passwort zurücksetzen" newPasswordIs: "Das neue Passwort ist „{password}“" reduceUiAnimation: "Animationen der Benutzeroberfläche reduzieren" @@ -1029,6 +1036,7 @@ resetPasswordConfirm: "Wirklich Passwort zurücksetzen?" sensitiveWords: "Sensible Wörter" sensitiveWordsDescription: "Die Notizsichtbarkeit aller Notizen, die diese Wörter enthalten, wird automatisch auf \"Startseite\" gesetzt. Durch Zeilenumbrüche können mehrere konfiguriert werden." sensitiveWordsDescription2: "Durch die Verwendung von Leerzeichen können AND-Verknüpfungen angegeben werden und durch das Umgeben von Schrägstrichen können reguläre Ausdrücke verwendet werden." +prohibitedWordsDescription2: "Durch die Verwendung von Leerzeichen können AND-Verknüpfungen angegeben werden und durch das Umgeben von Schrägstrichen können reguläre Ausdrücke verwendet werden." hiddenTags: "Ausgeblendete Hashtags" hiddenTagsDescription: "Die hier eingestellten Tags werden nicht mehr in den Trends angezeigt. Mit der Umschalttaste können mehrere ausgewählt werden." notesSearchNotAvailable: "Die Notizsuche ist nicht verfügbar." @@ -1150,6 +1158,7 @@ hideRepliesToOthersInTimelineAll: "Antworten von allen momentan gefolgten Benutz confirmShowRepliesAll: "Dies ist eine unwiderrufliche Aktion. Wirklich Antworten von allen momentan gefolgten Benutzern in der Chronik anzeigen?" confirmHideRepliesAll: "Dies ist eine unwiderrufliche Aktion. Wirklich Antworten von allen momentan gefolgten Benutzern nicht in der Chronik anzeigen?" externalServices: "Externe Dienste" +sourceCode: "Quellcode" impressum: "Impressum" impressumUrl: "Impressums-URL" impressumDescription: "In manchen Ländern, wie Deutschland und dessen Umgebung, ist die Angabe von Betreiberinformationen (ein Impressum) bei kommerziellem Betrieb zwingend." @@ -1171,7 +1180,11 @@ signupPendingError: "Beim Überprüfen der Mailadresse ist etwas schiefgelaufen. cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden." doReaction: "Reagieren" code: "Code" +decorate: "Dekorieren" +addMfmFunction: "MFM hinzufügen" +sfx: "Soundeffekte" lastNDays: "Letzten {n} Tage" +surrender: "Abbrechen" _announcement: forExistingUsers: "Nur für existierende Nutzer" forExistingUsersDescription: "Ist diese Option aktiviert, wird diese Ankündigung nur Nutzern angezeigt, die zum Zeitpunkt der Ankündigung bereits registriert sind. Ist sie deaktiviert, wird sie auch Nutzern, die sich nach dessen Veröffentlichung registrieren, angezeigt." @@ -1181,6 +1194,7 @@ _announcement: tooManyActiveAnnouncementDescription: "Zu viele aktive Ankündigungen können die Benutzerfreundlichkeit verschlechtern. Es wird empfohlen, veraltete Ankündigungen zu archivieren." readConfirmTitle: "Als gelesen markieren?" readConfirmText: "Dies markiert den Inhalt von \"{title}\" als gelesen." + shouldNotBeUsedToPresentPermanentInfo: "Es wird empfohlen, Ankündigungen für aktuelle und zeitlich begrenzte Neuigkeiten zu nutzen, statt für Informationen, die langfristig relevant sind." dialogAnnouncementUxWarn: "Bei der Verwendung von mehr als zwei Meldungen im Dialog-Format wird um Vorsicht geboten, da dies negative Auswirkungen auf die UX haben kann." silence: "Keine Benachrichtigung" silenceDescription: "Wenn aktiviert, gibt diese Meldung keine Nachricht aus und muss nicht als \"gelesen\" markiert werden." @@ -1210,6 +1224,24 @@ _initialTutorial: description: "Hier kannst du sehen, wie Misskey funktioniert" _note: title: "Was sind Notizen?" + description: "Beiträge auf Misskey heißen \"Notizen\". Notizen werden chronologisch in der Chronik angeordnet und in Echtzeit aktualisiert." + reply: "Klicke auf diesen Button, um auf eine Nachricht zu antworten. Es ist auch möglich, auf Antworten zu antworten und die Unterhaltung wie einen Thread fortzusetzen." + _reaction: + title: "Was sind Reaktionen?" + reactToContinue: "Füge eine Reaktion hinzu, um fortzufahren." + reactNotification: "Du erhältst Echtzeit-Benachrichtigungen, wenn jemand auf deine Notiz reagiert." + _postNote: + _visibility: + description: "Du kannst einschränken, wer deine Notiz sehen kann." + public: "Deine Notiz wird für alle Nutzer sichtbar sein." + doNotSendConfidencialOnDirect1: "Sei vorsichtig, wenn du sensible Informationen verschickst!" + _cw: + title: "Inhaltswarnung" + _done: + title: "Du hast das Tutorial abgeschlossen! 🎉" +_timelineDescription: + local: "In der lokalen Chronik siehst du Notizen von allen Benutzern auf diesem Server." + global: "In der globalen Chronik siehst du Notizen von allen föderierten Servern." _serverRules: description: "Eine Reihe von Regeln, die vor der Registrierung angezeigt werden. Eine Zusammenfassung der Nutzungsbedingungen anzuzeigen ist empfohlen." _serverSettings: @@ -1222,6 +1254,8 @@ _serverSettings: shortName: "Abkürzung" shortNameDescription: "Ein Kürzel für den Namen der Instanz, der angezeigt werden kann, falls der volle Instanzname lang ist." fanoutTimelineDescription: "Ist diese Option aktiviert, kann eine erhebliche Verbesserung im Abrufen von Chroniken und eine Reduzierung der Datenbankbelastung erzielt werden, im Gegenzug zu einer Steigerung in der Speichernutzung von Redis. Bei geringem Serverspeicher oder Serverinstabilität kann diese Option deaktiviert werden." + fanoutTimelineDbFallback: "Auf die Datenbank zurückfallen" + fanoutTimelineDbFallbackDescription: "Ist diese Option aktiviert, wird die Chronik auf zusätzliche Abfragen in der Datenbank zurückgreifen, wenn sich die Chronik nicht im Cache befindet. Eine Deaktivierung führt zu geringerer Serverlast, aber schränkt den Zeitraum der abrufbaren Chronik ein. " _accountMigration: moveFrom: "Von einem anderen Konto zu diesem migrieren" moveFromSub: "Alias für ein anderes Konto erstellen" @@ -1479,6 +1513,8 @@ _achievements: _smashTestNotificationButton: title: "Testüberfluss" description: "Betätige den Benachrichtigungstest mehrfach innerhalb einer extrem kurzen Zeitspanne" + _tutorialCompleted: + description: "Tutorial abgeschlossen" _role: new: "Rolle erstellen" edit: "Rolle bearbeiten" @@ -1489,7 +1525,9 @@ _role: assignTarget: "Zuweisungsart" descriptionOfAssignTarget: "Manuell bedeutet, dass die Liste der Benutzer einer Rolle manuell verwaltet wird.\nKonditional bedeutet, dass die Liste der Benutzer einer Rolle durch eine Bedingung automatisch verwaltet wird." manual: "Manuell" + manualRoles: "Manuelle Rollen" conditional: "Konditional" + conditionalRoles: "Bedingte Rolle" condition: "Bedingung" isConditionalRole: "Dies ist eine konditionale Rolle." isPublic: "Öffentliche Rolle" @@ -1531,13 +1569,14 @@ _role: webhookMax: "Maximale Anzahl an Webhooks" clipMax: "Maximale Anzahl an Clips" noteEachClipsMax: "Maximale Anzahl an Notizen innerhalb eines Clips" - userListMax: "Maximale Anzahl an Benutzern in einer Benutzerliste" - userEachUserListsMax: "Maximale Anzahl an Benutzerlisten" + userListMax: "Maximale Anzahl an Benutzerlisten" + userEachUserListsMax: "Maximale Anzahl an Benutzern in einer Benutzerliste" rateLimitFactor: "Versuchsanzahl" descriptionOfRateLimitFactor: "Je niedriger desto weniger restriktiv, je höher destro restriktiver." canHideAds: "Kann Werbung ausblenden" canSearchNotes: "Nutzung der Notizsuchfunktion" canUseTranslator: "Verwendung des Übersetzers" + avatarDecorationLimit: "Maximale Anzahl an Profilbilddekorationen, die angebracht werden können" _condition: isLocal: "Lokaler Benutzer" isRemote: "Benutzer fremder Instanz" @@ -1566,6 +1605,7 @@ _emailUnavailable: disposable: "Wegwerf-Email-Adressen können nicht verwendet werden" mx: "Dieser Email-Server ist ungültig" smtp: "Dieser Email-Server antwortet nicht" + banned: "Du kannst dich mit dieser E-Mail-Adresse nicht registrieren" _ffVisibility: public: "Öffentlich" followers: "Nur für Follower sichtbar" @@ -1894,6 +1934,7 @@ _widgets: _userList: chooseList: "Liste auswählen" clicker: "Klickzähler" + birthdayFollowings: "Nutzer, die heute Geburtstag haben" _cw: hide: "Inhalt verbergen" show: "Inhalt anzeigen" @@ -2243,5 +2284,9 @@ _externalResourceInstaller: title: "Das Farbschema konnte nicht installiert werden" description: "Während der Installation des Farbschemas ist ein Problem aufgetreten. Bitte versuche es erneut. Detaillierte Fehlerinformationen können über die Javascript-Konsole abgerufen werden." _reversi: + blackOrWhite: "Schwarz/Weiß" + rules: "Regeln" + black: "Schwarz" + white: "Weiß" total: "Gesamt" diff --git a/locales/en-US.yml b/locales/en-US.yml index fb4cb0a346..d00f23632c 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -122,7 +122,11 @@ add: "Add" reaction: "Reactions" reactions: "Reactions" emojiPicker: "Emoji picker" +pinnedEmojisForReactionSettingDescription: "Set the emojis which should be pinned and displayed immediately when reacting." +pinnedEmojisSettingDescription: "Set the emojis to be pinned and displayed when viewing emoji picker" emojiPickerDisplay: "Emoji picker display" +overwriteFromPinnedEmojisForReaction: "Override from reaction settings" +overwriteFromPinnedEmojis: "Override from general settings" reactionSettingDescription2: "Drag to reorder, click to delete, press \"+\" to add." rememberNoteVisibility: "Remember note visibility settings" attachCancel: "Remove attachment" @@ -376,8 +380,11 @@ hcaptcha: "hCaptcha" enableHcaptcha: "Enable hCaptcha" hcaptchaSiteKey: "Site key" hcaptchaSecretKey: "Secret key" +mcaptcha: "mCaptcha" +enableMcaptcha: "Enable mCaptcha" mcaptchaSiteKey: "Site key" mcaptchaSecretKey: "Secret key" +mcaptchaInstanceUrl: "mCaptcha instance URL" recaptcha: "reCAPTCHA" enableRecaptcha: "Enable reCAPTCHA" recaptchaSiteKey: "Site key" @@ -625,6 +632,7 @@ medium: "Medium" small: "Small" generateAccessToken: "Generate access token" permission: "Permissions" +adminPermission: "Admin Permissions" enableAll: "Enable all" disableAll: "Disable all" tokenRequested: "Grant access to account" @@ -641,7 +649,7 @@ smtpHost: "Host" smtpPort: "Port" smtpUser: "Username" smtpPass: "Password" -emptyToDisableSmtpAuth: "Leave username and password empty to disable SMTP verification" +emptyToDisableSmtpAuth: "Leave username and password empty to disable SMTP authentication" smtpSecure: "Use implicit SSL/TLS for SMTP connections" smtpSecureInfo: "Turn this off when using STARTTLS" testEmail: "Test email delivery" @@ -668,6 +676,7 @@ useGlobalSettingDesc: "If turned on, your account's notification settings will b other: "Other" regenerateLoginToken: "Regenerate login token" regenerateLoginTokenDescription: "Regenerates the token used internally during login. Normally this action is not necessary. If regenerated, all devices will be logged out." +theKeywordWhenSearchingForCustomEmoji: "This is the keyword when searching for custom emojis." setMultipleBySeparatingWithSpace: "Separate multiple entries with spaces." fileIdOrUrl: "File ID or URL" behavior: "Behavior" @@ -982,6 +991,7 @@ neverShow: "Don't show again" remindMeLater: "Maybe later" didYouLikeMisskey: "Have you taken a liking to Misskey?" pleaseDonate: "{host} uses the free software, Misskey. We would highly appreciate your donations so development of Misskey can continue!" +correspondingSourceIsAvailable: "The corresponding source code is available at {anchor}" roles: "Roles" role: "Role" noRole: "Role not found" @@ -1032,6 +1042,9 @@ resetPasswordConfirm: "Really reset your password?" sensitiveWords: "Sensitive words" sensitiveWordsDescription: "The visibility of all notes containing any of the configured words will be set to \"Home\" automatically. You can list multiple by separating them via line breaks." sensitiveWordsDescription2: "Using spaces will create AND expressions and surrounding keywords with slashes will turn them into a regular expression." +prohibitedWords: "Prohibited words" +prohibitedWordsDescription: "Enables an error when attempting to post a note containing the set word(s). Multiple words can be set, separated by a new line." +prohibitedWordsDescription2: "Using spaces will create AND expressions and surrounding keywords with slashes will turn them into a regular expression." hiddenTags: "Hidden hashtags" hiddenTagsDescription: "Select tags which will not shown on trend list.\nMultiple tags could be registered by lines." notesSearchNotAvailable: "Note search is unavailable." @@ -1050,6 +1063,8 @@ limitWidthOfReaction: "Limits the maximum width of reactions and display them in noteIdOrUrl: "Note ID or URL" video: "Video" videos: "Videos" +audio: "Audio" +audioFiles: "Audio" dataSaver: "Data Saver" accountMigration: "Account Migration" accountMoved: "This user has moved to a new account:" @@ -1145,6 +1160,7 @@ showRenotes: "Show renotes" edited: "Edited" notificationRecieveConfig: "Notification Settings" mutualFollow: "Mutual follow" +followingOrFollower: "Following or follower" fileAttachedOnly: "Only notes with files" showRepliesToOthersInTimeline: "Show replies to others in timeline" hideRepliesToOthersInTimeline: "Hide replies to others from timeline" @@ -1153,6 +1169,13 @@ hideRepliesToOthersInTimelineAll: "Hide replies to others from everyone you foll confirmShowRepliesAll: "This operation is irreversible. Would you really like to show replies to others from everyone you follow in your timeline?" confirmHideRepliesAll: "This operation is irreversible. Would you really like to hide replies to others from everyone you follow in your timeline?" externalServices: "External Services" +sourceCode: "Source code" +sourceCodeIsNotYetProvided: "Source code is not yet available. Contact the administrator to fix this problem." +repositoryUrl: "Repository URL" +repositoryUrlDescription: "If you are using Misskey as is (without any changes to the source code), enter https://github.com/misskey-dev/misskey" +repositoryUrlOrTarballRequired: "If you have not published a repository, you must provide a tarball instead. See .config/example.yml for more information." +feedback: "Feedback" +feedbackUrl: "Feedback URL" impressum: "Impressum" impressumUrl: "Impressum URL" impressumDescription: "In some countries, like germany, the inclusion of operator contact information (an Impressum) is legally required for commercial websites." @@ -1162,6 +1185,7 @@ tosAndPrivacyPolicy: "Terms of Service and Privacy Policy" avatarDecorations: "Avatar decorations" attach: "Attach" detach: "Remove" +detachAll: "Remove All" angle: "Angle" flip: "Flip" showAvatarDecorations: "Show avatar decorations" @@ -1175,11 +1199,45 @@ cwNotationRequired: "If \"Hide content\" is enabled, a description must be provi doReaction: "Add reaction" code: "Code" reloadRequiredToApplySettings: "Reloading is required to apply the settings." +remainingN: "Remaining: {n}" +overwriteContentConfirm: "Are you sure you want to overwrite the current content?" +seasonalScreenEffect: "Seasonal Screen Effect" decorate: "Decorate" +addMfmFunction: "Add MFM" +enableQuickAddMfmFunction: "Show advanced MFM picker" bubbleGame: "Bubble Game" sfx: "Sound Effects" +soundWillBePlayed: "Sound will be played" +showReplay: "View Replay" replay: "Replay" +replaying: "Showing replay" +endReplay: "Exit Replay" +copyReplayData: "Copy replay data" +ranking: "Ranking" lastNDays: "Last {n} days" +backToTitle: "Go back to title" +hemisphere: "Where are you located" +withSensitive: "Include notes with sensitive files" +userSaysSomethingSensitive: "Post by {name} contains sensitive content" +enableHorizontalSwipe: "Swipe to switch tabs" +loading: "Loading" +surrender: "Cancel" +gameRetry: "Retry" +_bubbleGame: + howToPlay: "How to play" + hold: "Hold" + _score: + score: "Score" + scoreYen: "Amount of money earned" + highScore: "High score" + maxChain: "Maximum number of chains" + yen: "{yen} Yen" + estimatedQty: "{qty} Pieces" + scoreSweets: "{onigiriQtyWithUnit} Onigiri" + _howToPlay: + section1: "Adjust the position and drop the object into the box." + section2: "When two objects of the same type touch each other, they will change into a different object and you score points." + section3: "The game is over when objects overflow from the box. Aim for a high score by fusing objects together while you avoid overflowing the box!" _announcement: forExistingUsers: "Existing users only" forExistingUsersDescription: "This announcement will only be shown to users existing at the point of publishment if enabled. If disabled, those newly signing up after it has been posted will also see it." @@ -1189,7 +1247,7 @@ _announcement: tooManyActiveAnnouncementDescription: "Having too many active announcements may worsen the user experience. Please consider archiving announcements that have become obsolete." readConfirmTitle: "Mark as read?" readConfirmText: "This will mark the contents of \"{title}\" as read." - shouldNotBeUsedToPresentPermanentInfo: "As it may significantly impact the user experience for new users, it is recommended to use notifications in the flow information rather than stock information." + shouldNotBeUsedToPresentPermanentInfo: "It's best to use announcements to publish fresh and time-bound information, not for information that will be relevant in the long term." dialogAnnouncementUxWarn: "Having two or more dialog-style notifications simultaneously can significantly impact the user experience, so please use them carefully." silence: "No notification" silenceDescription: "Turning this on will skip the notification of this announcement and the user won't need to read it." @@ -1552,8 +1610,11 @@ _achievements: description: "Tutorial completed" _bubbleGameExplodingHead: title: "🤯" + description: "The biggest object in the bubble game" _bubbleGameDoubleExplodingHead: title: "Double🤯" + description: "Two of the biggest objects in the bubble game at the same time" + flavor: "You can fill a lunch box like this 🤯 🤯 a bit." _role: new: "New role" edit: "Edit role" @@ -1594,6 +1655,7 @@ _role: gtlAvailable: "Can view the global timeline" ltlAvailable: "Can view the local timeline" canPublicNote: "Can send public notes" + mentionMax: "Maximum number of mentions in a note" canInvite: "Can create instance invite codes" inviteLimit: "Invite limit" inviteLimitCycle: "Invite limit cooldown" @@ -1615,7 +1677,9 @@ _role: canHideAds: "Can hide ads" canSearchNotes: "Usage of note search" canUseTranslator: "Translator usage" + avatarDecorationLimit: "Maximum number of avatar decorations that can be applied" _condition: + roleAssignedTo: "Assigned to manual roles" isLocal: "Local user" isRemote: "Remote user" createdLessThan: "Less than X has passed since account creation" @@ -1643,6 +1707,7 @@ _emailUnavailable: disposable: "Disposable email addresses may not be used" mx: "This email server is invalid" smtp: "This email server is not responding" + banned: "You cannot register with this email address" _ffVisibility: public: "Public" followers: "Visible to followers only" @@ -1715,6 +1780,8 @@ _aboutMisskey: contributors: "Main contributors" allContributors: "All contributors" source: "Source code" + original: "Original" + thisIsModifiedVersion: "{name} uses a modified version of the original Misskey." translation: "Translate Misskey" donate: "Donate to Misskey" morePatrons: "We also appreciate the support of many other helpers not listed here. Thank you! 🥰" @@ -1934,6 +2001,55 @@ _permissions: "write:flash": "Edit Plays" "read:flash-likes": "View list of liked Plays" "write:flash-likes": "Edit list of liked Plays" + "read:admin:abuse-user-reports": "View user reports" + "write:admin:delete-account": "Delete user account" + "write:admin:delete-all-files-of-a-user": "Delete all files of a user" + "read:admin:index-stats": "View database index stats" + "read:admin:table-stats": "View database table stats" + "read:admin:user-ips": "View user IP addresses" + "read:admin:meta": "View instance metadata" + "write:admin:reset-password": "Reset user password" + "write:admin:resolve-abuse-user-report": "Resolve user report" + "write:admin:send-email": "Send email" + "read:admin:server-info": "View server info" + "read:admin:show-moderation-log": "View moderation log" + "read:admin:show-user": "View private user info" + "read:admin:show-users": "View private user info" + "write:admin:suspend-user": "Suspend user" + "write:admin:unset-user-avatar": "Remove user avatar" + "write:admin:unset-user-banner": "Remove user banner" + "write:admin:unsuspend-user": "Unsuspend user" + "write:admin:meta": "Manage instance metadata" + "write:admin:user-note": "Manage moderation note" + "write:admin:roles": "Manage roles" + "read:admin:roles": "View roles" + "write:admin:relays": "Manage relays" + "read:admin:relays": "View relays" + "write:admin:invite-codes": "Manage invite codes" + "read:admin:invite-codes": "View invite codes" + "write:admin:announcements": "Manage announcements" + "read:admin:announcements": "View announcements" + "write:admin:avatar-decorations": "Manage avatar decorations" + "read:admin:avatar-decorations": "View avatar decorations" + "write:admin:federation": "Manage federation data" + "write:admin:account": "Manage user account" + "read:admin:account": "View user account" + "write:admin:emoji": "Manage emoji" + "read:admin:emoji": "View emoji" + "write:admin:queue": "Manage job queue" + "read:admin:queue": "View job queue info" + "write:admin:promo": "Manage promotion notes" + "write:admin:drive": "Manage user drive" + "read:admin:drive": "View user drive info" + "read:admin:stream": "Use WebSocket API for Admin" + "write:admin:ad": "Manage ads" + "read:admin:ad": "View ads" + "write:invite-codes": "Create invite codes" + "read:invite-codes": "Get invite codes" + "write:clip-favorite": "Manage favorited clips" + "read:clip-favorite": "View favorited clips" + "read:federation": "Get federation data" + "write:report-abuse": "Report violation" _auth: shareAccessTitle: "Granting application permissions" shareAccess: "Would you like to authorize \"{name}\" to access this account?" @@ -2051,6 +2167,7 @@ _profile: changeAvatar: "Change avatar" changeBanner: "Change banner" verifiedLinkDescription: "By entering an URL that contains a link to your profile here, an ownership verification icon can be displayed next to the field." + avatarDecorationMax: "You can add up to {max} decorations." _exportOrImport: allNotes: "All notes" favoritedNotes: "Favorite notes" @@ -2183,6 +2300,7 @@ _notification: reactedBySomeUsers: "{n} users reacted" renotedBySomeUsers: "Renote from {n} users" followedBySomeUsers: "Followed by {n} users" + flushNotification: "Clear notifications" _types: all: "All" note: "New notes" @@ -2280,6 +2398,7 @@ _moderationLogTypes: resetPassword: "Password reset" suspendRemoteInstance: "Remote instance suspended" unsuspendRemoteInstance: "Remote instance unsuspended" + updateRemoteInstanceNote: "Moderation note updated for remote instance." markSensitiveDriveFile: "File marked as sensitive" unmarkSensitiveDriveFile: "File unmarked as sensitive" resolveAbuseReport: "Report resolved" @@ -2344,14 +2463,65 @@ _externalResourceInstaller: _dataSaver: _media: title: "Loading Media" + description: "Prevents images/videos from being loaded automatically. Hidden images/videos will be loaded when tapped." _avatar: title: "Avatar image" description: "Stop avatar image animation. Animated images can be larger in file size than normal images, potentially leading to further reductions in data traffic." _urlPreview: title: "URL preview thumbnails" + description: "URL preview thumbnail images will no longer be loaded." _code: title: "Code highlighting" description: "If code highlighting notations are used in MFM, etc., they will not load until tapped. Syntax highlighting requires downloading the highlight definition files for each programming language. Therefore, disabling the automatic loading of these files is expected to reduce the amount of communication data." +_hemisphere: + N: "Northern Hemisphere" + S: "Southern Hemisphere" + caption: "Used in some client settings to determine season." _reversi: + reversi: "Reversi" + gameSettings: "Game settings" + chooseBoard: "Choose a board" + blackOrWhite: "Black/White" + blackIs: "{name} is playing Black" + rules: "Rules" + thisGameIsStartedSoon: "The game will begin shortly" + waitingForOther: "Waiting for opponent's turn" + waitingForMe: "Waiting for your turn" + waitingBoth: "Get ready" + ready: "Ready" + cancelReady: "Not ready" + opponentTurn: "Opponent's turn" + myTurn: "Your turn" + turnOf: "It's {name}'s turn" + pastTurnOf: "{name}'s turn" + surrender: "Surrender" + surrendered: "Surrendered" + timeout: "Out of time" + drawn: "Draw" + won: "{name} wins" + black: "Black" + white: "White" total: "Total" + turnCount: "Turn {count}" + myGames: "My rounds" + allGames: "All rounds" + ended: "Ended" + playing: "Currently playing" + isLlotheo: "The one with fewer stones wins (Llotheo)" + loopedMap: "Looping map" + canPutEverywhere: "Tiles are placeable everywhere" + timeLimitForEachTurn: "Time limit for turn" + freeMatch: "Free Match" + lookingForPlayer: "Finding opponent..." + gameCanceled: "The game has been cancelled." + shareToTlTheGameWhenStart: "Share Game to timeline when started" + iStartedAGame: "The game has begun! #MisskeyReversi" + opponentHasSettingsChanged: "The opponent has changed their settings." + allowIrregularRules: "Irregular rules (completely free)" + disallowIrregularRules: "No irregular rules" + showBoardLabels: "Display row and column numbering on the board" + useAvatarAsStone: "Turn stones into user avatars" +_offlineScreen: + title: "Offline - cannot connect to the server" + header: "Unable to connect to the server" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index d4c0d6c4ad..246ec23604 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -11,7 +11,7 @@ password: "Contraseña" forgotPassword: "Olvidé mi contraseña" fetchingAsApObject: "Buscando en el fediverso" ok: "OK" -gotIt: "Entendido" +gotIt: "¡Lo tengo!" cancel: "Cancelar" noThankYou: "No gracias" enterUsername: "Introduce el nombre de usuario" @@ -1041,6 +1041,8 @@ resetPasswordConfirm: "¿Realmente quieres cambiar la contraseña?" sensitiveWords: "Palabras sensibles" sensitiveWordsDescription: "La visibilidad de todas las notas que contienen cualquiera de las palabras configuradas serán puestas en \"Inicio\" automáticamente. Puedes enumerás varias separándolas con saltos de línea" sensitiveWordsDescription2: "Si se usan espacios se crearán expresiones AND y las palabras subsecuentes con barras inclinadas se convertirán en expresiones regulares." +prohibitedWords: "Palabras explícitas" +prohibitedWordsDescription2: "Si se usan espacios se crearán expresiones AND y las palabras subsecuentes con barras inclinadas se convertirán en expresiones regulares." hiddenTags: "Hashtags ocultos" hiddenTagsDescription: "Selecciona las etiquetas que no se mostrarán en tendencias. Una etiqueta por línea." notesSearchNotAvailable: "No se puede buscar una nota" @@ -1059,6 +1061,8 @@ limitWidthOfReaction: "Limitar ancho de las reacciones" noteIdOrUrl: "ID o URL de la nota" video: "Video" videos: "Video" +audio: "Sonido" +audioFiles: "Sonido" dataSaver: "Ahorro de datos" accountMigration: "Migración de cuenta" accountMoved: "Este usuario se movió a una nueva cuenta:" @@ -1162,6 +1166,7 @@ hideRepliesToOthersInTimelineAll: "Ocultar tus respuestas a otros usuarios que s confirmShowRepliesAll: "Esta operación es irreversible. ¿Confirmas que quieres mostrar tus respuestas a otros usuarios que sigues en tu línea de tiempo?" confirmHideRepliesAll: "Esta operación es irreversible. ¿Confirmas que quieres ocultar tus respuestas a otros usuarios que sigues en tu línea de tiempo?" externalServices: "Servicios Externos" +sourceCode: "Código fuente" impressum: "Impressum" impressumUrl: "Impressum URL" impressumDescription: "En algunos países, como Alemania, la inclusión del operador de datos (el Impressum) es requerido legalmente para sitios web comerciales." @@ -1193,14 +1198,24 @@ addMfmFunction: "Añadir función MFM" enableQuickAddMfmFunction: "Activar acceso rápido para añadir funciones MFM" bubbleGame: "Bubble Game" sfx: "Efectos de sonido" -soundWillBePlayed: "Se reproducirán efector sonoros" +soundWillBePlayed: "Se reproducirán efectos sonoros" showReplay: "Ver reproducción" replay: "Reproducir" replaying: "Reproduciendo" ranking: "Clasificación" lastNDays: "Últimos {n} días" +backToTitle: "Regresar al inicio" +hemisphere: "Región" +withSensitive: "Mostrar notas que contengan material sensible" +userSaysSomethingSensitive: "La publicación de {name} contiene material sensible" +enableHorizontalSwipe: "Deslice para cambiar de pestaña" +surrender: "detener" _bubbleGame: howToPlay: "Cómo jugar" + _howToPlay: + section1: "Ajuste la posición y deje caer el objeto en la caja" + section2: "Cuando dos objetos del mismo tipo se tocan, cambian a otro tipo y consigues puntos" + section3: "El juego termina cuando la caja se desborda de objetos. ¡Intenta conseguir una puntuación alta al juntar objetos mientras evitas desbordar la caja!" _announcement: forExistingUsers: "Solo para usuarios registrados" forExistingUsersDescription: "Este anuncio solo se mostrará a aquellos usuarios registrados en el momento de su publicación. Si se deshabilita esta opción, aquellos usuarios que se registren tras su publicación también lo verán." @@ -2426,6 +2441,11 @@ _dataSaver: _code: title: "Resaltar código" description: "Si se usa resaltado de código en MFM, etc., no se cargará hasta pulsar en ello. El resaltado de sintaxis requiere la descarga de archivos de definición para cada lenguaje de programación. Debido a esto, al deshabilitar la carga automática de estos archivos reducirás el consumo de datos." +_hemisphere: + N: "Hemisferio norte" + S: "Hemisferio sur" _reversi: + reversi: "Reversi" + won: "{name} ha ganado" total: "Total" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index a10580bcf3..9629726f54 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -2,7 +2,7 @@ _lang_: "Français" headlineMisskey: "Réseau relié par des notes" introMisskey: "Bienvenue ! Misskey est un service de microblogage décentralisé, libre et ouvert.\nÉcrivez des « notes » et partagez ce qui se passe à l’instant présent, autour de vous avec les autres 📡\nLa fonction « réactions », vous permet également d’ajouter une réaction rapide aux notes des autres utilisateur·rice·s 👍\nExplorons un nouveau monde 🚀" -poweredByMisskeyDescription: "{nom} est l'un des services propulsés par la plateforme ouverte Misskey (appelée \"instance Misskey\")." +poweredByMisskeyDescription: "{name} est l'un des services propulsés par la plateforme ouverte Misskey (appelée \"instance Misskey\")." monthAndDay: "{day}/{month}" search: "Rechercher" notifications: "Notifications" @@ -380,8 +380,11 @@ hcaptcha: "hCaptcha" enableHcaptcha: "Activer hCaptcha" hcaptchaSiteKey: "Clé du site" hcaptchaSecretKey: "Clé secrète" +mcaptcha: "mCaptcha" +enableMcaptcha: "Activer mCaptcha" mcaptchaSiteKey: "Clé du site" mcaptchaSecretKey: "Clé secrète" +mcaptchaInstanceUrl: "URL de l'instance de mCaptcha" recaptcha: "reCAPTCHA" enableRecaptcha: "Activer reCAPTCHA" recaptchaSiteKey: "Clé du site" @@ -399,7 +402,7 @@ antennaKeywords: "Mots clés à recevoir" antennaExcludeKeywords: "Mots clés à exclure" antennaKeywordsDescription: "Séparer avec des espaces pour la condition AND. Séparer avec un saut de ligne pour une condition OR." notifyAntenna: "Me notifier pour les nouvelles notes" -withFileAntenna: "Notes ayant des attachements uniquement" +withFileAntenna: "Notes ayant des fichiers joints uniquement" enableServiceworker: "Activer ServiceWorker" antennaUsersDescription: "Saisissez un seul nom d’utilisateur·rice par ligne" caseSensitive: "Sensible à la casse" @@ -523,7 +526,7 @@ hideThisNote: "Masquer cette note" showFeaturedNotesInTimeline: "Afficher les notes des Tendances dans le fil d'actualité" objectStorage: "Stockage d'objets" useObjectStorage: "Utiliser le stockage d'objets" -objectStorageBaseUrl: "Base URL" +objectStorageBaseUrl: "URL de base" objectStorageBaseUrlDesc: "Préfixe d’URL utilisé pour construire l’URL vers le référencement d’objet (média). Spécifiez son URL si vous utilisez un CDN ou un proxy, sinon spécifiez l’adresse accessible au public selon le guide de service que vous allez utiliser. P.ex. 'https://.s3.amazonaws.com' pour AWS S3 et 'https://storage.googleapis.com/' pour GCS." objectStorageBucket: "Bucket" objectStorageBucketDesc: "Veuillez spécifier le nom du compartiment utilisé sur le service configuré." @@ -628,6 +631,7 @@ medium: "Moyen" small: "Petit" generateAccessToken: "Générer un jeton d'accès" permission: "Autorisations " +adminPermission: "Droits de l'administrateur" enableAll: "Tout activer" disableAll: "Tout désactiver" tokenRequested: "Autoriser l'accès au compte" @@ -1031,12 +1035,18 @@ nonSensitiveOnlyForLocalLikeOnlyForRemote: "Non sensibles seulement (mentions j' rolesAssignedToMe: "Rôles attribués à moi" resetPasswordConfirm: "Souhaitez-vous réinitialiser votre mot de passe ?" sensitiveWords: "Mots sensibles" +sensitiveWordsDescription2: "Séparer par une espace pour créer une expression AND ; entourer de barres obliques pour créer une expression régulière." +prohibitedWords: "Mots interdits" +prohibitedWordsDescription2: "Séparer par une espace pour créer une expression AND ; entourer de barres obliques pour créer une expression régulière." hiddenTags: "Hashtags cachés" hiddenTagsDescription: "Les hashtags définis ne s'afficheront pas dans les tendances. Vous pouvez définir plusieurs hashtags en faisant un saut de ligne." notesSearchNotAvailable: "La recherche de notes n'est pas disponible." license: "Licence" +unfavoriteConfirm: "Vraiment supprimer des favoris ?" myClips: "Mes clips" drivecleaner: "Nettoyeur du Disque" +retryAllQueuesNow: "Réessayer tous les fils d'attente immédiatement" +retryAllQueuesConfirmTitle: "Vraiment réessayer ?" retryAllQueuesConfirmText: "Cela peut augmenter temporairement la charge du serveur." enableChartsForRemoteUser: "Générer les graphiques pour les utilisateurs distants" enableChartsForFederatedInstances: "Générer les graphiques pour les instances distantes" @@ -1046,6 +1056,8 @@ limitWidthOfReaction: "Limiter la largeur maximale des réactions et les affiche noteIdOrUrl: "Identifiant de la note ou URL" video: "Vidéo" videos: "Vidéos" +audio: "Audio" +audioFiles: "Fichiers audio" dataSaver: "Économiseur de données" accountMigration: "Migration de compte" accountMoved: "Cet·te utilisateur·rice a migré son compte vers :" @@ -1084,7 +1096,10 @@ specifyUser: "Spécifier l'utilisateur·rice" failedToPreviewUrl: "Aperçu d'URL échoué" update: "Mettre à jour" rolesThatCanBeUsedThisEmojiAsReaction: "Rôles qui peuvent utiliser cet émoji comme réaction" +rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "Si aucun rôle n'est spécifié, tout le monde peut utiliser cet émoji comme réaction." +rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Il faut un rôle public." cancelReactionConfirm: "Supprimez la réaction ?" +changeReactionConfirm: "Changer la réaction ?" later: "Plus tard" goToMisskey: "Retour vers Misskey" additionalEmojiDictionary: "Dictionnaires d'émojis additionnels" @@ -1110,11 +1125,13 @@ used: "Utilisé" expired: "Expiré" doYouAgree: "Êtes-vous d’accord ?" beSureToReadThisAsItIsImportant: "Assurez-vous de le lire ; c'est important." +iHaveReadXCarefullyAndAgree: "J'ai lu le contenu de « {x} » et donne mon accord." dialog: "Dialogue" icon: "Avatar" forYou: "Pour vous" currentAnnouncements: "Annonces actuelles" pastAnnouncements: "Annonces passées" +youHaveUnreadAnnouncements: "Il y a des annonces non lues." replies: "Réponses" renotes: "Renotes" loadReplies: "Inclure les réponses" @@ -1129,6 +1146,7 @@ showRenotes: "Afficher les renotes" edited: "Modifié" notificationRecieveConfig: "Paramètres des notifications" mutualFollow: "Abonnement mutuel" +fileAttachedOnly: "Avec fichiers joints seulement" showRepliesToOthersInTimeline: "Afficher les réponses aux autres dans le fil" hideRepliesToOthersInTimeline: "Masquer les réponses aux autres dans le fil" showRepliesToOthersInTimelineAll: "Afficher les réponses de toutes les personnes que vous suivez dans le fil" @@ -1136,6 +1154,12 @@ hideRepliesToOthersInTimelineAll: "Masquer les réponses de toutes les personnes confirmShowRepliesAll: "Cette opération est irréversible. Voulez-vous vraiment afficher les réponses de toutes les personnes que vous suivez dans le fil ?" confirmHideRepliesAll: "Cette opération est irréversible. Voulez-vous vraiment masquer les réponses de toutes les personnes que vous suivez dans le fil ?" externalServices: "Services externes" +sourceCode: "Code source" +sourceCodeIsNotYetProvided: "Le code source n'est pas encore disponible. Veuillez signaler ce problème aux administrateurs." +repositoryUrl: "URL du dépôt" +repositoryUrlDescription: "Entrez l'URL du dépôt où se trouve le code source ici. Si vous utilisez Misskey tel quel (sans changer le code source), entrez https://github.com/misskey-dev/misskey" +feedback: "Commentaires" +feedbackUrl: "URL pour les commentaires" impressum: "Impressum" impressumUrl: "URL de l'impressum" impressumDescription: "Dans certains pays comme l'Allemagne, il est obligatoire d'afficher les informations sur l'opérateur d'un site (un impressum)." @@ -1163,7 +1187,32 @@ remainingN: "Restants : {n}" overwriteContentConfirm: "Voulez-vous remplacer le contenu actuel ?" seasonalScreenEffect: "Effet d'écran saisonnier" decorate: "Décorer" +addMfmFunction: "Insérer MFM" +enableQuickAddMfmFunction: "Afficher le sélecteur de MFM avancé" +bubbleGame: "Jeu de bulles" +sfx: "Effets sonores" +soundWillBePlayed: "Le son sera joué" +showReplay: "Voir le replay" +replay: "Rediffusion" +replaying: "En cours de rediffusion" +endReplay: "Arrêter la rediffusion" +copyReplayData: "Copier les données de la rediffusion" +ranking: "Classement" lastNDays: "Derniers {n} jours" +backToTitle: "Retourner au titre" +hemisphere: "Votre région" +enableHorizontalSwipe: "Glisser pour changer d'onglet" +loading: "Chargement en cours" +surrender: "Annuler" +gameRetry: "Réessayer" +_bubbleGame: + howToPlay: "Comment jouer" + hold: "Réserver" + _score: + score: "Score" + scoreYen: "Montant gagné" + highScore: "Meilleur score" + yen: "{yen} yens" _announcement: forExistingUsers: "Pour les utilisateurs existants seulement" readConfirmTitle: "Marquer comme lu ?" @@ -1175,7 +1224,7 @@ _initialAccountSetting: profileSetting: "Paramètres du profil" privacySetting: "Paramètres de confidentialité" initialAccountSettingCompleted: "Configuration du profil terminée avec succès !" - youCanContinueTutorial: "Vous pouvez procéder au tutoriel sur l'utilisation de {nom}(Misskey) ou vous arrêter ici et commencer à l'utiliser immédiatement." + youCanContinueTutorial: "Vous pouvez procéder au tutoriel sur l'utilisation de {name}(Misskey) ou vous arrêter ici et commencer à l'utiliser immédiatement." startTutorial: "Démarrer le tutoriel" skipAreYouSure: "Désirez-vous ignorer la configuration du profil ?" _initialTutorial: @@ -1301,10 +1350,13 @@ _achievements: title: "Régulier III" description: "Se connecter pour un total de 400 jours" _login500: + title: "Expert I" description: "Se connecter pour un total de 500 jours" _login600: + title: "Expert II" description: "Se connecter pour un total de 600 jours" _login700: + title: "Expert III" description: "Se connecter pour un total de 700 jours" _login800: description: "Se connecter pour un total de 800 jours" @@ -1399,9 +1451,12 @@ _role: description: "Description du rôle" permission: "Rôle et autorisations" assignTarget: "Attribuer" + manual: "Manuel" manualRoles: "Rôles manuels" + conditional: "Conditionnel" conditionalRoles: "Rôles conditionnels" condition: "Condition" + isConditionalRole: "Ceci est un rôle conditionnel." isPublic: "Rôle public" options: "Options" policies: "Stratégies" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index 44a0503883..514a2866ca 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -81,7 +81,7 @@ exportRequested: "Kamu telah meminta ekspor. Ini akan memakan waktu sesaat. Sete importRequested: "Kamu telah meminta impor. Ini akan memakan waktu sesaat." lists: "Daftar" noLists: "Kamu tidak memiliki daftar apapun" -note: "Catat" +note: "Catatan" notes: "Catatan" following: "Ikuti" followers: "Pengikut" @@ -381,8 +381,10 @@ enableHcaptcha: "Nyalakan hCaptcha" hcaptchaSiteKey: "Site Key" hcaptchaSecretKey: "Secret Key" mcaptcha: "mCaptcha" +enableMcaptcha: "Nyalakan mCaptcha" mcaptchaSiteKey: "Site key" mcaptchaSecretKey: "Secret Key" +mcaptchaInstanceUrl: "URL instansi mCaptcha" recaptcha: "reCAPTCHA" enableRecaptcha: "Nyalakan reCAPTCHA" recaptchaSiteKey: "Site key" @@ -630,6 +632,7 @@ medium: "Sedang" small: "Kecil" generateAccessToken: "Buat token akses" permission: "Izin" +adminPermission: "Wewenang Izin Admin" enableAll: "Aktifkan semua" disableAll: "Nonaktifkan semua" tokenRequested: "Berikan ijin akses ke akun" @@ -1038,6 +1041,8 @@ resetPasswordConfirm: "Yakin untuk mereset kata sandimu?" sensitiveWords: "Kata sensitif" sensitiveWordsDescription: "Visibilitas dari semua catatan mengandung kata yang telah diatur akan dijadikan \"Beranda\" secara otomatis. Kamu dapat mendaftarkan kata tersebut lebih dari satu dengan menuliskannya di baris baru." sensitiveWordsDescription2: "Menggunakan spasi akan membuat ekspresi AND dan kata kunci disekitarnya dengan garis miring akan mengubahnya menjadi ekspresi reguler." +prohibitedWords: "Kata yang dilarang" +prohibitedWordsDescription2: "Menggunakan spasi akan membuat ekspresi AND dan kata kunci disekitarnya dengan garis miring akan mengubahnya menjadi ekspresi reguler." hiddenTags: "Tagar tersembunyi" hiddenTagsDescription: "Pilih tanda yang mana akan tidak diperlihatkan dalam daftar tren.\nTanda lebih dari satu dapat didaftarkan dengan tiap baris." notesSearchNotAvailable: "Pencarian catatan tidak tersedia." @@ -1056,6 +1061,8 @@ limitWidthOfReaction: "Batasi lebar maksimum reaksi dan tampilkan dalam ukuran t noteIdOrUrl: "ID catatan atau URL" video: "Video" videos: "Video" +audio: "Suara" +audioFiles: "Berkas Suara" dataSaver: "Penghemat data" accountMigration: "Pemindahan akun" accountMoved: "Pengguna ini telah berpindah ke akun baru:" @@ -1159,6 +1166,7 @@ hideRepliesToOthersInTimelineAll: "Sembuyikan balasan ke lainnya dari semua oran confirmShowRepliesAll: "Operasi ini tidak dapat diubah. Apakah kamu yakin untuk menampilkan balasan ke lainnya dari semua orang yang kamu ikuti di lini masa?" confirmHideRepliesAll: "Operasi ini tidak dapat diubah. Apakah kamu yakin untuk menyembunyikan balasan ke lainnya dari semua orang yang kamu ikuti di lini masa?" externalServices: "Layanan eksternal" +sourceCode: "Sumber kode" impressum: "Impressum" impressumUrl: "Tautan Impressum" impressumDescription: "Pada beberapa negara seperti Jerman, inklusi dari informasi kontak operator (sebuah Impressum) diperlukan secara legal untuk situs web komersil." @@ -1190,10 +1198,22 @@ addMfmFunction: "Tambahkan dekorasi" enableQuickAddMfmFunction: "Tampilkan pemilih MFM tingkat lanjut" bubbleGame: "Bubble Game" sfx: "Efek Suara" +soundWillBePlayed: "Suara yang akan dimainkan" +showReplay: "Lihat tayangan ulang" +replay: "Tayangan ulang" +replaying: "Menayangkan Ulang" +ranking: "Peringkat" lastNDays: "{n} hari terakhir" backToTitle: "Ke Judul" +hemisphere: "Letak kamu tinggal" +withSensitive: "Lampirkan catatan dengan berkas sensitif" +userSaysSomethingSensitive: "Postingan oleh {name} mengandung konten sensitif" +enableHorizontalSwipe: "Geser untuk mengganti tab" +surrender: "Batalkan" _bubbleGame: howToPlay: "Cara bermain" + _howToPlay: + section1: "Atur posisi dan jatuhkan obyek ke dalam kotak." _announcement: forExistingUsers: "Hanya pengguna yang telah ada" forExistingUsersDescription: "Pengumuman ini akan dimunculkan ke pengguna yang sudah ada dari titik waktu publikasi jika dinyalakan. Apabila dimatikan, mereka yang baru mendaftar setelah publikasi ini akan juga melihatnya." @@ -1255,6 +1275,8 @@ _initialTutorial: note: "Baru aja makan donat berlapis coklat 🍩😋" _howToMakeAttachmentsSensitive: title: "Bagaimana menandai lampiran sebagai sensitif?" + _done: + title: "Kamu telah menyelesaikan tutorial! 🎉" _serverRules: description: "Daftar peraturan akan ditampilkan sebelum pendaftaran. Mengatur ringkasan dari Syarat dan Ketentuan sangat direkomendasikan." _serverSettings: @@ -1899,6 +1921,55 @@ _permissions: "write:flash": "Sunting Play" "read:flash-likes": "Lihat daftar Play yang disukai" "write:flash-likes": "Sunting daftar Play yang disukai" + "read:admin:abuse-user-reports": "Lihat laporan pengguna" + "write:admin:delete-account": "Hapus akun pengguna" + "write:admin:delete-all-files-of-a-user": "Hapus semua berkas dari seorang pengguna" + "read:admin:index-stats": "Lihat statistik indeks basis data" + "read:admin:table-stats": "Lihat statistik tabel basis data" + "read:admin:user-ips": "Lihat alamat IP pengguna" + "read:admin:meta": "Lihat metadata instansi" + "write:admin:reset-password": "Atur ulang kata sandi pengguna" + "write:admin:resolve-abuse-user-report": "Selesaikan laporan pengguna" + "write:admin:send-email": "Mengirim surel" + "read:admin:server-info": "Lihat informasi peladen" + "read:admin:show-moderation-log": "Lihat log moderasi" + "read:admin:show-user": "Lihat informasi pengguna privat" + "read:admin:show-users": "Lihat informasi pengguna privat" + "write:admin:suspend-user": "Tangguhkan pengguna" + "write:admin:unset-user-avatar": "Hapus avatar pengguna" + "write:admin:unset-user-banner": "Hapus banner pengguna" + "write:admin:unsuspend-user": "Batalkan penangguhan pengguna" + "write:admin:meta": "Kelola metadata instansi" + "write:admin:user-note": "Kelola moderasi catatan" + "write:admin:roles": "Kelola peran" + "read:admin:roles": "Lihat peran" + "write:admin:relays": "Kelola relay" + "read:admin:relays": "Lihat relay" + "write:admin:invite-codes": "Kelola kode undangan" + "read:admin:invite-codes": "Lihat kode undangan" + "write:admin:announcements": "Kelola pengumuman" + "read:admin:announcements": "Lihat Pengumuman" + "write:admin:avatar-decorations": "Kelola dekorasi avatar" + "read:admin:avatar-decorations": "Lihat dekorasi avatar" + "write:admin:federation": "Kelola data federasi" + "write:admin:account": "Kelola akun pengguna" + "read:admin:account": "Lihat akun pengguna" + "write:admin:emoji": "Kelola emoji" + "read:admin:emoji": "Lihat emoji" + "write:admin:queue": "Kelola antrian kerja" + "read:admin:queue": "Lihat informasi antrian kerja" + "write:admin:promo": "Kelola catatan promosi" + "write:admin:drive": "Kelola drive pengguna" + "read:admin:drive": "Kelola informasi drive pengguna" + "read:admin:stream": "Gunakan API WebSocket untuk Admin" + "write:admin:ad": "Kelola iklan" + "read:admin:ad": "Lihat iklan" + "write:invite-codes": "Membuat kode undangan" + "read:invite-codes": "Mendapatkan kode undangan" + "write:clip-favorite": "Kelola klip yang difavoritkan" + "read:clip-favorite": "Lihat klip yang difavoritkan" + "read:federation": "Mendapatkan data federasi" + "write:report-abuse": "Melaporkan pelanggaran" _auth: shareAccessTitle: "Mendapatkan ijin akses aplikasi" shareAccess: "Apakah kamu ingin mengijinkan \"{name}\" untuk mengakses akun ini?" @@ -1953,6 +2024,7 @@ _widgets: _userList: chooseList: "Pilih daftar" clicker: "Pengeklik" + birthdayFollowings: "Pengguna yang merayakan hari ulang tahunnya hari ini" _cw: hide: "Sembunyikan" show: "Lihat konten" @@ -2319,6 +2391,41 @@ _dataSaver: _code: title: "Penyorotan kode" description: "Jika notasi penyorotan kode digunakan di MFM, dll. Fungsi tersebut tidak akan dimuat apabila tidak diketuk. Penyorotan sintaks membutuhkan pengunduhan berkas definisi penyorotan untuk setiap bahasa pemrograman. Oleh sebab itu, menonaktifkan pemuatan otomatis dari berkas ini dilakukan untuk mengurangi jumlah komunikasi data." +_hemisphere: + N: "Bumi belahan utara" + S: "Bumi belahan selatan" + caption: "Digunakan dalam beberapa pengaturan klien untuk menentukan musim." _reversi: + reversi: "Reversi" + gameSettings: "Pengaturan permainan" + chooseBoard: "Pilih papan" + blackOrWhite: "Hitam/Putih" + blackIs: "{name} bermain sebagai Hitam" + rules: "Aturan" + thisGameIsStartedSoon: "Permainan akan segera dimulai" + waitingForOther: "Menunggu langkah giliran dari lawan" + waitingForMe: "Menungguh langkah giliran dari kamu" + waitingBoth: "Bersiap" + ready: "Siap" + cancelReady: "Belum siap" + opponentTurn: "Giliran lawan" + myTurn: "Giliran kamu" + turnOf: "Giliran {name}" + pastTurnOf: "Giliran {name}" + surrender: "Menyerah" + surrendered: "Telah menyerah" + timeout: "Waktu habis" + drawn: "Seri" + won: "{name} menang" + black: "Hitam" + white: "Putih" total: "Jumlah" + turnCount: "Langkah ke {count}" + myGames: "Rondeku" + allGames: "Semua ronde" + ended: "Selesai" + playing: "Sedang bermain" + isLlotheo: "Pemain dengan batu yang sedikit menang (Llotheo)" + loopedMap: "Peta melingkar" + canPutEverywhere: "Keping dapat ditaruh dimana saja" diff --git a/locales/index.d.ts b/locales/index.d.ts index 6aaa9fc034..9621a737dc 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -3980,6 +3980,10 @@ export interface Locale extends ILocale { * Misskeyは{host}が使用している無料のソフトウェアです。これからも開発を続けられるように、ぜひ寄付をお願いします! */ "pleaseDonate": ParameterizedString<"host">; + /** + * 対応するソースコードは{anchor}から利用可能です。 + */ + "correspondingSourceIsAvailable": ParameterizedString<"anchor">; /** * ロール */ @@ -4180,6 +4184,18 @@ export interface Locale extends ILocale { * スペースで区切るとAND指定になり、キーワードをスラッシュで囲むと正規表現になります。 */ "sensitiveWordsDescription2": string; + /** + * 禁止ワード + */ + "prohibitedWords": string; + /** + * 設定したワードが含まれるノートを投稿しようとした際、エラーとなるようにします。改行で区切って複数設定できます。 + */ + "prohibitedWordsDescription": string; + /** + * スペースで区切るとAND指定になり、キーワードをスラッシュで囲むと正規表現になります。 + */ + "prohibitedWordsDescription2": string; /** * 非表示ハッシュタグ */ @@ -4640,6 +4656,10 @@ export interface Locale extends ILocale { * 相互フォロー */ "mutualFollow": string; + /** + * フォロー中またはフォロワー + */ + "followingOrFollower": string; /** * ファイル付きのみ */ @@ -4672,6 +4692,34 @@ export interface Locale extends ILocale { * 外部サービス */ "externalServices": string; + /** + * ソースコード + */ + "sourceCode": string; + /** + * ソースコードはまだ提供されていません。この問題の修正について管理者に問い合わせてください。 + */ + "sourceCodeIsNotYetProvided": string; + /** + * リポジトリURL + */ + "repositoryUrl": string; + /** + * ソースコードが公開されているリポジトリがある場合、そのURLを記入します。Misskeyを現状のまま(ソースコードにいかなる変更も加えずに)使用している場合は https://github.com/misskey-dev/misskey と記入します。 + */ + "repositoryUrlDescription": string; + /** + * リポジトリを公開していない場合、代わりにtarballを提供する必要があります。詳細は.config/example.ymlを参照してください。 + */ + "repositoryUrlOrTarballRequired": string; + /** + * フィードバック + */ + "feedback": string; + /** + * フィードバックURL + */ + "feedbackUrl": string; /** * 運営者情報 */ @@ -4812,6 +4860,14 @@ export interface Locale extends ILocale { * リプレイ中 */ "replaying": string; + /** + * リプレイを終了 + */ + "endReplay": string; + /** + * リプレイデータをコピー + */ + "copyReplayData": string; /** * ランキング */ @@ -4840,11 +4896,57 @@ export interface Locale extends ILocale { * スワイプしてタブを切り替える */ "enableHorizontalSwipe": string; + /** + * 読み込み中 + */ + "loading": string; + /** + * やめる + */ + "surrender": string; + /** + * リトライ + */ + "gameRetry": string; "_bubbleGame": { /** * 遊び方 */ "howToPlay": string; + /** + * ホールド + */ + "hold": string; + "_score": { + /** + * スコア + */ + "score": string; + /** + * 稼いだ金額 + */ + "scoreYen": string; + /** + * ハイスコア + */ + "highScore": string; + /** + * 最大チェーン数 + */ + "maxChain": string; + /** + * {yen}円 + */ + "yen": ParameterizedString<"yen">; + /** + * {qty}個分 + */ + "estimatedQty": ParameterizedString<"qty">; + /** + * おにぎり {onigiriQtyWithUnit} + */ + "scoreSweets": ParameterizedString<"onigiriQtyWithUnit">; + }; "_howToPlay": { /** * 位置を調整してハコにモノを落とします。 @@ -4894,7 +4996,7 @@ export interface Locale extends ILocale { */ "readConfirmText": ParameterizedString<"title">; /** - * 特に新規ユーザーのUXを損ねる可能性が高いため、ストック情報ではなくフロー情報の掲示にお知らせを使用することを推奨します。 + * 特に新規ユーザーのUXを損ねる可能性が高いため、常時掲示するための情報ではなく、即時性が求められる情報の掲示のためにお知らせを使用することを推奨します。 */ "shouldNotBeUsedToPresentPermanentInfo": string; /** @@ -6340,6 +6442,10 @@ export interface Locale extends ILocale { * パブリック投稿の許可 */ "canPublicNote": string; + /** + * ノート内の最大メンション数 + */ + "mentionMax": string; /** * サーバー招待コードの発行 */ @@ -6430,6 +6536,10 @@ export interface Locale extends ILocale { "avatarDecorationLimit": string; }; "_condition": { + /** + * マニュアルロールにアサイン済み + */ + "roleAssignedTo": string; /** * ローカルユーザー */ @@ -6801,6 +6911,14 @@ export interface Locale extends ILocale { * ソースコード */ "source": string; + /** + * オリジナル + */ + "original": string; + /** + * {name}はオリジナルのMisskeyを改変したバージョンを使用しています。 + */ + "thisIsModifiedVersion": ParameterizedString<"name">; /** * Misskeyを翻訳 */ @@ -8811,6 +8929,10 @@ export interface Locale extends ILocale { * {n}人にフォローされました */ "followedBySomeUsers": ParameterizedString<"n">; + /** + * 通知の履歴をリセットする + */ + "flushNotification": string; "_types": { /** * すべて @@ -9132,7 +9254,7 @@ export interface Locale extends ILocale { */ "updateServerSettings": string; /** - * モデレーションノート更新 + * ユーザーのモデレーションノート更新 */ "updateUserNote": string; /** @@ -9179,6 +9301,10 @@ export interface Locale extends ILocale { * リモートサーバーを再開 */ "unsuspendRemoteInstance": string; + /** + * リモートサーバーのモデレーションノート更新 + */ + "updateRemoteInstanceNote": string; /** * ファイルをセンシティブ付与 */ @@ -9615,6 +9741,14 @@ export interface Locale extends ILocale { * 変則なし */ "disallowIrregularRules": string; + /** + * 盤面に行・列番号を表示 + */ + "showBoardLabels": string; + /** + * 石をアイコンにする + */ + "useAvatarAsStone": string; }; "_offlineScreen": { /** diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 5678ab7e34..480d11b6ba 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -102,7 +102,7 @@ defaultNoteVisibility: "Privacy predefinita delle note" follow: "Segui" followRequest: "Richiesta di follow" followRequests: "Richieste di follow" -unfollow: "Interrompi following" +unfollow: "Smetti di seguire" followRequestPending: "Richiesta in approvazione" enterEmoji: "Inserisci emoji" renote: "Rinota" @@ -380,9 +380,11 @@ hcaptcha: "hCaptcha" enableHcaptcha: "Abilita hCaptcha" hcaptchaSiteKey: "Chiave del sito" hcaptchaSecretKey: "Chiave segreta" +mcaptcha: "mCaptcha" enableMcaptcha: "Abilita hCaptcha" mcaptchaSiteKey: "Chiave del sito" mcaptchaSecretKey: "Chiave segreta" +mcaptchaInstanceUrl: "URL della istanza mCaptcha" recaptcha: "reCAPTCHA" enableRecaptcha: "Abilita reCAPTCHA" recaptchaSiteKey: "Chiave del sito" @@ -433,7 +435,7 @@ moderation: "moderazione" moderationNote: "Promemoria di moderazione" addModerationNote: "Aggiungi promemoria di moderazione" moderationLogs: "Cronologia di moderazione" -nUsersMentioned: "{n} profili menzionati" +nUsersMentioned: "{n} profili ne parlano" securityKeyAndPasskey: "Chiave di sicurezza e accesso" securityKey: "Chiave di sicurezza" lastUsed: "Ultima attività" @@ -630,6 +632,7 @@ medium: "Medio" small: "Piccolo" generateAccessToken: "Genera token di accesso" permission: "Autorizzazioni " +adminPermission: "Privilegi amministrativi" enableAll: "Abilita tutto" disableAll: "Disabilita tutto" tokenRequested: "Autorizza accesso al profilo" @@ -655,7 +658,7 @@ hardWordMute: "Filtro parole forte" regexpError: "errore regex" regexpErrorDescription: "Si è verificato un errore nell'espressione regolare alla riga {line} della parola muta {tab}:" instanceMute: "Silenzia l'istanza" -userSaysSomething: "{name} ha detto qualcosa" +userSaysSomething: "{name} ha parlato" makeActive: "Attiva" display: "Visualizza" copy: "Copia" @@ -673,6 +676,7 @@ useGlobalSettingDesc: "Quando attiva, verranno utilizzate le impostazioni notifi other: "Ulteriori" regenerateLoginToken: "Genera di nuovo un token di connessione" regenerateLoginTokenDescription: "Genera un nuovo token di autenticazione. Solitamente questa operazione non è necessaria: quando si genera un nuovo token, tutti i dispositivi vanno disconnessi." +theKeywordWhenSearchingForCustomEmoji: "Questa sarà la parola chiave durante la ricerca di emoji personalizzate" setMultipleBySeparatingWithSpace: "È possibile creare multiple voci separate da spazi." fileIdOrUrl: "ID o URL del file" behavior: "Comportamento" @@ -758,7 +762,7 @@ reloadToApplySetting: "Le tue preferenze verranno impostate dopo il ricaricament needReloadToApply: "È necessario riavviare per rendere effettive le modifiche." showTitlebar: "Visualizza la barra del titolo" clearCache: "Svuota la cache" -onlineUsersCount: "{n} persone online" +onlineUsersCount: "{n} persone attive adesso" nUsers: "{n} profili" nNotes: "{n}Note" sendErrorReports: "Invia segnalazioni di errori" @@ -869,7 +873,7 @@ pubSub: "Publish/Subscribe del profilo" lastCommunication: "La comunicazione più recente" resolved: "Risolto" unresolved: "Non risolto" -breakFollow: "Interrompi follow" +breakFollow: "Impedire di seguirmi" breakFollowConfirm: "Vuoi davvero che questo profilo smetta di seguirti?" itsOn: "Abilitato" itsOff: "Disabilitato" @@ -885,6 +889,8 @@ makeReactionsPublicDescription: "La lista delle reazioni che avete fatto è a di classic: "Classico" muteThread: "Silenzia conversazione" unmuteThread: "Riattiva la conversazione" +followingVisibility: "Visibilità dei profili seguiti" +followersVisibility: "Visibilità dei profili che ti seguono" continueThread: "Altre conversazioni" deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?" incorrectPassword: "La password è errata." @@ -985,6 +991,7 @@ neverShow: "Non mostrare più" remindMeLater: "Rimanda" didYouLikeMisskey: "Ti piace Misskey?" pleaseDonate: "Misskey è il software libero utilizzato su {host}. Offrendo una donazione è più facile continuare a svilupparlo!" +correspondingSourceIsAvailable: "" roles: "Ruoli" role: "Ruolo" noRole: "Ruolo non trovato" @@ -1035,6 +1042,9 @@ resetPasswordConfirm: "Vuoi davvero ripristinare la password?" sensitiveWords: "Parole esplicite" sensitiveWordsDescription: "Imposta automaticamente \"Home\" alla visibilità delle Note che contengono una qualsiasi parola tra queste configurate. Puoi separarle per riga." sensitiveWordsDescription2: "Gli spazi creano la relazione \"E\" tra parole (questo E quello). Racchiudere una parola nelle slash \"/\" la trasforma in Espressione Regolare." +prohibitedWords: "Parole proibite" +prohibitedWordsDescription: "Verrà impedito di pubblicare Note che abbiano le parole indicate. Puoi impostare più parole, separatamente, su ogni riga." +prohibitedWordsDescription2: "Gli spazi creano la relazione \"E\" tra parole (questo E quello). Racchiudere una parola nelle slash \"/\" la trasforma in Espressione Regolare." hiddenTags: "Hashtag nascosti" hiddenTagsDescription: "Impedire la visualizzazione del tag impostato nei trend. Puoi impostare più valori, uno per riga." notesSearchNotAvailable: "Non è possibile cercare tra le Note." @@ -1053,6 +1063,8 @@ limitWidthOfReaction: "Limita la larghezza delle reazioni e ridimensionale" noteIdOrUrl: "ID della Nota o URL" video: "Video" videos: "Video" +audio: "Audio" +audioFiles: "Audio" dataSaver: "Risparmia dati" accountMigration: "Migrazione del profilo" accountMoved: "Questo profilo ha migrato altrove:" @@ -1156,6 +1168,13 @@ hideRepliesToOthersInTimelineAll: "Nascondi le risposte dei tuoi follow nella TL confirmShowRepliesAll: "Questa è una attività irreversibile. Vuoi davvero includere tutte le risposte dei following in TL?" confirmHideRepliesAll: "Questa è una attività irreversibile. Vuoi davvero escludere tutte le risposte dei following in TL?" externalServices: "Servizi esterni" +sourceCode: "Codice sorgente" +sourceCodeIsNotYetProvided: "" +repositoryUrl: "URL della repository" +repositoryUrlDescription: "Se esiste un repository il cui il codice sorgente è disponibile pubblicamente, inserisci il suo URL. Se stai utilizzando Misskey così com'è (senza alcuna modifica al codice sorgente), inserisci https://github.com/misskey-dev/misskey." +repositoryUrlOrTarballRequired: "Se non disponi di un repository pubblico, dovrai fornire un file tarball (tar). Vedere .config/example.yml per i dettagli." +feedback: "Feedback" +feedbackUrl: "URL di feedback" impressum: "Dichiarazione di proprietà" impressumUrl: "URL della dichiarazione di proprietà" impressumDescription: "La dichiarazione di proprietà, è obbligatoria in alcuni paesi come la Germania (Impressum)." @@ -1183,7 +1202,28 @@ remainingN: "Rimangono: {n}" overwriteContentConfirm: "Vuoi davvero sostituire l'attuale contenuto?" seasonalScreenEffect: "Schermate in base alla stagione" decorate: "Decora" +addMfmFunction: "Aggiungi decorazioni" +enableQuickAddMfmFunction: "Attiva il selettore di funzioni MFM" +bubbleGame: "Bubble Game" +sfx: "Effetti sonori" +soundWillBePlayed: "Con musica ed effetti sonori" +showReplay: "Vedi i replay" +replay: "Replay" +replaying: "Replay in corso" +ranking: "Classifica" lastNDays: "Ultimi {n} giorni" +backToTitle: "Torna al titolo" +hemisphere: "Geolocalizzazione" +withSensitive: "Mostra le Note con allegati espliciti" +userSaysSomethingSensitive: "Note da {name} con allegati espliciti" +enableHorizontalSwipe: "Trascina per invertire i tab" +surrender: "Annulla" +_bubbleGame: + howToPlay: "Come giocare" + _howToPlay: + section1: "Scegli la posizione e rilascia l'oggetto nel contenitore." + section2: "Se due oggetti dello stesso tipo si toccano, si trasformano in un oggetto diverso, aumentando il punteggio." + section3: "Se gli oggetti escono dal limite superiore del contenitore, il gioco finisce. Cerca di ottenere un punteggio elevato fondendo gli oggetti, evitando che escano dal contenitore!" _announcement: forExistingUsers: "Solo ai profili attuali" forExistingUsersDescription: "L'annuncio sarà visibile solo ai profili esistenti in questo momento. Se disabilitato, sarà visibile anche ai profili che verranno creati dopo la pubblicazione di questo annuncio." @@ -1554,6 +1594,13 @@ _achievements: _tutorialCompleted: title: "Attestato di partecipazione al corso per principianti di Misskey" description: "Ha completato il tutorial" + _bubbleGameExplodingHead: + title: "🤯" + description: "Estrai l'oggetto più grande dal Bubble Game" + _bubbleGameDoubleExplodingHead: + title: "Doppio 🤯" + description: "Due oggetti più grossi contemporaneamente nel Bubble Game" + flavor: "Ha le dimensioni di una bento-box 🤯 🤯" _role: new: "Nuovo ruolo" edit: "Modifica ruolo" @@ -1644,6 +1691,7 @@ _emailUnavailable: disposable: "Indirizzo email non utilizzabile" mx: "Server email non corretto" smtp: "Il server email non risponde" + banned: "Non puoi registrarti con questo indirizzo email" _ffVisibility: public: "Pubblica" followers: "Mostra solo ai follower" @@ -1716,6 +1764,8 @@ _aboutMisskey: contributors: "Principali sostenitori" allContributors: "Tutti i sostenitori" source: "Codice sorgente" + original: "Originale" + thisIsModifiedVersion: "{name} sta usando una versione modificata diversa da Misskey originale." translation: "Tradurre Misskey" donate: "Sostieni Misskey" morePatrons: "Apprezziamo sinceramente il supporto di tante altre persone. Grazie mille! 🥰" @@ -1935,6 +1985,55 @@ _permissions: "write:flash": "Modifica Play" "read:flash-likes": "Visualizza lista di Play piaciuti" "write:flash-likes": "Modifica lista di Play piaciuti" + "read:admin:abuse-user-reports": "Mostra i report dai profili utente" + "write:admin:delete-account": "Elimina l'account utente" + "write:admin:delete-all-files-of-a-user": "Elimina i file dell'account utente" + "read:admin:index-stats": "Visualizza informazioni sugli indici del database" + "read:admin:table-stats": "Visualizza informazioni sulle tabelle del database" + "read:admin:user-ips": "Visualizza indirizzi IP degli account" + "read:admin:meta": "Visualizza i metadati dell'istanza" + "write:admin:reset-password": "Ripristina la password dell'account utente" + "write:admin:resolve-abuse-user-report": "Risolvere le segnalazioni dagli account utente" + "write:admin:send-email": "Spedire email" + "read:admin:server-info": "Vedere le informazioni sul server" + "read:admin:show-moderation-log": "Vedere lo storico di moderazione" + "read:admin:show-user": "Vedere le informazioni private degli account utente" + "read:admin:show-users": "Vedere le informazioni private degli account utente" + "write:admin:suspend-user": "Sospendere i profili" + "write:admin:unset-user-avatar": "Rimuovere la foto profilo dai profili" + "write:admin:unset-user-banner": "Rimuovere l'immagine testata dai profili" + "write:admin:unsuspend-user": "Togliere la sospensione ai profili" + "write:admin:meta": "Modificare i metadati dell'istanza" + "write:admin:user-note": "Scrivere annotazioni di moderazione" + "write:admin:roles": "Gestire i ruoli" + "read:admin:roles": "Vedere i ruoli" + "write:admin:relays": "Gestire i Relay" + "read:admin:relays": "Vedere i Relay" + "write:admin:invite-codes": "Gestire codici di invito" + "read:admin:invite-codes": "Vedere codici di invito" + "write:admin:announcements": "Gestire gli annunci" + "read:admin:announcements": "Leggere gli annunci" + "write:admin:avatar-decorations": "Gestire le decorazioni" + "read:admin:avatar-decorations": "Vedere le decorazioni" + "write:admin:federation": "Gestire la federazione" + "write:admin:account": "Vedere la federazione" + "read:admin:account": "Vedere le utenze" + "write:admin:emoji": "Gestire le emoji personalizzate" + "read:admin:emoji": "Vedere le emoji personalizzate" + "write:admin:queue": "Gestire la coda di attività" + "read:admin:queue": "Vedere la coda di attività" + "write:admin:promo": "Gestire le promozioni" + "write:admin:drive": "Gestire il Drive degli account" + "read:admin:drive": "Vedere il Drive degli account" + "read:admin:stream": "Usare le API Websocket" + "write:admin:ad": "Gestire i banner pubblicitari" + "read:admin:ad": "Vedere i banner pubblicitari" + "write:invite-codes": "Creare codici di invito" + "read:invite-codes": "Vedere i codici di invito" + "write:clip-favorite": "Impostare Clip preferite" + "read:clip-favorite": "Vedere Clip preferite" + "read:federation": "Vedere la federazione" + "write:report-abuse": "Inviare segnalazioni" _auth: shareAccessTitle: "Permessi dell'applicazione" shareAccess: "Vuoi autorizzare {name} ad accedere al tuo profilo?" @@ -1979,7 +2078,7 @@ _widgets: postForm: "Finestra di pubblicazione" slideshow: "Diapositive" button: "Pulsante" - onlineUsers: "Persone online" + onlineUsers: "Persone attive adesso" jobQueue: "Coda di lavoro" serverMetric: "Statistiche server" aiscript: "Console AiScript" @@ -2175,6 +2274,7 @@ _notification: pollEnded: "Risultati del sondaggio." newNote: "Nuove Note" unreadAntennaNote: "Antenna {name}" + roleAssigned: "Ruolo assegnato" emptyPushNotificationMessage: "Le notifiche push sono state aggiornate." achievementEarned: "Obiettivo raggiunto" testNotification: "Prova la notifica" @@ -2196,6 +2296,7 @@ _notification: pollEnded: "Sondaggio chiuso." receiveFollowRequest: "Richiesta di follow ricevuta" followRequestAccepted: "Richiesta di follow accettata" + roleAssigned: "Ruolo concesso" achievementEarned: "Risultato raggiunto" app: "Notifiche da applicazioni" _actions: @@ -2354,6 +2455,53 @@ _dataSaver: _code: title: "Codice evidenziato" description: "Impedire che il codice sorgente sia automaticamente evidenziato. Evidenziare il codice richiede il caricamento di un file per ogni linguaggio. Puoi evidenziare soltanto il codice che intendi leggere e ridurre il traffico inutilizzato." +_hemisphere: + N: "Emisfero boreale" + S: "Emisfero australe" + caption: "Utile per alcune impostazioni del client, per determinare la stagione." _reversi: + reversi: "Reversi" + gameSettings: "Impostazioni di gioco" + chooseBoard: "Segli la tavola" + blackOrWhite: "Neri / Bianchi" + blackIs: "{name} muove i Neri" + rules: "Regole del gioco" + thisGameIsStartedSoon: "Il gioco sta per iniziare" + waitingForOther: "Attendere l'avversario" + waitingForMe: "Ti stanno aspettando" + waitingBoth: "Preparatevi" + ready: "Pronti" + cancelReady: "Riprendere la preparazione" + opponentTurn: "Turno avversario" + myTurn: "Tocca a te" + turnOf: "Tocca a {name}" + pastTurnOf: "Turno di {name}" + surrender: "Mi arrendo" + surrendered: "Ha ceduto" + timeout: "Tempo scaduto" + drawn: "Pareggio" + won: "Ha vinto {name}" + black: "Neri" + white: "Bianchi" total: "Totale" + turnCount: "Turno N. {count}" + myGames: "Le mie sfide" + allGames: "Tutte le sfide" + ended: "Conclusione" + playing: "In gioco" + isLlotheo: "Vince chi ha meno pietre (Roseo)" + loopedMap: "Mappa ricorsiva" + canPutEverywhere: "Modalità che può essere posizionata ovunque" + timeLimitForEachTurn: "Tempo limite per turno" + freeMatch: "Sfida libera" + lookingForPlayer: "Alla ricerca di un avversario" + gameCanceled: "Sfida cancellata" + shareToTlTheGameWhenStart: "Pubblica l'inizio della partita sulla tua Timeline" + iStartedAGame: "Inizia la sfida! #MisskeyReversi" + opponentHasSettingsChanged: "L'avversario ha cambiato configurazione" + allowIrregularRules: "Regole inconsuete (completamente libere)" + disallowIrregularRules: "Impedire le regole inconsuete" +_offlineScreen: + title: "Scollegato. Impossibile connettersi al server" + header: "Impossibile connettersi al server" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 7c3c82458a..717511521e 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -991,6 +991,7 @@ neverShow: "今後表示しない" remindMeLater: "また後で" didYouLikeMisskey: "Misskeyを気に入っていただけましたか?" pleaseDonate: "Misskeyは{host}が使用している無料のソフトウェアです。これからも開発を続けられるように、ぜひ寄付をお願いします!" +correspondingSourceIsAvailable: "対応するソースコードは{anchor}から利用可能です。" roles: "ロール" role: "ロール" noRole: "ロールはありません" @@ -1041,6 +1042,9 @@ resetPasswordConfirm: "パスワードリセットしますか?" sensitiveWords: "センシティブワード" sensitiveWordsDescription: "設定したワードが含まれるノートの公開範囲をホームにします。改行で区切って複数設定できます。" sensitiveWordsDescription2: "スペースで区切るとAND指定になり、キーワードをスラッシュで囲むと正規表現になります。" +prohibitedWords: "禁止ワード" +prohibitedWordsDescription: "設定したワードが含まれるノートを投稿しようとした際、エラーとなるようにします。改行で区切って複数設定できます。" +prohibitedWordsDescription2: "スペースで区切るとAND指定になり、キーワードをスラッシュで囲むと正規表現になります。" hiddenTags: "非表示ハッシュタグ" hiddenTagsDescription: "設定したタグをトレンドに表示させないようにします。改行で区切って複数設定できます。" notesSearchNotAvailable: "ノート検索は利用できません。" @@ -1156,6 +1160,7 @@ showRenotes: "リノートを表示" edited: "編集済み" notificationRecieveConfig: "通知の受信設定" mutualFollow: "相互フォロー" +followingOrFollower: "フォロー中またはフォロワー" fileAttachedOnly: "ファイル付きのみ" showRepliesToOthersInTimeline: "TLに他の人への返信を含める" hideRepliesToOthersInTimeline: "TLに他の人への返信を含めない" @@ -1164,6 +1169,13 @@ hideRepliesToOthersInTimelineAll: "TLに現在フォロー中の人全員の返 confirmShowRepliesAll: "この操作は元に戻せません。本当にTLに現在フォロー中の人全員の返信を含めるようにしますか?" confirmHideRepliesAll: "この操作は元に戻せません。本当にTLに現在フォロー中の人全員の返信を含めないようにしますか?" externalServices: "外部サービス" +sourceCode: "ソースコード" +sourceCodeIsNotYetProvided: "ソースコードはまだ提供されていません。この問題の修正について管理者に問い合わせてください。" +repositoryUrl: "リポジトリURL" +repositoryUrlDescription: "ソースコードが公開されているリポジトリがある場合、そのURLを記入します。Misskeyを現状のまま(ソースコードにいかなる変更も加えずに)使用している場合は https://github.com/misskey-dev/misskey と記入します。" +repositoryUrlOrTarballRequired: "リポジトリを公開していない場合、代わりにtarballを提供する必要があります。詳細は.config/example.ymlを参照してください。" +feedback: "フィードバック" +feedbackUrl: "フィードバックURL" impressum: "運営者情報" impressumUrl: "運営者情報URL" impressumDescription: "ドイツなどの一部の国と地域では表示が義務付けられています(Impressum)。" @@ -1199,6 +1211,8 @@ soundWillBePlayed: "サウンドが再生されます" showReplay: "リプレイを見る" replay: "リプレイ" replaying: "リプレイ中" +endReplay: "リプレイを終了" +copyReplayData: "リプレイデータをコピー" ranking: "ランキング" lastNDays: "直近{n}日" backToTitle: "タイトルへ" @@ -1206,9 +1220,21 @@ hemisphere: "お住まいの地域" withSensitive: "センシティブなファイルを含むノートを表示" userSaysSomethingSensitive: "{name}のセンシティブなファイルを含む投稿" enableHorizontalSwipe: "スワイプしてタブを切り替える" +loading: "読み込み中" +surrender: "やめる" +gameRetry: "リトライ" _bubbleGame: howToPlay: "遊び方" + hold: "ホールド" + _score: + score: "スコア" + scoreYen: "稼いだ金額" + highScore: "ハイスコア" + maxChain: "最大チェーン数" + yen: "{yen}円" + estimatedQty: "{qty}個分" + scoreSweets: "おにぎり {onigiriQtyWithUnit}" _howToPlay: section1: "位置を調整してハコにモノを落とします。" section2: "同じ種類のモノがくっつくと別のモノに変化して、スコアが得られます。" @@ -1223,7 +1249,7 @@ _announcement: tooManyActiveAnnouncementDescription: "アクティブなお知らせが多いため、UXが低下する可能性があります。終了したお知らせはアーカイブすることを検討してください。" readConfirmTitle: "既読にしますか?" readConfirmText: "「{title}」の内容を読み、既読にします。" - shouldNotBeUsedToPresentPermanentInfo: "特に新規ユーザーのUXを損ねる可能性が高いため、ストック情報ではなくフロー情報の掲示にお知らせを使用することを推奨します。" + shouldNotBeUsedToPresentPermanentInfo: "特に新規ユーザーのUXを損ねる可能性が高いため、常時掲示するための情報ではなく、即時性が求められる情報の掲示のためにお知らせを使用することを推奨します。" dialogAnnouncementUxWarn: "ダイアログ形式のお知らせが同時に2つ以上ある場合、UXに悪影響を及ぼす可能性が非常に高いため、使用は慎重に行うことを推奨します。" silence: "非通知" silenceDescription: "オンにすると、このお知らせは通知されず、既読にする必要もなくなります。" @@ -1639,6 +1665,7 @@ _role: gtlAvailable: "グローバルタイムラインの閲覧" ltlAvailable: "ローカルタイムラインの閲覧" canPublicNote: "パブリック投稿の許可" + mentionMax: "ノート内の最大メンション数" canInvite: "サーバー招待コードの発行" inviteLimit: "招待コードの作成可能数" inviteLimitCycle: "招待コードの発行間隔" @@ -1662,6 +1689,7 @@ _role: canUseTranslator: "翻訳機能の利用" avatarDecorationLimit: "アイコンデコレーションの最大取付個数" _condition: + roleAssignedTo: "マニュアルロールにアサイン済み" isLocal: "ローカルユーザー" isRemote: "リモートユーザー" createdLessThan: "アカウント作成から~以内" @@ -1775,6 +1803,8 @@ _aboutMisskey: contributors: "コントリビューター" allContributors: "全てのコントリビューター" source: "ソースコード" + original: "オリジナル" + thisIsModifiedVersion: "{name}はオリジナルのMisskeyを改変したバージョンを使用しています。" translation: "Misskeyを翻訳" donate: "Misskeyに寄付" morePatrons: "他にも多くの方が支援してくれています。ありがとうございます🥰" @@ -2330,6 +2360,7 @@ _notification: reactedBySomeUsers: "{n}人がリアクションしました" renotedBySomeUsers: "{n}人がリノートしました" followedBySomeUsers: "{n}人にフォローされました" + flushNotification: "通知の履歴をリセットする" _types: all: "すべて" @@ -2424,7 +2455,7 @@ _moderationLogTypes: updateCustomEmoji: "カスタム絵文字更新" deleteCustomEmoji: "カスタム絵文字削除" updateServerSettings: "サーバー設定更新" - updateUserNote: "モデレーションノート更新" + updateUserNote: "ユーザーのモデレーションノート更新" deleteDriveFile: "ファイルを削除" deleteNote: "ノートを削除" createGlobalAnnouncement: "全体のお知らせを作成" @@ -2436,6 +2467,7 @@ _moderationLogTypes: resetPassword: "パスワードをリセット" suspendRemoteInstance: "リモートサーバーを停止" unsuspendRemoteInstance: "リモートサーバーを再開" + updateRemoteInstanceNote: "リモートサーバーのモデレーションノート更新" markSensitiveDriveFile: "ファイルをセンシティブ付与" unmarkSensitiveDriveFile: "ファイルをセンシティブ解除" resolveAbuseReport: "通報を解決" @@ -2561,6 +2593,8 @@ _reversi: opponentHasSettingsChanged: "相手が設定を変更しました" allowIrregularRules: "変則許可 (完全フリー)" disallowIrregularRules: "変則なし" + showBoardLabels: "盤面に行・列番号を表示" + useAvatarAsStone: "石をアイコンにする" _offlineScreen: title: "オフライン - サーバーに接続できません" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 719812bfdb..7ff26c757d 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -991,6 +991,7 @@ neverShow: "今後表示しない" remindMeLater: "また後で" didYouLikeMisskey: "Misskey気に入ってくれた?" pleaseDonate: "Misskeyは{host}が使うとる無料のソフトウェアやで。これからも開発を続けれるように、寄付したってな~。" +correspondingSourceIsAvailable: "{anchor}" roles: "ロール" role: "ロール" noRole: "ロールはありまへん" @@ -1041,6 +1042,7 @@ resetPasswordConfirm: "パスワード作り直すんでええな?" sensitiveWords: "けったいな単語" sensitiveWordsDescription: "設定した単語が入っとるノートの公開範囲をホームにしたるわ。改行で区切ったら複数設定できるで。" sensitiveWordsDescription2: "スペースで区切るとAND指定、キーワードをスラッシュで囲んだら正規表現や。" +prohibitedWordsDescription2: "スペースで区切るとAND指定、キーワードをスラッシュで囲んだら正規表現や。" hiddenTags: "見えてへんハッシュタグ" hiddenTagsDescription: "設定したタグを最近流行りのとこに見えんようにすんで。複数設定するときは改行で区切ってな。" notesSearchNotAvailable: "なんかノート探せへん。" @@ -1164,6 +1166,7 @@ hideRepliesToOthersInTimelineAll: "タイムラインに今フォローしとる confirmShowRepliesAll: "これは元に戻せへんから慎重に決めてや。本当にタイムラインに今フォローしとる全員の返信を入れるか?" confirmHideRepliesAll: "これは元に戻せへんから慎重に決めてや。本当にタイムラインに今フォローしとる全員の返信を入れへんのか?" externalServices: "他のサイトのサービス" +sourceCode: "ソースコード" impressum: "運営者の情報" impressumUrl: "運営者の情報URL" impressumDescription: "ドイツとかの一部んところではな、表示が義務付けられてんねん(Impressum)。" @@ -1206,6 +1209,7 @@ hemisphere: "住んでる地域" withSensitive: "センシティブなファイルを含むノートを表示" userSaysSomethingSensitive: "{name}のセンシティブなファイルを含む投稿" enableHorizontalSwipe: "スワイプしてタブを切り替える" +surrender: "やめとく" _bubbleGame: howToPlay: "遊び方" _howToPlay: @@ -2033,9 +2037,9 @@ _auth: _antennaSources: all: "みんなのノート" homeTimeline: "フォローしとるユーザーのノート" - users: "選らんだ一人か複数のユーザーのノート" + users: "選んだ一人か複数のユーザーのノート" userList: "選んだリストのユーザーのノート" - userBlacklist: "選んだ1人か複数のユーザーのノート" + userBlacklist: "選んだ一人か複数のユーザーを除いた全てのノート" _weekday: sunday: "日曜日" monday: "月曜日" @@ -2485,6 +2489,8 @@ _reversi: shareToTlTheGameWhenStart: "初めの時に対局をタイムラインに投稿するで" iStartedAGame: "対局し始めたで! #MisskeyReversi" opponentHasSettingsChanged: "相手が設定変えたで" + allowIrregularRules: "変則許可 (完全フリー)" + disallowIrregularRules: "変則なし" _offlineScreen: title: "オフライン - サーバーに接続できひんで" header: "サーバーに接続できへんわ" diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml index 1d6c6f7bbc..39492d902f 100644 --- a/locales/ko-GS.yml +++ b/locales/ko-GS.yml @@ -40,7 +40,7 @@ favorites: "질겨찾기" unfavorite: "질겨찾기서 어ᇝ애기" favorited: "질겨찾기에 담앗십니다." alreadyFavorited: "벌시로 질겨찾기에 담기 잇십니다." -cantFavorite: "질겨찾기에 몬 담았십니다." +cantFavorite: "질겨찾기에 몬 담앗십니다." pin: "프로필에 붙이기" unpin: "프로필서 띠기" copyContent: "내용 복사하기" @@ -124,6 +124,7 @@ reactions: "반엉" reactionSettingDescription2: "꺼시서 두고, 누질라서 뭉캐고, ‘+’럴 누질라서 옇십니다." rememberNoteVisibility: "공개 범위럴 기억하기" attachCancel: "붙임 빼기" +deleteFile: "파일 뭉캐기" markAsSensitive: "수ᇚ힘 설정" unmarkAsSensitive: "수ᇚ힘 무루기" enterFileName: "파일 이럼 서기" @@ -463,6 +464,8 @@ onlyOneFileCanBeAttached: "메시지엔 파일 하나까제밖에 몬 넣십니 invitations: "초대하기" invitationCode: "초대장" checking: "학인하고 잇십니다" +tooShort: "억수로 짜립니다" +tooLong: "억수로 집니다" passwordMatched: "맞십니다" passwordNotMatched: "안 맞십니다" signinFailed: "로그인 몬 했십니다. 고 이름이랑 비밀번호 제대로 썼는가 확인해 주이소." @@ -515,7 +518,7 @@ objectStoragePrefixDesc: "요 Prefix 디렉토리 안에다가 파일이 들어 objectStorageEndpoint: "Endpoint" objectStorageEndpointDesc: "AWS S3을 쓸라멘 요는 비워두고, 아이멘은 그 서비스 가이드에 맞게 endpoint를 넣어 주이소. '' 내지 ':'처럼 넣십니다." objectStorageRegion: "Region" -objectStorageRegionDesc: "'xx-east-1' 같은 region 이름을 옇어 주이소. 써먹을 서비스에 region 개념 같은 게 읎다! 카면은 대신에 'us-east-1'을 옇어 놓으이소. AWS 설정 파일이나 환경 변수를 갖다 끌어다 쓸 거면은 요는 비워 두이소." +objectStorageRegionDesc: "'xx-east-1' 같은 region 이름을 옇어 주이소. 만약에 내 서비스엔 region 같은 개념이 읎다, 카면은 대신에 'us-east-1'라고 해 두이소. AWS 설정 파일이나 환경 변수를 끌어다 쓰겠다믄 요는 비워 두이소." objectStorageUseSSL: "SSL 쓰기" objectStorageUseSSLDesc: "API 호출할 때 HTTPS 안 쓸거면은 꺼 두이소" objectStorageUseProxy: "연결에 프락시 사용" @@ -538,7 +541,7 @@ volume: "음량" masterVolume: "대빵 음량" notUseSound: "음소거하기" useSoundOnlyWhenActive: "Misskey가 활성화되어 있을 때만 소리 내기" -details: "좀 더" +details: "자세히" chooseEmoji: "이모지 선택" unableToProcess: "작업 다 몬 했십니다" recentUsed: "최근 쓴 놈" @@ -571,7 +574,11 @@ userSilenced: "요 게정은... 수ᇚ혀 있십니다." relays: "릴레이" addRelay: "릴레이 옇기" addedRelays: "옇은 릴레이" +deletedNote: "뭉캔 걸" enableInfiniteScroll: "알아서 더 보기" +useCw: "내용 수ᇚ후기" +description: "설멩" +describeFile: "캡션 옇기" author: "맨던 사람" manage: "간리" emailServer: "전자우펜 서버" @@ -600,6 +607,7 @@ renotesCount: "리노트한 수" renotedCount: "리노트덴 수" followingCount: "팔로우 수" followersCount: "팔로워 수" +noteFavoritesCount: "질겨찾기한 노트 수" clips: "클립 맨걸기" clearCache: "캐시 비우기" unlikeConfirm: "좋네예럴 무룹니꺼?" @@ -608,6 +616,7 @@ user: "사용자" administration: "간리" on: "킴" off: "껌" +hide: "수ᇚ후기" clickToFinishEmailVerification: "[{ok}]럴 누질라서 전자우펜 정멩얼 껕내이소." searchByGoogle: "찾기" tenMinutes: "십 분" @@ -626,9 +635,12 @@ role: "옉할" noRole: "옉할이 없십니다" thisPostMayBeAnnoyingCancel: "아이예" likeOnly: "좋네예마" +myClips: "내 클립" icon: "아바타" replies: "답하기" renotes: "리노트" +attach: "옇기" +surrender: "아이예" _initialAccountSetting: startTutorial: "길라잡이 하기" _initialTutorial: @@ -641,9 +653,52 @@ _initialTutorial: title: "길라잡이가 껕낫십니다!🎉" _achievements: _types: + _notes1: + description: "첫 노트럴 섯어예" + _notes10: + description: "노트럴 10번 섰어예" + _notes100: + description: "노트럴 100번 섰어예" + _notes500: + description: "노트럴 500번 섰어예" + _notes1000: + description: "노트럴 1,000번 섰어예" + _notes5000: + description: "노트럴 5,000번 섰어예" + _notes10000: + description: "노트럴 10,000번 섰어예" + _notes20000: + description: "노트럴 20,000번 섰어예" + _notes30000: + description: "노트럴 30,000번 섰어예" + _notes40000: + description: "노트럴 40,000번 섰어예" + _notes50000: + description: "노트럴 50,000번 섰어예" + _notes60000: + description: "노트럴 60,000번 섰어예" + _notes70000: + description: "노트럴 70,000번 섰어예" + _notes80000: + description: "노트럴 80,000번 섰어예" + _notes90000: + description: "노트럴 90,000번 섰어예" + _notes100000: + description: "노트럴 100,000번 섰어예" + _noteClipped1: + description: "첫 노트럴 클립햇어예" + _noteFavorited1: + description: "첫 노트럴 질겨찾기에 담앗어예" + _myNoteFavorited1: + description: "다런 사람이 내 노트럴 질겨찾기에 담앗십니다" + _iLoveMisskey: + description: "“I ❤ #Misskey”럴 섰어예" + _postedAt0min0sec: + description: "0분 0초에 노트를 섰어예" _tutorialCompleted: description: "길라잡이럴 껕냇십니다" _gallery: + my: "내 걸" liked: "좋네예한 걸" like: "좋네예!" unlike: "좋네예 무루기" @@ -654,7 +709,12 @@ _serverDisconnectedBehavior: reload: "알아서 새로곤침" _channel: removeBanner: "배너 뭉캐기" + usersCount: "{n}명 참여" + notesCount: "노트 {n}개" +_menuDisplay: + hide: "수ᇚ후기" _theme: + description: "설멩" keys: mention: "멘션" _sfx: @@ -663,6 +723,9 @@ _sfx: _2fa: step3Title: "학인 기호럴 서기" renewTOTPCancel: "뎃어예" +_permissions: + "read:favorites": "질겨찾기 보기" + "write:favorites": "질겨찾기 곤치기" _widgets: profile: "프로필" instanceInfo: "서버 정보" @@ -674,7 +737,10 @@ _widgets: _userList: chooseList: "리스트 개리기" _cw: + hide: "수ᇚ후기" show: "더 볼래예" + chars: "걸자 {count}개" + files: "파일 {count}개" _visibility: home: "덜머리" followers: "팔로워" @@ -682,6 +748,7 @@ _profile: name: "이럼" username: "사용자 이럼" _exportOrImport: + favoritedNotes: "질겨찾기한 노트" clips: "클립 맨걸기" followingList: "팔로잉" muteList: "수ᇚ후기" @@ -692,16 +759,20 @@ _charts: _timelines: home: "덜머리" _play: + my: "내 플레이" script: "스크립트" + summary: "설멩" _pages: like: "좋네예" unlike: "좋네예 무루기" + my: "내 페이지" blocks: image: "이미지" _note: id: "노트 아이디" _notification: youWereFollowed: "새 팔로워가 잇십니다" + newNote: "새 걸" _types: follow: "팔로잉" mention: "멘션" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index de4cb3395b..877ae6b217 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -279,7 +279,7 @@ uploadFromUrl: "URL 업로드" uploadFromUrlDescription: "업로드하려는 파일의 URL" uploadFromUrlRequested: "업로드를 요청했습니다" uploadFromUrlMayTakeTime: "업로드가 완료될 때까지 시간이 소요될 수 있습니다." -explore: "발견하기" +explore: "둘러보기" messageRead: "읽음" noMoreHistory: "이것보다 과거의 기록이 없습니다" startMessaging: "대화 시작하기" @@ -991,6 +991,7 @@ neverShow: "다시 보지 않기" remindMeLater: "나중에 알림" didYouLikeMisskey: "Misskey가 마음에 드시나요?" pleaseDonate: "Misskey는 {host} 서버의 무료 소프트웨어입니다. 앞으로도 개발을 이어 나가려면 후원이 절실히 필요합니다!" +correspondingSourceIsAvailable: "소스 코드는 {anchor}에서 받아보실 수 있습니다." roles: "역할" role: "역할" noRole: "역할이 없습니다" @@ -1022,7 +1023,7 @@ internalServerError: "내부 서버 오류" internalServerErrorDescription: "내부 서버에서 예기치 않은 오류가 발생했습니다." copyErrorInfo: "오류 정보 복사" joinThisServer: "이 서버에 가입" -exploreOtherServers: "다른 서버 둘러보기" +exploreOtherServers: "다른 서버 찾기" letsLookAtTimeline: "타임라인 구경하기" disableFederationConfirm: "정말로 연합을 끄시겠습니까?" disableFederationConfirmWarn: "연합을 끄더라도 게시물이 비공개로 전환되는 것은 아닙니다. 대부분의 경우 연합을 비활성화할 필요가 없습니다." @@ -1041,6 +1042,9 @@ resetPasswordConfirm: "비밀번호를 재설정하시겠습니까?" sensitiveWords: "민감한 단어" sensitiveWordsDescription: "설정한 단어가 포함된 노트의 공개 범위를 '홈'으로 강제합니다. 개행으로 구분하여 여러 개를 지정할 수 있습니다." sensitiveWordsDescription2: "공백으로 구분하면 AND 지정이 되며, 키워드를 슬래시로 둘러싸면 정규 표현식이 됩니다." +prohibitedWords: "금지 워드" +prohibitedWordsDescription: "설정된 워드가 포함되는 노트를 작성하려고 하면, 에러가 발생하도록 합니다. 줄바꿈으로 구분지어 복수 설정할 수 있습니다." +prohibitedWordsDescription2: "공백으로 구분하면 AND 지정이 되며, 키워드를 슬래시로 둘러싸면 정규 표현식이 됩니다." hiddenTags: "숨긴 해시태그" hiddenTagsDescription: "설정한 태그를 트렌드에 표시하지 않도록 합니다. 줄 바꿈으로 하나씩 나눠서 설정할 수 있습니다." notesSearchNotAvailable: "노트 검색을 이용하실 수 없습니다." @@ -1164,6 +1168,13 @@ hideRepliesToOthersInTimelineAll: "타임라인에 현재 팔로우 중인 사 confirmShowRepliesAll: "이 조작은 되돌릴 수 없습니다. 정말로 타임라인에 현재 팔로우 중인 사람 전원의 답글이 나오게 하시겠습니까?" confirmHideRepliesAll: "이 조작은 되돌릴 수 없습니다. 정말로 타임라인에 현재 팔로우 중인 사람 전원의 답글이 나오지 않게 하시겠습니까?" externalServices: "외부 서비스" +sourceCode: "소스 코드" +sourceCodeIsNotYetProvided: "소스 코드를 아직 제공하지 않습니다. 이 문제를 해결하려면 관리자에게 문의해 주세요." +repositoryUrl: "저장소 URL" +repositoryUrlDescription: "소스 코드를 공개한 저장소가 있는 경우, 그 URL을 적습니다. Misskey를 원본 그대로 (소스 코드를 어떤 식으로도 변경하지 않고) 쓰고 있는 경우 https://github.com/misskey-dev/misskey 라고 적습니다." +repositoryUrlOrTarballRequired: "저장소를 공개하지 않은 경우 대신 tarball을 제공할 필요가 있습니다. 세부사항은 .config/example.yml을 참조해 주세요." +feedback: "피드백" +feedbackUrl: "피드백 URL" impressum: "운영자 정보" impressumUrl: "운영자 정보 URL" impressumDescription: "독일 등의 일부 나라와 지역에서는 꼭 표시해야 합니다(Impressum)." @@ -1206,6 +1217,7 @@ hemisphere: "거주 지역" withSensitive: "민감한 파일이 포함된 노트 보기" userSaysSomethingSensitive: "{name}의 민감한 파일이 포함된 게시물" enableHorizontalSwipe: "스와이프하여 탭 전환" +surrender: "그만두기" _bubbleGame: howToPlay: "설명" _howToPlay: @@ -1752,6 +1764,8 @@ _aboutMisskey: contributors: "주요 기여자" allContributors: "모든 기여자" source: "소스 코드" + original: "원본" + thisIsModifiedVersion: "{name}에서는 원본 미스키를 수정한 버전을 사용하고 있습니다." translation: "Misskey를 번역하기" donate: "Misskey에 기부하기" morePatrons: "이 외에도 다른 많은 분들이 도움을 주시고 계십니다. 감사합니다🥰" @@ -1797,7 +1811,7 @@ _instanceMute: title: "지정한 서버의 노트를 숨깁니다." heading: "뮤트할 서버" _theme: - explore: "테마 찾아보기" + explore: "테마 둘러보기" install: "테마 설치" manage: "테마 관리" code: "테마 코드" @@ -2022,7 +2036,7 @@ _permissions: "write:report-abuse": "위반 내용 신고하기" _auth: shareAccessTitle: "어플리케이션의 접근 허가" - shareAccess: "\"{name}\" 이 계정에 접근하는 것을 허용하시겠습니까?" + shareAccess: "‘{name}’에서 계정에 접근하는 것을 허용하시겠습니까?" shareAccessAsk: "이 애플리케이션이 계정에 접근하는 것을 허용하시겠습니까?" permission: "{name}에서 다음 권한을 요청하였습니다" permissionAsk: "이 앱은 다음의 권한을 요청합니다" @@ -2367,6 +2381,7 @@ _moderationLogTypes: resetPassword: "비밀번호 재설정" suspendRemoteInstance: "리모트 서버를 정지" unsuspendRemoteInstance: "리모트 서버의 정지를 해제" + updateRemoteInstanceNote: "리모트 서버의 조정 기록 갱신" markSensitiveDriveFile: "파일에 열람주의를 설정" unmarkSensitiveDriveFile: "파일에 열람주의를 해제" resolveAbuseReport: "신고 처리" @@ -2482,6 +2497,11 @@ _reversi: freeMatch: "프리매치" lookingForPlayer: "상대를 찾고 있습니다" gameCanceled: "대국이 취소되었습니다" + shareToTlTheGameWhenStart: "대국 시작 시 타임라인에 대국을 게시" + iStartedAGame: "대국이 시작되었습니다! #MisskeyReversi" + opponentHasSettingsChanged: "상대방이 설정을 변경했습니다" + allowIrregularRules: "규칙변경 허가 (완전 자유)" + disallowIrregularRules: "규칙변경 없음" _offlineScreen: title: "오프라인 - 서버에 접속할 수 없습니다" header: "서버에 접속할 수 없습니다" diff --git a/locales/no-NO.yml b/locales/no-NO.yml index 85ccd62566..098faa8add 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -463,6 +463,7 @@ options: "Alternativ" icon: "Avatar" replies: "Svar" renotes: "Renote" +surrender: "Avbryt" _initialAccountSetting: theseSettingsCanEditLater: "Du kan endre disse innstillingene senere." _achievements: diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 9de413eb3b..99eb1f3028 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -871,6 +871,7 @@ youFollowing: "Śledzeni" icon: "Awatar" replies: "Odpowiedz" renotes: "Udostępnij" +sourceCode: "Kod źródłowy" flip: "Odwróć" _role: priority: "Priorytet" diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index bf8a8ca38b..f62557fb23 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -1011,6 +1011,7 @@ renotes: "Repostar" keepScreenOn: "Manter a tela do dispositivo sempre ligada" flip: "Inversão" lastNDays: "Últimos {n} dias" +surrender: "Cancelar" _initialAccountSetting: followUsers: "Siga usuários que lhe interessam para criar a sua linha do tempo." _serverSettings: diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 60682fe961..d666b69490 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -1015,6 +1015,7 @@ resetPasswordConfirm: "Сбросить пароль?" sensitiveWords: "Чувствительные слова" sensitiveWordsDescription: "Установите общедоступный диапазон заметки, содержащей заданное слово, на домашний. Можно сделать несколько настроек, разделив их переносами строк." sensitiveWordsDescription2: "Разделение пробелом создаёт спецификацию AND, а разделение косой чертой создаёт регулярное выражение." +prohibitedWordsDescription2: "Разделение пробелом создаёт спецификацию AND, а разделение косой чертой создаёт регулярное выражение." notesSearchNotAvailable: "Поиск заметок недоступен" license: "Лицензия" unfavoriteConfirm: "Удалить избранное?" @@ -1081,8 +1082,10 @@ icon: "Аватар" replies: "Ответы" renotes: "Репост" loadReplies: "Показать ответы" +sourceCode: "Исходный код" flip: "Переворот" lastNDays: "Последние {n} сут" +surrender: "Этот пост не может быть отменен." _initialAccountSetting: accountCreated: "Аккаунт успешно создан!" letsStartAccountSetup: "Давайте настроим вашу учётную запись." diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index 7856809bf8..251496b10b 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -919,6 +919,7 @@ youFollowing: "Sledované" icon: "Avatar" replies: "Odpovedať" renotes: "Preposlať" +sourceCode: "Zdrojový kód" flip: "Preklopiť" lastNDays: "Posledných {n} dní" _role: diff --git a/locales/th-TH.yml b/locales/th-TH.yml index ed776e5ec7..c0e79d5e16 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -8,12 +8,12 @@ search: "ค้นหา" notifications: "การเเจ้งเตือน" username: "ชื่อผู้ใช้" password: "รหัสผ่าน" -forgotPassword: "ลืมรหัสผ่านใช่ไหม" +forgotPassword: "ลืมรหัสผ่าน" fetchingAsApObject: "กำลังดึงข้อมูลจากสหพันธ์..." ok: "ตกลง" gotIt: "เข้าใจแล้ว !" cancel: "ยกเลิก" -noThankYou: "ไม่เป็นไร" +noThankYou: "ไม่เอาดีกว่า" enterUsername: "กรอกชื่อผู้ใช้" renotedBy: "รีโน้ตโดย {user}" noNotes: "ไม่มีโน้ต" @@ -31,16 +31,16 @@ login: "เข้าสู่ระบบ" loggingIn: "กำลังเข้าสู่ระบบ" logout: "ออกจากระบบ" signup: "สร้างบัญชีผู้ใช้" -uploading: "กำลังอัพโหลด..." +uploading: "กำลังอัปโหลด" save: "บันทึก" users: "ผู้ใช้งาน" addUser: "เพิ่มผู้ใช้" favorite: "รายการโปรด" favorites: "รายการโปรด" unfavorite: "ลบออกจากรายการโปรด" -favorited: "เพิ่มแล้วในรายการโปรด" -alreadyFavorited: "เพิ่มในรายการโปรดอยู่แล้ว" -cantFavorite: "ไม่สามารถเพิ่มในรายการโปรดได้" +favorited: "เพิ่มลงรายการโปรดแล้ว" +alreadyFavorited: "เพิ่มลงรายการโปรดอยู่แล้ว" +cantFavorite: "ไม่สามารถเพิ่มลงรายการโปรดได้" pin: "ปักหมุด" unpin: "เลิกปักหมุด" copyContent: "คัดลอกเนื้อหา" @@ -65,18 +65,18 @@ loadMore: "แสดงเพิ่มเติม" showMore: "แสดงเพิ่มเติม" showLess: "ปิด" youGotNewFollower: "ได้ติดตามคุณ" -receiveFollowRequest: "คำขอผู้ติดตามที่ได้รับ" -followRequestAccepted: "อนุมัติการติดตามแล้ว" +receiveFollowRequest: "มีคำขอติดตามส่งมาหา" +followRequestAccepted: "การติดตามได้รับการอนุมัติแล้ว" mention: "กล่าวถึง" mentions: "พูดถึง" -directNotes: "ไดเร็คโน้ต" +directNotes: "โพสต์แบบไดเร็กต์" importAndExport: "นำเข้า / ส่งออก" import: "นำเข้า" export: "ส่งออก" files: "ไฟล์" download: "ดาวน์โหลด" -driveFileDeleteConfirm: "ต้องการลบไฟล์ “{name}” ใช่หรือไม่? โน้ตที่แนบมากับไฟล์นี้ก็จะถูกลบไปด้วย" -unfollowConfirm: "ต้องการเลิกติดตาม {name}?" +driveFileDeleteConfirm: "ต้องการลบไฟล์ “{name}” ใช่ไหม? โน้ตที่แนบมากับไฟล์นี้ก็จะถูกลบไปด้วย" +unfollowConfirm: "ต้องการเลิกติดตาม {name} ใช่ไหม?" exportRequested: "คุณได้ร้องขอการส่งออก อาจใช้เวลาสักครู่ และจะถูกเพิ่มในไดรฟ์ของคุณเมื่อเสร็จสิ้นแล้ว" importRequested: "คุณได้ร้องขอการนำเข้า การดำเนินการนี้อาจใช้เวลาสักครู่" lists: "รายชื่อ" @@ -128,9 +128,9 @@ emojiPickerDisplay: "แสดงตัวจิ้มเอโมจิ" overwriteFromPinnedEmojisForReaction: "เขียนทับการตั้งค่ารีแอคชั่น" overwriteFromPinnedEmojis: "เขียนทับการตั้งค่าทั่วไป" reactionSettingDescription2: "ลากเพื่อจัดลำดับใหม่ คลิกที่เอโมจินั้นเพื่อลบ กด “+” เพื่อเพิ่ม" -rememberNoteVisibility: "จดจำการตั้งค่าการมองเห็นตัวโน้ต" -attachCancel: "ลบไฟล์ออกที่แนบมา" -deleteFile: "ลบไฟล์ออกแล้ว" +rememberNoteVisibility: "จำการตั้งค่าการมองเห็นโน้ต" +attachCancel: "ยกเลิกแนบไฟล์" +deleteFile: "ลบไฟล์ออก" markAsSensitive: "ทำเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน" unmarkAsSensitive: "ยกเลิกทำเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน" enterFileName: "พิมพ์ชื่อไฟล์" @@ -138,14 +138,14 @@ mute: "ปิดเสียง" unmute: "ยกเลิกการปิดเสียง" renoteMute: "ปิดเสียงรีโน้ต" renoteUnmute: "เปิดเสียง รีโน้ต" -block: "บล็อค" -unblock: "เลิกปิดกั้น" -suspend: "ถูกระงับ" -unsuspend: "ยกเลิกระงับ" -blockConfirm: "ต้องการบล็อกบัญชีนี้?" -unblockConfirm: "ต้องการปลดบล็อคบัญชีนี้?" -suspendConfirm: "ต้องการระงับบัญชีนี้?" -unsuspendConfirm: "ต้องการยกเลิกการระงับบัญชีนี้?" +block: "บล็อก" +unblock: "เลิกบล็อก" +suspend: "ระงับ" +unsuspend: "เลิกระงับ" +blockConfirm: "ต้องการบล็อกบัญชีนี้ใช่ไหม?" +unblockConfirm: "ต้องการเลิกบล็อกบัญชีนี้ใช่ไหม?" +suspendConfirm: "ต้องการระงับบัญชีนี้ใช่ไหม?" +unsuspendConfirm: "ต้องการยกเลิกการระงับบัญชีนี้ใช่ไหม?" selectList: "เลือกรายชื่อ" editList: "แก้ไขรายชื่อ" selectChannel: "เลือกช่อง" @@ -162,13 +162,13 @@ emojiUrl: "URL ของเอโมจิ" addEmoji: "แทรกเอโมจิ" settingGuide: "การตั้งค่าที่แนะนำ" cacheRemoteFiles: "แคชไฟล์ระยะไกล" -cacheRemoteFilesDescription: "เมื่อปิดใช้งานการตั้งค่านี้ ไฟล์ระยะไกลนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกล แต่กรณีการปิดใช้งานนี้จะช่วยลดปริมาณการใช้พื้นที่จัดเก็บข้อมูล แต่เพิ่มปริมาณการใช้งาน เพราะเนื่องจากจะไม่มีการสร้างภาพขนาดย่อ" +cacheRemoteFilesDescription: "หากเปิดใช้งาน ไฟล์ระยะไกลจะถูกแคชไว้ ทำให้แสดงภาพเร็วขึ้น แต่ก็ใช้พื้นที่เก็บข้อมูลของเซิร์ฟเวอร์มากขึ้นเช่นกัน สำหรับขีดจำกัดที่ผู้ใช้ระยะไกลถูกแคชไว้จะขึ้นอยู่กับความจุไดรฟ์ตามบทบาทของเขา เมื่อเกินแล้วไฟล์เก่าจะถูกลบออกและเก็บเป็นลิงก์แทน หากปิดใช้งาน ไฟล์ระยะไกลจะถูกเก็บเป็นลิงก์ตั้งแต่ต้น เราแนะนำให้ตั้งค่า proxyRemoteFiles ใน default.yml เป็น true เพื่อสร้างธัมบ์เนลและปกป้องความเป็นส่วนตัวของผู้ใช้" youCanCleanRemoteFilesCache: "คุณสามารถล้างแคชได้โดยคลิกที่ปุ่ม 🗑️ ในมุมมองการจัดการไฟล์" -cacheRemoteSensitiveFiles: "แคชไฟล์ระยะไกลที่มีเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน" +cacheRemoteSensitiveFiles: "แคชไฟล์ระยะไกลที่มีเนื้อหาละเอียดอ่อน" cacheRemoteSensitiveFilesDescription: "เมื่อปิดการใช้งานการตั้งค่านี้ ไฟล์ระยะไกลที่มีเครื่องหมายว่ามีเนื้อหาละเอียดอ่อนนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกลโดยที่ไม่มีการแคช" -flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอท" +flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอต" flagAsBotDescription: "การเปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยนักเขียนโปรแกรม หรือ ถ้าหากเปิดใช้งาน มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่นๆ และเพื่อป้องกันการโต้ตอบแบบไม่มีที่สิ้นสุดกับบอทตัวอื่นๆ และยังสามารถปรับเปลี่ยนระบบภายในของ Misskey เพื่อปฏิบัติต่อบัญชีนี้เป็นบอท" -flagAsCat: "เมี้ยววววววว!!!!!!!!!!! (ทำเครื่องหมายว่าบัญชีนี้เป็นแมว)" +flagAsCat: "เมี้ยววววววววววววววว!!!!!!!!!!!" flagAsCatDescription: "เหมียวเหมียวเมี้ยว??" flagShowTimelineReplies: "แสดงตอบกลับ ในไทม์ไลน์" flagShowTimelineRepliesDescription: "แสดงการตอบกลับของผู้ใช้งานไปยังโน้ตของผู้ใช้งานรายอื่นๆในไทม์ไลน์หากได้เปิดเอาไว้" @@ -180,7 +180,7 @@ showOnRemote: "ดูบนอินสแตนซ์ระยะไกล" general: "ทั่วไป" wallpaper: "ภาพพื้นหลัง" setWallpaper: "ตั้งค่าภาพพื้นหลัง" -removeWallpaper: "น้ำภาพพื้นหลังออก" +removeWallpaper: "นำภาพพื้นหลังออก" searchWith: "ค้นหา: {q}" youHaveNoLists: "คุณไม่มีรายชื่อใดๆ " followConfirm: "ต้องการติดตาม {name} ใช่ไหม?" @@ -189,11 +189,11 @@ proxyAccountDescription: "บัญชีพร็อกซี่ คือ บ host: "โฮสต์" selectUser: "เลือกผู้ใช้งาน" recipient: "ผู้รับ" -annotation: "ความคิดเห็น" +annotation: "หมายเหตุประกอบ" federation: "สหพันธ์" instances: "อินสแตนซ์" -registeredAt: "จดทะเบียนที่" -latestRequestReceivedAt: "ได้รับคำขอล่าสุดไปแล้ว" +registeredAt: "วันที่ลงทะเบียน" +latestRequestReceivedAt: "คำขอล่าสุดที่ได้รับ" latestStatus: "สถานะล่าสุด" storageUsage: "พื้นที่จัดเก็บข้อมูลที่ใช้ไป" charts: "โดดเด่น" @@ -215,10 +215,10 @@ disk: "ดิสก์" instanceInfo: "ข้อมูลอินสแตนซ์" statistics: "สถิติการใช้งาน" clearQueue: "ล้างคิว" -clearQueueConfirmTitle: "คุณแน่ใจแล้วหรอว่าต้องการที่จะล้างคิว?" +clearQueueConfirmTitle: "ต้องการล้างคิวใช่ไหม?" clearQueueConfirmText: "โพสต์ที่ยังค้างในคิวจะไม่ถูกจัดส่งอีกต่อไป โดยปกติแล้วการดำเนินการนี้ไม่จำเป็น" clearCachedFiles: "ล้างแคช" -clearCachedFilesConfirm: "ต้องการลบไฟล์ระยะไกลที่แคชไว้ทั้งหมด?" +clearCachedFilesConfirm: "ต้องการลบไฟล์ระยะไกลที่แคชไว้ทั้งหมดใช่ไหม?" blockedInstances: "อินสแตนซ์ที่ถูกบล็อก" blockedInstancesDescription: "ระบุชื่อโฮสต์ของอินสแตนซ์ที่คุณต้องการบล็อก อินสแตนซ์ที่อยู่ในรายการนั้นจะไม่สามารถพูดคุยกับอินสแตนซ์นี้ได้อีกต่อไป" silencedInstances: "ปิดปากอินสแตนซ์นี้แล้ว" @@ -228,7 +228,7 @@ mutedUsers: "ผู้ใช้ที่ถูกปิดเสียง" blockedUsers: "ผู้ใช้ที่ถูกบล็อก" noUsers: "ไม่พบผู้ใช้งาน" editProfile: "แก้ไขโปรไฟล์" -noteDeleteConfirm: "ต้องการลบโน้ตนี้?" +noteDeleteConfirm: "ต้องการลบโน้ตนี้ใช่ไหม?" pinLimitExceeded: "คุณไม่สามารถปักหมุดโน้ตเพิ่มเติมใดๆได้อีก" intro: "การติดตั้ง Misskey เสร็จสิ้นแล้วนะ! โปรดสร้างผู้ใช้งานที่เป็นผู้ดูแลระบบ" done: "เสร็จสิ้น" @@ -237,7 +237,7 @@ preview: "แสดงตัวอย่าง" default: "ค่าเริ่มต้น" defaultValueIs: "ค่าเริ่มต้น: {value}" noCustomEmojis: "ไม่มีเอโมจิ" -noJobs: "ไม่มีชิ้นงาน" +noJobs: "ไม่มีงาน" federating: "สหพันธ์" blocked: "ถูกบล็อก" suspended: "ถูกระงับ" @@ -261,11 +261,11 @@ usernameOrUserId: "ชื่อผู้ใช้หรือรหัสผู noSuchUser: "ไม่พบผู้ใช้" lookup: "การค้นหา" announcements: "ประกาศ" -imageUrl: "url รูปภาพ" +imageUrl: "URL รูปภาพ" remove: "ลบ" removed: "ถูกลบไปแล้ว" -removeAreYouSure: "ต้องการที่จะลบ “{x}” ออก?" -deleteAreYouSure: "ต้องการลบ {x} หรือไม่คะ?" +removeAreYouSure: "ต้องการลบ “{x}” ใช่ไหม?" +deleteAreYouSure: "ต้องการลบ “{x}” ใช่ไหม?" resetAreYouSure: "รีเซ็ตเลยไหม?" areYouSure: "แน่ใจแล้วใช่ไหมคะ?" saved: "บันทึกแล้ว" @@ -275,7 +275,7 @@ keepOriginalUploading: "เก็บภาพต้นฉบับ" keepOriginalUploadingDescription: "เก็บภาพต้นฉบับไว้เมื่ออัปโหลดภาพ หากปิด รูปภาพสำหรับการเผยแพร่ทางเว็บจะถูกสร้างขึ้นในเบราว์เซอร์เมื่อทำการอัปโหลด" fromDrive: "จากไดรฟ์" fromUrl: "จาก URL" -uploadFromUrl: "อัพโหลดจาก URL" +uploadFromUrl: "อัปโหลดจาก URL" uploadFromUrlDescription: "URL ของไฟล์ที่คุณต้องการอัปโหลด" uploadFromUrlRequested: "ร้องขอการอัปโหลดแล้ว" uploadFromUrlMayTakeTime: "การอัปโหลดอาจใช้เวลาสักครู่จึงจะเสร็จสมบูรณ์" @@ -289,7 +289,7 @@ agree: "ยอมรับ" agreeBelow: "ฉันยอมรับถึงด้านล่าง" basicNotesBeforeCreateAccount: "หมายเหตุสำคัญ" termsOfService: "เงื่อนไขการให้บริการ" -start: "เริ่มต้น​ใช้งาน​" +start: "เริ่ม" home: "หน้าแรก" remoteUserCaution: "ข้อมูลอาจไม่สมบูรณ์เนื่องจากผู้ใช้รายนี้มาจากอินสแตนซ์ระยะไกล" activity: "กิจกรรม" @@ -333,11 +333,11 @@ rename: "เปลี่ยนชื่อ" avatar: "ไอคอน" banner: "แบนเนอร์" displayOfSensitiveMedia: "แสดงสื่อที่มีเนื้อหาละเอียดอ่อน" -whenServerDisconnected: "สูญเสียการเชื่อมต่อกับเซิร์ฟเวอร์" -disconnectedFromServer: "ถูกตัดการเชื่อมต่อออกจากเซิร์ฟเวอร์" +whenServerDisconnected: "เมื่อสูญเสียการเชื่อมต่อกับเซิร์ฟเวอร์" +disconnectedFromServer: "การเชื่อมต่อเซิร์ฟเวอร์ถูกตัด" reload: "รีโหลด" doNothing: "เมิน" -reloadConfirm: "นายต้องการรีเฟรชไทม์ไลน์หรือป่าว?" +reloadConfirm: "รีโหลดเลยไหม?" watch: "ดู" unwatch: "หยุดดู" accept: "ยอมรับ" @@ -347,7 +347,7 @@ instanceName: "ชื่ออินสแตนซ์" instanceDescription: "คำอธิบายอินสแตนซ์" maintainerName: "ผู้ดูแล" maintainerEmail: "อีเมลผู้ดูแลระบบ" -tosUrl: "เงื่อนไขการให้บริการ URL" +tosUrl: "URL เงื่อนไขการให้บริการ" thisYear: "ปีนี้" thisMonth: "เดือนนี้" today: "วันนี้" @@ -370,7 +370,7 @@ inMb: "เป็นเมกะไบต์" bannerUrl: "URL รูปภาพแบนเนอร์" backgroundImageUrl: "URL ภาพพื้นหลัง" basicInfo: "ข้อมูลเบื้องต้น" -pinnedUsers: "ผู้ใช้งานที่ได้รับการปักหมุด" +pinnedUsers: "ผู้ใช้ที่ถูกปักหมุด" pinnedUsersDescription: "ป้อนชื่อผู้ใช้ที่คุณต้องการปักหมุดในหน้า “ค้นพบ” ฯลฯ คั่นด้วยการขึ้นบรรทัดใหม่" pinnedPages: "หน้าเพจที่ปักหมุด" pinnedPagesDescription: "ป้อนเส้นทางของหน้าเพจที่คุณต้องการปักหมุดไว้ที่หน้าแรกของอินสแตนซ์นี้ คั่นด้วยขึ้นบรรทัดใหม่" @@ -409,16 +409,16 @@ caseSensitive: "อักษรพิมพ์ใหญ่-พิมพ์เล withReplies: "รวมตอบกลับ" connectedTo: "บัญชีดังต่อไปนี้มีการเชื่อมต่อกัน" notesAndReplies: "โพสต์และการตอบกลับ" -withFiles: "รวบรวมไฟล์" +withFiles: "มีไฟล์" silence: "ถูกปิดปาก" -silenceConfirm: "ต้องการที่จะ ปิดปาก ผู้ใช้รายนี้?" +silenceConfirm: "ต้องการปิดปากผู้ใช้รายนี้ใช่ไหม?" unsilence: "ยกเลิกการปิดปาก" -unsilenceConfirm: "ต้องการยกเลิกปิดปากผู้ใช้รายนี้?" +unsilenceConfirm: "ต้องการเลิกปิดปากผู้ใช้รายนี้ใช่ไหม?" popularUsers: "ผู้ใช้ที่เป็นที่นิยม" recentlyUpdatedUsers: "ผู้ใช้ที่เพิ่งใช้งานล่าสุด" recentlyRegisteredUsers: "ผู้ใช้ที่เข้าร่วมใหม่" recentlyDiscoveredUsers: "ผู้ใช้ที่เพิ่งค้นพบใหม่" -exploreUsersCount: "มีผู้ใช้ {จำนวน} ราย" +exploreUsersCount: "มีผู้ใช้ {count} ราย" exploreFediverse: "สำรวจสหพันธ์" popularTags: "แท็กยอดนิยม" userList: "ลิสต์" @@ -435,7 +435,7 @@ moderation: "การกลั่นกรอง" moderationNote: "โน้ตการกลั่นกรอง" addModerationNote: "เพิ่มโน้ตการกลั่นกรอง" moderationLogs: "ปูมการแก้ไข" -nUsersMentioned: "กล่าวถึงโดยผู้ใช้ {n} รายนี้" +nUsersMentioned: "กล่าวถึงโดยผู้ใช้ {n} ราย" securityKeyAndPasskey: "ความปลอดภัยและรหัสผ่าน" securityKey: "กุญแจความปลอดภัย" lastUsed: "ใช้ล่าสุด" @@ -449,7 +449,7 @@ reduceUiAnimation: "ลดภาพเคลื่อนไหว UI" share: "แบ่งปัน" notFound: "ไม่พบหน้าที่ต้องการ" notFoundDescription: "ไม่พบหน้าตาม URL ที่ระบุ" -uploadFolder: "โฟลเดอร์เริ่มต้นสำหรับอัพโหลด" +uploadFolder: "โฟลเดอร์เริ่มต้นสำหรับอัปโหลด" markAsReadAllNotifications: "ทำเครื่องหมายการแจ้งเตือนทั้งหมดว่าอ่านแล้ว" markAsReadAllUnreadNotes: "ทำเครื่องหมายโน้ตทั้งหมดว่าอ่านแล้ว" markAsReadAllTalkMessages: "ทำเครื่องหมายข้อความทั้งหมดว่าอ่านแล้ว" @@ -464,7 +464,7 @@ text: "ข้อความ" enable: "เปิดใช้งาน" next: "ถัด​ไป" retype: "พิมพ์รหัสอีกครั้ง" -noteOf: "โน้ต โดย {user}" +noteOf: "โน้ตของ {user}" quoteAttached: "อ้างอิง" quoteQuestion: "ต้องการที่จะแนบมันเพื่ออ้างอิงใช่ไหม?" noMessagesYet: "ยังไม่มีข้อความ" @@ -472,7 +472,7 @@ newMessageExists: "คุณมีข้อความใหม่" onlyOneFileCanBeAttached: "สามารถแนบไฟล์ได้เพียงไฟล์เดียวต่อ 1 ข้อความ" signinRequired: "กรุณาลงทะเบียนหรือลงชื่อเข้าใช้ก่อนดำเนินการต่อ" invitations: "คำเชิญ" -invitationCode: "รหัสคำเชิญ" +invitationCode: "รหัสเชิญ" checking: "Checking" available: "พร้อมใช้งาน" unavailable: "ไม่พร้อมใช้" @@ -557,7 +557,7 @@ popout: "ป๊อปเอาต์" volume: "ระดับเสียง" masterVolume: "ระดับเสียงหลัก" notUseSound: "ไม่ใช้เสียง" -useSoundOnlyWhenActive: "มีเสียงออกเฉพาะเมื่อ Misskey ทำงานอยู่" +useSoundOnlyWhenActive: "มีเสียงออกเฉพาะตอนกำลังใช้ Misskey อยู่เท่านั้น" details: "รายละเอียด" chooseEmoji: "เลือกเอโมจิ" unableToProcess: "ไม่สามารถดำเนินการให้เสร็จสิ้นได้" @@ -570,8 +570,8 @@ installedDate: "วันที่ติดตั้ง" lastUsedDate: "ใช้งานครั้งล่าสุด" state: "สถานะ" sort: "เรียงลำดับ" -ascendingOrder: "เรียงจากน้อยไปมาก" -descendingOrder: "เรียงจากมากไปน้อย" +ascendingOrder: "เรียงลำดับขึ้น" +descendingOrder: "เรียงลำดับลง" scratchpad: "Scratchpad" scratchpadDescription: "Scratchpad เป็นการจัดเตรียมสภาพแวดล้อมสำหรับการทดลอง AiScript แต่คุณสามารถเขียน ดำเนินการ และตรวจสอบผลลัพธ์ของการโต้ตอบกับ Misskey มันได้ด้วยนะ" output: "เอาท์พุต" @@ -579,15 +579,15 @@ script: "สคริปต์" disablePagesScript: "ปิดการใช้งาน AiScript บนเพจ" updateRemoteUser: "อัปเดตข้อมูลผู้ใช้งานระยะไกล" unsetUserAvatar: "เลิกตั้งอวตาร" -unsetUserAvatarConfirm: "ต้องการเลิกตั้งอวตาร?" +unsetUserAvatarConfirm: "ต้องการเลิกตั้งอวตารใข่ไหม?" unsetUserBanner: "เลิกตั้งแบนเนอร์" unsetUserBannerConfirm: "ต้องการเลิกตั้งแบนเนอร์?" deleteAllFiles: "ลบไฟล์ทั้งหมด" -deleteAllFilesConfirm: "ต้องการลบไฟล์ทั้งหมดหรือไม่?" +deleteAllFilesConfirm: "ต้องการลบไฟล์ทั้งหมดใช่ไหม?" removeAllFollowing: "เลิกติดตามผู้ใช้ที่ติดตามทั้งหมด" removeAllFollowingDescription: "เลิกติดตามทั้งหมดจาก {host} โปรดเรียกใช้สิ่งนี้เมื่ออินสแตนซ์ดังกล่าวได้สูญหายตายจากไปแล้ว" userSuspended: "ผู้ใช้รายนี้ถูกระงับการใช้งาน" -userSilenced: "ผู้ใช้รายนี้กำลังถูกปิดกั้น" +userSilenced: "ผู้ใช้รายนี้ถูกปิดปากอยู่" yourAccountSuspendedTitle: "บัญชีนี้นั้นถูกระงับ" yourAccountSuspendedDescription: "บัญชีนี้ถูกระงับ เนื่องจากละเมิดข้อกำหนดในการให้บริการของเซิร์ฟเวอร์หรืออาจจะละเมิดหลักเกณฑ์ชุมชน หรือ อาจจะโดนร้องเรียนเรื่องการละเมิดลิขสิทธิ์และอื่นๆอย่างต่อเนื่องซ้ำๆ หากคุณคิดว่าไม่ได้ทำผิดจริงๆหรือตัดสินผิดพลาด ได้โปรดกรุณาติดต่อผู้ดูแลระบบหากคุณต้องการทราบเหตุผลโดยละเอียดเพิ่มเติม และขอความกรุณาอย่าสร้างบัญชีใหม่" tokenRevoked: "โทเค็นไม่ถูกต้อง" @@ -600,7 +600,7 @@ addItem: "เพิ่มรายการ" rearrange: "จัดใหม่" relays: "รีเลย์" addRelay: "เพิ่มรีเลย์" -inboxUrl: "อินบ็อกซ์ URL" +inboxUrl: "URL ของอินบ็อกซ์" addedRelays: "เพิ่มรีเลย์แล้ว" serviceworkerInfo: "ต้องเปิดใช้งานสำหรับการแจ้งเตือนแบบพุช" deletedNote: "โน้ตที่ถูกลบ" @@ -617,7 +617,7 @@ description: "รายละเอียด" describeFile: "เพิ่มแคปชั่น" enterFileDescription: "ใส่แคปชั่น" author: "ผู้เขียน" -leaveConfirm: "คุณมีการเปลี่ยนแปลงที่ไม่ได้บันทึกนะ นายต้องการทิ้งการเปลี่ยนแปลงเหล่านั้นหรอ?" +leaveConfirm: "มีการเปลี่ยนแปลงที่ยังไม่ได้บันทึก ต้องการละทิ้งมันใช่ไหม?" manage: "การจัดการ" plugins: "ปลั๊กอิน" preferencesBackups: "ตั้งค่าการสำรองข้อมูล" @@ -664,7 +664,7 @@ display: "แสดงผล" copy: "คัดลอก" metrics: "เมตริก" overview: "ภาพรวม" -logs: "บันทึกข้อมูลระบบ" +logs: "ปูม" delayed: "ดีเลย์" database: "ฐานข้อมูล" channel: "ช่อง" @@ -672,26 +672,26 @@ create: "สร้าง" notificationSetting: "ตั้งค่าการแจ้งเตือน" notificationSettingDesc: "เลือกประเภทการแจ้งเตือนที่ต้องการจะแสดง" useGlobalSetting: "ใช้การตั้งค่าส่วนกลาง" -useGlobalSettingDesc: "หากเปิดไว้ ระบบจะใช้การตั้งค่าการแจ้งเตือนของบัญชีของคุณ หากปิดอยู่ สามารถทำการกำหนดค่าแต่ละรายการได้นะ" +useGlobalSettingDesc: "เมื่อเปิดใช้งาน ใช้การตั้งค่าการแจ้งเตือนจากบัญชีคุณ เมื่อปิดใช้งาน สามารถตั้งค่าได้อย่างอิสระ" other: "อื่น ๆ" regenerateLoginToken: "สร้างโทเค็นการเข้าสู่ระบบอีกครั้ง" regenerateLoginTokenDescription: "สร้างโทเค็นใหม่ที่ใช้ภายในระหว่างการเข้าสู่ระบบ โดยตามหลักปกติแล้วการดำเนินการนี้ไม่จำเป็น หากสร้างใหม่ อุปกรณ์ทั้งหมดจะถูกออกจากระบบนะ" -theKeywordWhenSearchingForCustomEmoji: "คีย์เวิร์ดสำหรับใช้ค้นหาอีโมจิที่กำหนดเอง" +theKeywordWhenSearchingForCustomEmoji: "คีย์เวิร์ดสำหรับใช้ค้นหาเอโมจิที่กำหนดเอง" setMultipleBySeparatingWithSpace: "คั่นหลายรายการด้วยช่องว่าง" -fileIdOrUrl: "ไฟล์ ID หรือ URL" +fileIdOrUrl: "ID ของไฟล์ หรือ URL" behavior: "พฤติกรรม" sample: "ตัวอย่าง" abuseReports: "รายงาน" reportAbuse: "รายงาน" reportAbuseRenote: "รายงานรีโน้ต" -reportAbuseOf: "รายงาน {ชื่อ}" +reportAbuseOf: "รายงาน {name}" fillAbuseReportDescription: "กรุณากรอกรายละเอียดเกี่ยวกับรายงานนี้ หากเป็นเรื่องเกี่ยวกับโน้ตโดยเฉพาะ ได้โปรดระบุ URL" abuseReported: "เราได้ส่งรายงานของคุณไปแล้ว ขอบคุณมากๆนะ" -reporter: "นักข่าว" +reporter: "ผู้รายงาน" reporteeOrigin: "รายงานต้นทาง" -reporterOrigin: "นักข่าวต้นทาง" +reporterOrigin: "แหล่งผู้รายงาน" forwardReport: "ส่งต่อรายงานไปยังอินสแตนซ์ระยะไกล" -forwardReportIsAnonymous: "แทนที่จะเป็นบัญชีของคุณ บัญชีระบบที่ไม่ระบุตัวตนจะแสดงเป็นนักข่าวที่อินสแตนซ์ระยะไกล" +forwardReportIsAnonymous: "ข้อมูลของคุณจะไม่ปรากฏบนอินสแตนซ์ระยะไกลและปรากฏเป็นบัญชีระบบที่ไม่ระบุชื่อ" send: "ส่ง" abuseMarkAsResolved: "ทำเครื่องหมายรายงานว่าแก้ไขแล้ว" openInNewTab: "เปิดในแท็บใหม่" @@ -699,7 +699,7 @@ openInSideView: "เปิดในมุมมองด้านข้าง" defaultNavigationBehaviour: "พฤติกรรมการนำทางที่เป็นค่าเริ่มต้น" editTheseSettingsMayBreakAccount: "การแก้ไขการตั้งค่าเหล่านี้อาจทำให้บัญชีของคุณเสียหายนะ" instanceTicker: "ข้อมูลอินสแตนซ์ของโน้ต" -waitingFor: "กำลังรอคอย {x}" +waitingFor: "กำลังรอ {x}" random: "สุ่มค่า" system: "ระบบ" switchUi: "สลับ UI" @@ -709,7 +709,7 @@ createNew: "สร้างใหม่" optional: "ไม่บังคับ" createNewClip: "สร้างคลิปใหม่" unclip: "ลบคลิป" -confirmToUnclipAlreadyClippedNote: "โน้ตนี้เป็นส่วนหนึ่งของคลิป \"{name}\" แล้ว คุณต้องการลบออกจากคลิปนี้แทนอย่างงั้นหรอ?" +confirmToUnclipAlreadyClippedNote: "โน้ตนี้เป็นส่วนหนึ่งของคลิป “{name}” อยู่แล้ว ต้องการนำมันออกจากคลิปใช่ไหม?" public: "สาธารณะ" private: "ส่วนตัว" i18nInfo: "Misskey กำลังได้รับการแปลเป็นภาษาต่างๆ โดยอาสาสมัคร คุณสามารถช่วยเหลือได้ที่ {link}" @@ -732,7 +732,7 @@ driveFilesCount: "จำนวนไฟล์ไดรฟ์" driveUsage: "การใช้พื้นที่ไดรฟ์" noCrawle: "ปฏิเสธการจัดทำดัชนีของโปรแกรมรวบรวมข้อมูล" noCrawleDescription: "ขอให้เครื่องมือค้นหาไม่จัดทำดัชนีหน้าโปรไฟล์ โน้ต หน้าเพจ ฯลฯ" -lockedAccountInfo: "เว้นแต่ว่าคุณจะต้องตั้งค่าการเปิดเผยโน้ตเป็น \"ผู้ติดตามเท่านั้น\" โน้ตย่อของคุณจะปรากฏแก่ทุกคน ถึงแม้ว่าคุณจะเป็นกำหนดให้ผู้ติดตามต้องได้รับการอนุมัติด้วยตนเองก็ตาม" +lockedAccountInfo: "แม้ว่าการอนุมัติการติดตามถูกเปิดใช้งานอยู่ทุกคนก็ยังคงสามารถเห็นโน้ตของคุณได้ เว้นแต่ว่าคุณจะเปลี่ยนการเปิดเผยโน้ตของคุณเป็น “เฉพาะผู้ติดตาม”" alwaysMarkSensitive: "ทำเครื่องหมายว่ามีเนื้อหาละเอียดอ่อนเป็นค่าเริ่มต้น" loadRawImages: "โหลดภาพต้นฉบับแทนการแสดงภาพขนาดย่อ" disableShowingAnimatedImages: "ไม่ต้องเล่นภาพเคลื่อนไหว" @@ -768,29 +768,29 @@ nNotes: "{n} โน้ต" sendErrorReports: "ส่งรายงานว่าข้อผิดพลาด" sendErrorReportsDescription: "เมื่อเปิดใช้งาน ข้อมูลข้อผิดพลาดโดยรายละเอียดนั้นจะถูกแชร์ให้กับ Misskey เมื่อเกิดปัญหา ซึ่งช่วยปรับปรุงคุณภาพของ Misskey\nซึ่งจะรวมถึงข้อมูล เช่น เวอร์ชั่นของระบบปฏิบัติการ เบราว์เซอร์ที่คุณใช้ กิจกรรมของคุณใน Misskey เป็นต้น" myTheme: "ธีมของฉัน" -backgroundColor: "ภาพพื้นหลัง" -accentColor: "รูปแบบสี" +backgroundColor: "สีพื้นหลัง" +accentColor: "สีหลัก" textColor: "สีข้อความ" saveAs: "บันทึกเป็น..." advanced: "ขั้นสูง" advancedSettings: "การตั้งค่าขั้นสูง" value: "ค่า" createdAt: "สร้างเมื่อ" -updatedAt: "อัพเดทล่าสุด" +updatedAt: "อัปเดตล่าสุด" saveConfirm: "บันทึกเปลี่ยนแปลงมั้ย?" deleteConfirm: "ลบจริงๆเหรอ?" invalidValue: "ค่านี้ไม่ถูกต้อง" registry: "ทะเบียน" closeAccount: "ปิด บัญชี" currentVersion: "เวอร์ชั่นปัจจุบัน" -latestVersion: "รุ่นปัจจุบัน" +latestVersion: "เวอร์ชั่นล่าสุด" youAreRunningUpToDateClient: "คุณกำลังใช้ไคลเอ็นต์เวอร์ชันใหม่ล่าสุดนะ" newVersionOfClientAvailable: "มีไคลเอ็นต์เวอร์ชันใหม่กว่าของคุณพร้อมใช้งานนะ" usageAmount: "การใช้งาน" capacity: "ความจุ" inUse: "ใช้แล้ว" editCode: "แก้ไขโค้ด" -apply: "ตกลง" +apply: "นำไปใช้" receiveAnnouncementFromInstance: "รับการแจ้งเตือนจากอินสแตนซ์นี้" emailNotification: "การแจ้งเตือนทางอีเมล" publish: "เผยแพร่" @@ -802,7 +802,7 @@ showingPastTimeline: "กำลังแสดงผลไทม์ไลน์ clear: "ล้าง" markAllAsRead: "ทำเครื่องหมายทั้งหมดว่าอ่านแล้ว" goBack: "ย้อนกลับ" -unlikeConfirm: "เลิกถูกใจจริงๆ หรือ?" +unlikeConfirm: "ต้องการเลิกถูกใจใช่ไหม?" fullView: "มุมมองแบบเต็ม" quitFullView: "ออกจากมุมมองแบบเต็ม" addDescription: "เพิ่มคำอธิบาย" @@ -813,12 +813,12 @@ userInfo: "ข้อมูลผู้ใช้" unknown: "ไม่ทราบสถานะ" onlineStatus: "สถานะออนไลน์" hideOnlineStatus: "ซ่อนสถานะออนไลน์" -hideOnlineStatusDescription: "การซ่อนสถานะออนไลน์ของคุณช่วยลดความสะดวกของคุณสมบัติบางอย่าง เช่น การค้นหา อ่ะนะ" +hideOnlineStatusDescription: "การซ่อนสถานะออนไลน์อาจทำให้ฟังก์ชันบางอย่าง เช่น การค้นหา สะดวกน้อยลง" online: "ออนไลน์" active: "ใช้งานอยู่" offline: "ออฟไลน์" notRecommended: "ไม่แนะนำ" -botProtection: "การป้องกัน Bot (or AI)" +botProtection: "การป้องกัน Bot" instanceBlocking: "อินสแตนซ์ที่ถูกบล็อก" selectAccount: "เลือกบัญชี" switchAccount: "สลับบัญชีผู้ใช้" @@ -880,7 +880,7 @@ itsOff: "ปิดใช้งาน" on: "เปิด" off: "ปิด" emailRequiredForSignup: "จำเป็นต้องการใช้ที่อยู่อีเมลสำหรับการสมัคร" -unread: "ไม่ได้อ่าน" +unread: "ยังไม่ได้อ่าน" filter: "กรอง" controlPanel: "แผงควบคุม" manageAccounts: "จัดการบัญชี" @@ -888,13 +888,13 @@ makeReactionsPublic: "ตั้งค่าประวัติการรี makeReactionsPublicDescription: "การทำเช่นนี้จะทำให้รายการรีแอคชั่นของคุณที่ผ่านมาทั้งหมดปรากฏต่อสาธารณะ" classic: "คลาสสิค" muteThread: "ปิดเสียงเธรด" -unmuteThread: "เปิดเสียงเธรด" +unmuteThread: "เลิกปิดเสียงเธรด" followingVisibility: "การมองเห็นที่เรากำลังติดตาม" followersVisibility: "การมองเห็นผู้ที่กำลังติดตามเรา" continueThread: "ดูความต่อเนื่องเธรด" deleteAccountConfirm: "การดำเนินการนี้จะลบบัญชีของคุณอย่างถาวรเลยนะ แน่ใจหรอดำเนินการ?" incorrectPassword: "รหัสผ่านไม่ถูกต้อง" -voteConfirm: "ยืนยันการโหวต “{choice}” ไหม?" +voteConfirm: "ต้องการโหวต “{choice}” ใช่ไหม?" hide: "ซ่อน" useDrawerReactionPickerForMobile: "แสดง ตัวจิ้มรีแอคชั่น เป็นแบบลิ้นชัก เมื่อใช้บนมือถือ" welcomeBackWithName: "ยินดีต้อนรับการกลับมานะคะ, คุณ{name}" @@ -941,13 +941,13 @@ deleteAccount: "ลบบัญชี" document: "เอกสาร" numberOfPageCache: "จำนวนหน้าเพจที่แคช" numberOfPageCacheDescription: "การเพิ่มจำนวนนี้จะช่วยเพิ่มความสะดวกให้กับผู้ใช้งาน แต่จะทำให้เซิร์ฟเวอร์โหลดมากขึ้นและต้องใช้หน่วยความจำมากขึ้นอีกด้วย" -logoutConfirm: "ต้องการออกจากระบบ?" -lastActiveDate: "ใช้งานล่าสุดที่" +logoutConfirm: "ต้องการออกจากระบบใช่ไหม?" +lastActiveDate: "ใช้งานล่าสุดเมื่อ" statusbar: "แถบสถานะ" pleaseSelect: "ตัวเลือก" -reverse: "ย้อนกลับ" +reverse: "พลิก" colored: "สี" -refreshInterval: "รอบการอัพเดต" +refreshInterval: "ความถี่ในการอัปเดต" label: "ป้ายชื่อ" type: "รูปแบบ" speed: "ความเร็ว" @@ -974,8 +974,8 @@ unsubscribePushNotification: "ปิดการแจ้งเตือนแ pushNotificationAlreadySubscribed: "การแจ้งเตือนแบบพุชได้เปิดใช้งานแล้ว" pushNotificationNotSupported: "เบราว์เซอร์หรืออินสแตนซ์ของคุณนั้นไม่รองรับการแจ้งเตือนแบบพุช" sendPushNotificationReadMessage: "ลบการแจ้งเตือนแบบพุชเมื่ออ่านการแจ้งเตือนหรือข้อความที่เกี่ยวข้องแล้ว" -sendPushNotificationReadMessageCaption: "การแจ้งเตือนที่มีข้อความ \"{emptyPushNotificationMessage}\" จะแสดงขึ้นมาในช่วงระยะเวลาสั้นๆ การดำเนินการนี้อาจทำให้เพิ่มการใช้งานแบตเตอรี่ของอุปกรณ์ถ้าหากมีนะ" -windowMaximize: "ขยายใหญ่สุดแล้ว" +sendPushNotificationReadMessageCaption: "อาจทำให้อุปกรณ์ของคุณใช้พลังงานมากขึ้น" +windowMaximize: "ขยายใหญ่สุด" windowMinimize: "ย่อเล็กที่สุด" windowRestore: "เลิกทำ" caption: "คำอธิบาย" @@ -991,6 +991,7 @@ neverShow: "ไม่ต้องแสดงข้อความนี้อ remindMeLater: "ไว้ครั้งหน้าแล้วกัน" didYouLikeMisskey: "คุณชอบ Misskey ไหม?" pleaseDonate: "Misskey เป็นซอฟต์แวร์ฟรีที่ใช้งานโดย {host} เราขอขอบคุณการสนับสนุนของคุณอย่างสูงเพื่อให้การพัฒนา Misskey สามารถดำเนินต่อไปได้!" +correspondingSourceIsAvailable: "ซอร์สโค้ดที่เกี่ยวข้องมีอยู่ที่ {anchor}" roles: "บทบาท" role: "บทบาท" noRole: "ไม่พบบทบาท" @@ -1041,6 +1042,9 @@ resetPasswordConfirm: "รีเซ็ตรหัสผ่านของคุ sensitiveWords: "คำที่มีเนื้อหาละเอียดอ่อน" sensitiveWordsDescription: "การเปิดเผยโน้ตทั้งหมดที่มีคำที่กำหนดค่าไว้จะถูกตั้งค่าเป็น \"หน้าแรก\" โดยอัตโนมัติ คุณยังสามารถแสดงหลายรายการได้โดยแยกรายการโดยใช้ตัวแบ่งบรรทัดได้นะ" sensitiveWordsDescription2: "การใช้ช่องว่างนั้นอาจจะสร้างนิพจน์ AND และคำหลักที่มีเครื่องหมายทับล้อมรอบจะเปลี่ยนเป็นนิพจน์ทั่วไปนะ" +prohibitedWords: "คำต้องห้าม" +prohibitedWordsDescription: "จะแจ้งเตือนว่าเกิดข้อผิดพลาดเมื่อพยายามโพสต์โน้ตที่มีคำที่กำหนดไว้ สามารถตั้งได้หลายคำด้วยการขึ้นบรรทัดใหม่" +prohibitedWordsDescription2: "การใช้ช่องว่างนั้นอาจจะสร้างนิพจน์ AND และคำหลักที่มีเครื่องหมายทับล้อมรอบจะเปลี่ยนเป็นนิพจน์ทั่วไปนะ" hiddenTags: "แฮชแท็กที่ซ่อนอยู่" hiddenTagsDescription: "เลือกแท็กที่จะไม่แสดงในรายการเทรนด์ สามารถลงทะเบียนหลายแท็กได้โดยขึ้นบรรทัดใหม่" notesSearchNotAvailable: "การค้นหาโน้ตไม่พร้อมใช้งาน" @@ -1056,7 +1060,7 @@ enableChartsForFederatedInstances: "สร้างแผนภูมิข้ showClipButtonInNoteFooter: "เพิ่ม “คลิป” ไปยังเมนูสั่งการของโน้ต" reactionsDisplaySize: "ขนาดของรีแอคชั่น" limitWidthOfReaction: "จำกัดความกว้างสูงสุดของรีแอคชั่นและแสดงให้เล็กลง" -noteIdOrUrl: "โน้ต ID หรือ URL" +noteIdOrUrl: "ID ของโน้ต หรือ URL" video: "วีดีโอ" videos: "วีดีโอ" audio: "เสียง" @@ -1078,7 +1082,7 @@ leftBottom: "ล่างซ้าย" rightBottom: "ล่างขวา" stackAxis: "ทิศทางการซ้อน" vertical: "แนวตั้ง" -horizontal: "ด้านข้าง" +horizontal: "แนวนอน" position: "ตำแหน่ง" serverRules: "กฎของเซิร์ฟเวอร์" pleaseConfirmBelowBeforeSignup: "โปรดยืนยันที่ด้านล่างก่อนสมัครใช้งาน" @@ -1094,17 +1098,17 @@ thisChannelArchived: "ช่องนี้ถูกเก็บถาวรแ displayOfNote: "การแสดงโน้ต" initialAccountSetting: "ตั้งค่าโปรไฟล์" youFollowing: "ติดตามแล้ว" -preventAiLearning: "ปฏิเสธการใช้งาน ในการเรียนรู้ของเครื่อง (Generative AI)" -preventAiLearningDescription: "การส่งคำร้องขอโปรแกรมรวบรวมข้อมูลไม่ให้ใช้ข้อความที่โพสต์หรือรูปภาพ ฯลฯ ในชุดข้อมูลแมชชีนเลิร์นนิง (Predictive / Generative AI) สิ่งนี้นั้นทำได้โดยการเพิ่มแฟล็กการตอบสนอง \"noai\" HTML ให้กับเนื้อหาที่เกี่ยวข้อง แต่อย่างไรก็ตามแล้ว การป้องกันโดยสมบูรณ์นั้นไม่สามารถทำได้ผ่านแฟล็กนี้เนื่องจากอาจจะทำให้ถูกเพิกเฉยได้" +preventAiLearning: "ปฏิเสธการเรียนรู้ด้วย generative AI" +preventAiLearningDescription: "ส่งคำร้องขอไม่ให้ใช้ ข้อความในโน้ตที่โพสต์, หรือเนื้อหารูปภาพ ฯลฯ ในการเรียนรู้ของเครื่อง(machine learning) / Predictive AI / Generative AI โดยการเพิ่มแฟล็ก “noai” ลง HTML-Response ให้กับเนื้อหาที่เกี่ยวข้อง แต่ทั้งนี้ ไม่ได้ป้องกัน AI จากการเรียนรู้ได้อย่างสมบูรณ์ เนื่องจากมี AI บางตัวเท่านั้นที่จะเคารพคำขอดังกล่าว" options: "ตัวเลือกบทบาท" specifyUser: "ผู้ใช้เฉพาะ" failedToPreviewUrl: "ไม่สามารถดูตัวอย่างได้" update: "อัปเดต" rolesThatCanBeUsedThisEmojiAsReaction: "บทบาทที่สามารถใช้เอโมจินี้เป็นรีแอคชั่นได้" -rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ถ้าหากไม่ได้ระบุบทบาท ทุกคนนั้นก็สามารถใช้เอโมจินี้เพื่อรีแอคชั่นได้นะ" +rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ถ้าหากไม่ได้ระบุบทบาท ใคร ๆ ก็สามารถใช้เอโมจินี้เพื่อรีแอคชั่นได้" rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "บทบาทเหล่านี้ต้องเป็นสาธารณะ" -cancelReactionConfirm: "ต้องการลบรีแอคชั่นของคุณจริงๆหรอ?" -changeReactionConfirm: "ต้องการเปลี่ยนรีแอคชั่นของคุณจริงๆหรอ?" +cancelReactionConfirm: "ต้องการลบรีแอคชั่นใช่ไหม?" +changeReactionConfirm: "ต้องการเปลี่ยนรีแอคชั่นใช่ไหม?" later: "ไว้ทีหลัง" goToMisskey: "ถึง Misskey" additionalEmojiDictionary: "พจนานุกรมเอโมจิเพิ่มเติม" @@ -1113,20 +1117,20 @@ branding: "แบรนดิ้ง" enableServerMachineStats: "เผยแพร่สถานะฮาร์ดแวร์ของเซิร์ฟเวอร์" enableIdenticonGeneration: "เปิดใช้งานผู้ใช้สร้างตัวระบุ" turnOffToImprovePerformance: "การปิดส่วนนี้สามารถเพิ่มประสิทธิภาพได้" -createInviteCode: "สร้างคำเชิญ" +createInviteCode: "สร้างรหัสเชิญ" createWithOptions: "สร้างด้วยตัวเลือก" -createCount: "จำนวนการเชิญ" -inviteCodeCreated: "สร้างคำเชิญแล้ว" -inviteLimitExceeded: "คุณสร้างคำเชิญเกินถึงขีดจำกัดแล้วนะ" -createLimitRemaining: "ขีดจำกัดการเชิญ: {limit} ที่เหลืออยู่" -inviteLimitResetCycle: "ขีดจำกัดนี้จะถูกรีเซ็ตเป็น {limit} ที่ {time}." +createCount: "จำนวนรหัสเชิญ" +inviteCodeCreated: "สร้างรหัสเชิญแล้ว" +inviteLimitExceeded: "จำนวนรหัสเชิญที่สามารถสร้างได้ถึงขีดจำกัดแล้ว" +createLimitRemaining: "รหัสเชิญที่สามารถสร้างได้: เหลืออยู่ {limit} รหัส" +inviteLimitResetCycle: "สามารถสร้างรหัสเชิญได้อีกสูงสุด {limit} รหัส ภายใน {time}" expirationDate: "วันที่หมดอายุ" noExpirationDate: "ไม่มีหมดอายุ" -inviteCodeUsedAt: "รหัสคำเชิญใช้แล้วที่" -registeredUserUsingInviteCode: "ใช้คำเชิญแล้วโดย" +inviteCodeUsedAt: "วันเวลาที่ใช้รหัสเชิญ" +registeredUserUsingInviteCode: "ผู้ใช้ที่ใช้รหัสเชิญ" waitingForMailAuth: "กำลังรอการยืนยันอีเมล" -inviteCodeCreator: "สร้างการเชิญแล้วโดย" -usedAt: "ใช้แล้วที่" +inviteCodeCreator: "ผู้ใช้ที่สร้างรหัสเชิญ" +usedAt: "วันเวลาที่ถูกใช้" unused: "ยังไม่ได้ใช้" used: "ถูกใช้แล้ว" expired: "หมดอายุแล้ว" @@ -1145,7 +1149,7 @@ renotes: "รีโน้ต" loadReplies: "แสดงการตอบกลับ" loadConversation: "แสดงบทสนทนา" pinnedList: "รายชื่อที่ปักหมุดไว้" -keepScreenOn: "เปิดหน้าจอไว้" +keepScreenOn: "เปิดหน้าจออุปกรณ์ค้างไว้" verifiedLink: "ความเป็นเจ้าของลิงก์ได้รับการยืนยันแล้ว" notifyNotes: "แจ้งเตือนเกี่ยวกับโพสต์ใหม่" unnotifyNotes: "หยุดการแจ้งเตือนเกี่ยวกับโน้ตใหม่" @@ -1156,6 +1160,7 @@ showRenotes: "แสดงรีโน้ต" edited: "แก้ไขแล้ว" notificationRecieveConfig: "การตั้งค่าการแจ้งเตือน" mutualFollow: "ติดตามซึ่งกันและกัน" +followingOrFollower: "กำลังติดตามหรือผู้ติดตาม" fileAttachedOnly: "เฉพาะโน้ตที่มีไฟล์เท่านั้น" showRepliesToOthersInTimeline: "แสดงการตอบกลับผู้อื่นลงในไทม์ไลน์" hideRepliesToOthersInTimeline: "ไม่แสดงการตอบกลับผู้อื่นลงในไทม์ไลน์" @@ -1164,6 +1169,13 @@ hideRepliesToOthersInTimelineAll: "ซ่อนตอบกลับจากท confirmShowRepliesAll: "การดำเนินการนี้ไม่สามารถย้อนกลับได้ คุณต้องการแสดงการตอบกลับผู้อื่นจากผู้ใช้ทุกคนที่คุณติดตามอยู่ในไทม์ไลน์ของคุณหรือไม่?" confirmHideRepliesAll: "การดำเนินการนี้ไม่สามารถย้อนกลับได้ คุณต้องการซ่อนการตอบกลับผู้อื่นจากผู้ใช้ทุกคนที่คุณติดตามอยู่ในไทม์ไลน์ของคุณหรือไม่?" externalServices: "บริการภายนอก" +sourceCode: "ซอร์สโค้ด" +sourceCodeIsNotYetProvided: "ซอร์สโค้ดยังไม่พร้อมใช้งาน โปรดติดต่อผู้ดูแลระบบของคุณเพื่อแก้ไขปัญหานี้" +repositoryUrl: "URL ของ repository" +repositoryUrlDescription: "หากมีที่เก็บซอร์สโค้ดที่เปิดเผยต่อสาธารณะ ให้ป้อน URL ที่เก็บซอร์สโค้ดนั้น แต่หากคุณใช้ Misskey ตามต้นฉบับ (ไม่มีการเปลี่ยนแปลงซอร์สโค้ด) ให้ป้อน https://github.com/misskey-dev/misskey" +repositoryUrlOrTarballRequired: "หากคุณไม่มี repository สาธารณะ คุณจะต้องจัดเตรียม tarball แทน ดู .config/example.yml สำหรับรายละเอียด" +feedback: "ฟีดแบ็ก" +feedbackUrl: "URLของฟีดแบ็ก" impressum: "อิมเพรสชั่น" impressumUrl: "URL อิมเพรสชั่น" impressumDescription: "การติดป้ายกำกับ (Impressum) มีผลบังคับใช้ในบางประเทศและภูมิภาค เช่น ประเทศเยอรมนี" @@ -1175,7 +1187,7 @@ attach: "แนบ" detach: "นำออก" detachAll: "เอาออกทั้งหมด" angle: "แองเกิล" -flip: "ย้อนกลับ" +flip: "พลิก" showAvatarDecorations: "แสดงตกแต่งอวตาร" releaseToRefresh: "ปล่อยเพื่อรีเฟรช" refreshing: "กำลังรีเฟรช..." @@ -1199,12 +1211,29 @@ soundWillBePlayed: "จะมีการเล่นเอฟเฟกต์เ showReplay: "ดูรีเพลย์" replay: "รีเพลย์" replaying: "กำลังรีเพลย์" +endReplay: "ออกจากรีเพลย์" +copyReplayData: "คัดลอกข้อมูลรีเพลย์" ranking: "อันดับ" lastNDays: "ล่าสุด {n} วันที่แล้ว" backToTitle: "กลับไปหน้าไตเติ้ล" +hemisphere: "พื้นที่ที่อาศัยอยู่" +withSensitive: "แสดงโน้ตที่มีไฟล์เนื้อหาละเอียดอ่อน" +userSaysSomethingSensitive: "โพสต์ที่มีไฟล์เนื้อหาละเอียดอ่อนของ {name}" enableHorizontalSwipe: "ปัดเพื่อสลับแท็บ" +loading: "กำลังโหลด" +surrender: "ยอมแพ้" +gameRetry: "เริ่มเกมใหม่" _bubbleGame: howToPlay: "วิธีเล่น" + hold: "หยุดชั่วคราว" + _score: + score: "คะแนน" + scoreYen: "จำนวนเงินที่ได้รับ" + highScore: "คะแนนสูงสุด" + maxChain: "จำนวน chain สูงสุด" + yen: "{yen} เยน" + estimatedQty: "{qty} อัน" + scoreSweets: "โอนิงิริ {onigiriQtyWithUnit}" _howToPlay: section1: "ขยับตำแหน่งและวางวัตถุลงในกล่อง" section2: "เมื่อวัตถุประเภทเดียวกันมารวมกัน พวกมันจะกลายเป็นวัตถุใหม่และคุณจะได้รับคะแนน" @@ -1212,16 +1241,16 @@ _bubbleGame: _announcement: forExistingUsers: "ผู้ใช้งานที่มีอยู่เท่านั้น" forExistingUsersDescription: "การประกาศนี้จะแสดงต่อผู้ใช้ที่มีอยู่ ณ จุดที่เผยแพร่นั้นๆถ้าหากเปิดใช้งาน ถ้าหากปิดใช้งานผู้ที่กำลังสมัครใหม่หลังจากโพสต์แล้วนั้นก็จะเห็นเช่นกัน" - needConfirmationToRead: "จำเป็นต้องยืนยันเพื่อทำเครื่องหมายบอกว่าอ่านแล้ว" - needConfirmationToReadDescription: "ข้อความแจ้งแยก ถ้าหากต้องการเพื่อยืนยันว่ากำลังทำเครื่องหมายประกาศนี้ว่าอ่านแล้วจะแสดงขึ้นถ้าหากเปิดใช้งาน การประกาศนั้นจะไม่รวมอยู่ในฟังก์ชั่นว่า \"ทำเครื่องหมายทั้งหมดว่าอ่านแล้ว\"" + needConfirmationToRead: "จำเป็นต้องยืนยันว่าอ่านแล้ว" + needConfirmationToReadDescription: "กล่องโต้ตอบการยืนยันจะปรากฏขึ้นเมื่อจะทำเครื่องหมายว่าอ่านแล้ว นอกจากนี้ยังทำให้ประกาศนี้ยังไม่ถูกอ่านเมื่อใช้ฟังก์ชั่น “ทำเครื่องหมายฯ ทั้งหมดว่าอ่านแล้ว”" end: "เก็บประกาศ" tooManyActiveAnnouncementDescription: "การมีประกาศที่ใช้งานมากเกินไปนั้นอาจจะทำให้ประสบการณ์ของผู้ใช้งานนั้นดูแย่ลง โปรดกรุณาพิจารณาการเก็บประกาศที่ล้าสมัยด้วยนะค่ะ" - readConfirmTitle: "ทำเครื่องหมายบอกว่าอ่านแล้วเลยมั้ย?" - readConfirmText: "การดำเนินการนี้จะทำเครื่องหมายเนื้อหาของ \"{title}\" บอกว่าอ่านแล้วนะ" + readConfirmTitle: "ทำเครื่องหมายว่าอ่านแล้วเลยไหม?" + readConfirmText: "จะทำเครื่องหมายใส่ “{title}” ว่าอ่านแล้ว" shouldNotBeUsedToPresentPermanentInfo: "เราขอแนะนำให้ใช้ประกาศเพื่อโพสต์ข้อมูลแบบ flow มากกว่าข้อมูลแบบ stock เนื่องจากมีแนวโน้มที่จะส่งผลเสียต่อ UX โดยเฉพาะสำหรับผู้ใช้ใหม่" dialogAnnouncementUxWarn: "เราขอแนะนำให้ใช้ด้วยความระมัดระวัง เนื่องจากการแจ้งเตือนแบบกล่องโต้ตอบตั้งแต่ 2 รายการขึ้นไปพร้อมกันอาจส่งผลเสียต่อ UX ได้อย่างมาก" silence: "ไม่มีการแจ้งเตือน" - silenceDescription: "หากเปิดใช้งาน จะไม่ได้แจ้งเตือนประกาศนี้ และผู้ใช้จะไม่จำเป็นต้องอ่าน" + silenceDescription: "หากเปิดใช้งาน จะไม่มีการแจ้งเตือนประกาศนี้ และผู้ใช้จะไม่จำเป็นต้องทำเครื่องหมายว่าอ่านแล้ว" _initialAccountSetting: accountCreated: "คุณได้สร้างบัญชีของคุณสำเร็จเรียบร้อยแล้ว!" letsStartAccountSetup: "สำหรับผู้เริ่มต้นมาตั้งค่าโปรไฟล์ของคุณกันเถอะ" @@ -1308,7 +1337,7 @@ _timelineDescription: _serverRules: description: "ชุดของกฎที่จะแสดงก่อนการลงทะเบียนเราขอแนะนำให้ตั้งค่าสรุปข้อกำหนดในการให้บริการ" _serverSettings: - iconUrl: "ไอคอน URL" + iconUrl: "URL ไอคอน" appIconDescription: "ระบุไอคอนที่จะใช้เมื่อ {host} แสดงเป็นแอป" appIconUsageExample: "E.g. เป็น PWA หรือเมื่อแสดงผลเป็นบุ๊กมาร์กหน้าจอหลักบนโทรศัพท์" appIconStyleRecommendation: "เนื่องจากไอคอนอาจถูกครอบตัดเป็นสี่เหลี่ยมจัตุรัสหรือวงกลม จึงแนะนำให้ใช้ไอคอนที่มีขอบสีรอบๆ เนื้อหา" @@ -1596,7 +1625,7 @@ _role: assignTarget: "มอบหมาย" descriptionOfAssignTarget: "แบบปรับเอง เพิ่มถอนบทบาทนี้แก่ผู้ใช้ด้วยตัวเอง\nแบบมีเงื่อนไข เพิ่มถอนบทบาทนี้แก่ผู้ใช้โดยอัตโนมัติหากเข้าเงื่อนไขใดต่อไปนี้" manual: "ปรับเอง" - manualRoles: "บทบาทแบบทำเอง" + manualRoles: "บทบาทแบบทำมือ" conditional: "มีเงื่อนไข" conditionalRoles: "บทบาทแบบมีเงื่อนไข" condition: "เงื่อนไข" @@ -1608,13 +1637,13 @@ _role: baseRole: "เทมเพลตบทบาท" useBaseValue: "ใช้ตามเทมเพลตบทบาท" chooseRoleToAssign: "เลือกบทบาทที่ต้องการกำหนด" - iconUrl: "ไอคอน URL" + iconUrl: "URL ไอคอน" asBadge: "แสดงเป็นตรา" descriptionOfAsBadge: "เมื่อเปิดใช้งาน ไอคอนบทบาทจะปรากฏถัดจากชื่อผู้ใช้" isExplorable: "ค้นหาผู้ใช้ได้ง่ายขึ้นโดยดูจากบทบาท" descriptionOfIsExplorable: "เมื่อเปิดใช้งาน ไทมไลน์บทบาทนี้และสมาชิกที่มีบทบาทนี้จะเปิดเผยเป็นสาธารณะ" - displayOrder: "ตำแหน่ง" - descriptionOfDisplayOrder: "ยิ่งตัวเลขสูง ตำแหน่ง UI ก็ยิ่งสูงขึ้นนะ" + displayOrder: "ลำดับการแสดงผล" + descriptionOfDisplayOrder: "เลขที่สูงกว่าจะแสดงบน UI ก่อน" canEditMembersByModerator: "อนุญาตให้ผู้ควบคุมแก้ไขสมาชิก" descriptionOfCanEditMembersByModerator: "เมื่อเปิดใช้ นอกเหนือจากผู้ควบคุมและผู้ดูแลระบบแล้ว จะสามารถเพิ่มถอนบทบาทนี้แก่ผู้ใช้ได้ แต่เมื่อปิดใช้ จะมีเฉพาะผู้ดูแลระบบเท่านั้นที่จะสามารถดำเนินการได้" priority: "ลำดับความสำคัญ" @@ -1626,6 +1655,7 @@ _role: gtlAvailable: "การดูไทม์ไลน์ทั่วโลก" ltlAvailable: "การดูไทม์ไลน์ในท้องถิ่น" canPublicNote: "สามารถโพสต์แบบสาธารณะ" + mentionMax: "จำนวนการกล่าวถึงสูงสุดต่อโน้ต" canInvite: "สร้างรหัสเชิญอินสแตนซ์" inviteLimit: "จำกัดการเชิญ" inviteLimitCycle: "คูลดาวน์ในการเชิญ" @@ -1649,6 +1679,7 @@ _role: canUseTranslator: "การใช้งานแปล" avatarDecorationLimit: "จำนวนการตกแต่งไอคอนสูงสุดที่สามารถติดตั้งได้" _condition: + roleAssignedTo: "มอบหมายให้มีบทบาทแบบทำมือ" isLocal: "ผู้ใช้ในพื้นที่" isRemote: "ผู้ใช้ระยะไกล" createdLessThan: "สร้างน้อยกว่า" @@ -1678,13 +1709,13 @@ _emailUnavailable: smtp: "เซิร์ฟเวอร์อีเมลนี้ไม่มีการตอบสนอง" banned: "คุณไม่สามารถลงทะเบียนด้วยที่อยู่อีเมลนี้ได้" _ffVisibility: - public: "เผยแพร่" + public: "สาธารณะ" followers: "ปรากฏให้แก่ผู้ติดตามเท่านั้น" private: "ส่วนตัว" _signup: almostThere: "เกือบจะเสร็จแล้ว" emailAddressInfo: "กรุณากรอกที่อยู่อีเมลที่คุณใช้ ที่อยู่อีเมลของคุณจะไม่ถูกเผยแพร่สู่สาธารณชน" - emailSent: "เราได้ส่งอีเมลยืนยันไปยังที่อยู่อีเมลของคุณแล้วนะ ({email}) โปรดคลิกลิงก์ที่รวมไว้เพื่อสร้างบัญชีให้เสร็จสิ้น" + emailSent: "อีเมลยืนยันได้ถูกส่งไปยังที่อยู่อีเมลที่คุณป้อน ({email}) แล้ว กรุณาติดตามลิงก์ในอีเมลเพื่อสร้างบัญชีให้เสร็จสมบูรณ์ ลิงก์ที่ให้ไว้จะหมดอายุใน 30 นาที" _accountDelete: accountDelete: "ลบบัญชีผู้ใช้" mayTakeTime: "เนื่องจากการลบบัญชีนี้จะเป็นกระบวนการที่ต้องใช้ทรัพยากรมาก จึงอาจจะต้องใช้เวลาสักครู่ถึงจะเสร็จสมบูรณ์ ทั้งนี้ขึ้นอยู่กับจำนวนเนื้อหาที่คุณสร้างและจำนวนไฟล์ที่คุณอัปโหลดนะ" @@ -1722,7 +1753,7 @@ _plugin: viewSource: "ดูต้นฉบับ" _preferencesBackups: list: "สร้างการสำรองข้อมูล" - saveNew: "บันทึกใหม่" + saveNew: "บันทึกข้อมูลสำรองใหม่" loadFile: "โหลดจากไฟล์" apply: "นำไปใช้กับอุปกรณ์นี้" save: "บันทึก" @@ -1732,8 +1763,8 @@ _preferencesBackups: applyConfirm: "คุณต้องการใช้ข้อมูลสำรอง \"{name}\" กับอุปกรณ์นี้อย่างงั้นจริงหรอ การตั้งค่าที่มีอยู่ของอุปกรณ์นี้จะถูกเขียนทับนะ" saveConfirm: "บันทึกข้อมูลสำรองเป็น {name} มั้ย?" deleteConfirm: "ลบข้อมูลสำรอง {name} มั้ย?" - renameConfirm: "เปลี่ยนชื่อข้อมูลสำรองนี้จาก \"{old}\" เป็น \"{new}\" หรือไม่?" - noBackups: "ไม่มีข้อมูลสำรองนะ คุณสามารถสำรองข้อมูลการตั้งค่าไคลเอนต์ของคุณบนเซิร์ฟเวอร์นี้โดยใช้ \"สร้างการสำรองข้อมูลใหม่\"ได้นะ" + renameConfirm: "ต้องการเปลี่ยนชื่อข้อมูลสำรองจาก “{old}” เป็น “{new}” ใช่ไหม?" + noBackups: "ไม่มีข้อมูลสำรอง สามารถบันทึกการตั้งค่าไคลเอนต์ปัจจุบันไปยังเซิร์ฟเวอร์ด้วย “บันทึกข้อมูลสำรองใหม่”" createdAt: "สร้างเมื่อ: {date} {time}" updatedAt: "อัปเดตเมื่อ: {date} {time}" cannotLoad: "การโหลดล้มเหลว" @@ -1749,14 +1780,16 @@ _aboutMisskey: contributors: "ผู้สนับสนุนหลัก" allContributors: "ผู้มีส่วนร่วมทั้งหมด" source: "ซอร์สโค้ด" + original: "ต้นฉบับ" + thisIsModifiedVersion: "{name} ใช้ Misskey เวอร์ชันดัดแปลง" translation: "แปลภาษา Misskey" donate: "บริจาคให้กับ Misskey" - morePatrons: " ขอบคุณทุกท่านที่ร่วมกันช่วยเหลือตลอดมานะคะ 🥰" - patrons: "สมาชิกพันธมิตร" + morePatrons: "และอีกหลายท่านที่ไม่ได้เอ่ยนาม ขอบคุณที่ร่วมช่วยเหลือตลอดมานะคะ 🥰" + patrons: "ผู้อุปถัมภ์" projectMembers: "สมาชิกในโครงการ" _displayOfSensitiveMedia: - respect: "ซ่อนสื่อที่ทำเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน" - ignore: "แสดงสื่อที่ทำเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน" + respect: "ซ่อนสื่อที่มีเนื้อหาละเอียดอ่อน" + ignore: "แสดงสื่อที่มีเนื้อหาละเอียดอ่อน" force: "ซ่อนสื่อทั้งหมด" _instanceTicker: none: "ไม่ต้องแสดง" @@ -1824,8 +1857,8 @@ _theme: importInfo: "ถ้าหากต้องการป้อนโค้ดที่นี่ คุณยังสามารถนำเข้าไปยังโปรแกรมแก้ไขธีมได้" deleteConstantConfirm: "คุณต้องการลบค่าคงที่ {const} หรือป่าว?" keys: - accent: "เน้น" - bg: "ภาพพื้นหลัง" + accent: "สีหลัก" + bg: "พื้นหลัง" fg: "ข้อความ" focus: "โฟกัส" indicator: "ตัวบ่งชี้" @@ -1861,11 +1894,11 @@ _theme: wallpaperOverlay: "วอลล์เปเปอร์ซ้อนทับ" badge: "ตรา" messageBg: "พื้นหลังแชท" - accentDarken: "เน้น (มืด)" - accentLighten: "เน้น (สว่าง)" + accentDarken: "สีหลัก (มืด)" + accentLighten: "สีหลัก (สว่าง)" fgHighlighted: "ข้อความที่ไฮไลต์" _sfx: - note: "หมายเหตุ" + note: "โน้ต" noteMy: "โน้ตของตัวเอง" notification: "การเเจ้งเตือน" antenna: "เสาอากาศ" @@ -1952,7 +1985,7 @@ _permissions: "read:reactions": "ดูรีแอคชั่นของคุณ" "write:reactions": "แก้ไขรีแอคชั่นของคุณ" "write:votes": "โหวตบนสำรวจความคิดเห็น" - "read:pages": "ดหน้าเพจ" + "read:pages": "ดูหน้าเพจ" "write:pages": "แก้ไขหรือลบเพจของคุณ" "read:page-likes": "ดูรายการเพจที่ถูกใจไว้" "write:page-likes": "แก้ไขรายการเพจที่ถูกใจ" @@ -1964,8 +1997,8 @@ _permissions: "write:gallery": "แก้ไขแกลเลอรี่ของคุณ" "read:gallery-likes": "ดูรายการโพสต์แกลเลอรีที่ถูกใจไว้" "write:gallery-likes": "แก้ไขรายการโพสต์แกลเลอรีที่ถูกใจไว้" - "read:flash": "วิว เพลย์" - "write:flash": "แก้ไขเพลย์" + "read:flash": "ดู Play" + "write:flash": "แก้ไข Play" "read:flash-likes": "ดูรายการ play ที่ถูกใจไว้" "write:flash-likes": "แก้ไขรายการ play ที่ถูกใจไว้" "read:admin:abuse-user-reports": "ดูรายงานจากผู้ใช้" @@ -1992,8 +2025,8 @@ _permissions: "read:admin:roles": "ดูบทบาท" "write:admin:relays": "จัดการรีเลย์" "read:admin:relays": "ดูรีเลย์" - "write:admin:invite-codes": "จัดการคำเชิญ" - "read:admin:invite-codes": "ดูรหัสคำเชิญ" + "write:admin:invite-codes": "จัดการรหัสเชิญ" + "read:admin:invite-codes": "ดูรหัสเชิญ" "write:admin:announcements": "จัดการประกาศ" "read:admin:announcements": "ดูประกาศ" "write:admin:avatar-decorations": "จัดการการตกแต่งอวตาร" @@ -2011,7 +2044,7 @@ _permissions: "read:admin:stream": "ใช้ Websocket API สำหรับผู้ดูแลระบบ" "write:admin:ad": "จัดการโฆษณา" "read:admin:ad": "ดูโฆษณา" - "write:invite-codes": "สร้างรหัสคำเชิญ" + "write:invite-codes": "สร้างรหัสเชิญ" "read:invite-codes": "รับรหัสเชิญ" "write:clip-favorite": "ควบคุมการถูกใจของคลิป" "read:clip-favorite": "ดูการถูกใจของคลิป" @@ -2064,8 +2097,8 @@ _widgets: onlineUsers: "ผู้ใช้ที่ออนไลน์" jobQueue: "คิวงาน" serverMetric: "ตัวชี้วัดเซิร์ฟเวอร์" - aiscript: "AiScript คอนโซล" - aiscriptApp: "AiScript แอพ" + aiscript: " คอนโซล AiScript" + aiscriptApp: "แอป AiScript" aichan: "ไอ" userList: "รายชื่อผู้ใช้" _userList: @@ -2079,15 +2112,15 @@ _cw: files: "{count} ไฟล์" _poll: noOnlyOneChoice: "จำเป็นต้องมีอย่างน้อยสองตัวเลือก" - choiceN: "ตัวเลือก {n}" - noMore: "คุณไม่สามารถเพิ่มตัวเลือกอื่นได้" + choiceN: "ตัวเลือกที่ {n}" + noMore: "เพิ่มตัวเลือกอีกไม่ได้แล้ว" canMultipleVote: "สามารถตอบได้หลายคำตอบ" - expiration: "สิ้นสุดการสำรวจความคิดเห็น" - infinite: "ไม่ต้องเลย" - at: "จบที่..." - after: "สิ้นสุดหลัง..." + expiration: "สิ้นสุดโพล" + infinite: "ไม่กำหนดระยะเวลา" + at: "ระบุวันเวลา" + after: "ระบุระยะเวลา" deadlineDate: "วันสิ้นสุด" - deadlineTime: "ชั่วโมง" + deadlineTime: "เวลา" duration: "ระยะเวลา" votesCount: "{n} คะแนนเสียง" totalVotes: "{n} คะแนนเสียงทั้งหมด" @@ -2095,17 +2128,17 @@ _poll: showResult: "ดูผลลัพธ์" voted: "โหวตแล้ว" closed: "สิ้นสุดแล้ว" - remainingDays: "จะเสร็จสิ้นในอีก {d} วัน {h} ชั่วโมง" - remainingHours: "{h} ชั่วโมง(s) {m} นาที(s) ที่เหลืออยู่" - remainingMinutes: "{m} นาที(s) {s} วินาที(s) ที่เหลืออยู่" - remainingSeconds: "{s} นาที(s) ที่เหลืออยู่" + remainingDays: "เหลืออีก {d} วัน {h} ชั่วโมง" + remainingHours: "เหลืออีก {h} ชั่วโมง {m} นาที" + remainingMinutes: "เหลืออีก {m} นาที {s} วินาที" + remainingSeconds: "เหลืออีก {s} วินาที" _visibility: public: "สาธารณะ" publicDescription: "โน้ตของคุณจะปรากฏแก่ผู้ใช้ทุกคน" home: "หน้าแรก" homeDescription: "โพสลงไทม์ไลน์ที่บ้านเท่านั้น" followers: "ผู้ติดตาม" - followersDescription: "ทำให้ผู้ติดตามนั้นมองเห็นแค่คุณเท่านั้น" + followersDescription: "เฉพาะผู้ติดตามเท่านั้นที่มองเห็นได้" specified: "ไดเร็ค" specifiedDescription: "ทำให้มองเห็นได้เฉพาะผู้ใช้ที่ระบุเท่านั้น" disableFederation: "ไม่มีสหพันธ์" @@ -2115,11 +2148,11 @@ _postForm: quotePlaceholder: "อ้างโน้ตนี้..." channelPlaceholder: "โพสต์ลงช่อง..." _placeholders: - a: "คุณเป็นอะไรไปหรอ?" - b: "เกิดอะไรขึ้นรอบตัวคุณ?" - c: "คุณกำลังคิดอะไรอยู่?" - d: "คุณต้องการจะพูดอะไร?" - e: "เริ่มเขียน..." + a: "ตอนนี้เป็นยังไงบ้าง?" + b: "มีอะไรเกิดขึ้นหรือเปล่า?" + c: "กำลังคิดอะไรอยู่?" + d: "ต้องการจะพูดอะไรไหม?" + e: "มาเขียนกันเถอะ" f: "กำลังรอให้คุณเขียน..." _profile: name: "ชื่อ" @@ -2133,11 +2166,11 @@ _profile: metadataContent: "เนื้อหา" changeAvatar: "เปลี่ยนอวาตาร์" changeBanner: "เปลี่ยนแบนเนอร์" - verifiedLinkDescription: "โดยการป้อน URL ที่มีลิงก์ไปยังโปรไฟล์ของคุณตรงนี้ ส่วนไอคอนการยืนยันความเป็นเจ้าของนั้นก็สามารถแสดงถัดจากฟิลด์ได้นะ" + verifiedLinkDescription: "หากป้อน URL ที่มีลิงก์ไปยังโปรไฟล์ของคุณ ไอคอนการยืนยันความเป็นเจ้าของจะแสดงถัดจากฟิลด์นั้น ๆ" avatarDecorationMax: "คุณสามารถเพิ่มการตกแต่งได้สูงสุด {max}" _exportOrImport: allNotes: "โน้ตทั้งหมด" - favoritedNotes: "บันทึกที่ชื่นชอบ" + favoritedNotes: "โน้ตที่ถูกใจไว้" clips: "คลิป" followingList: "กำลังติดตาม" muteList: "ปิดเสียง" @@ -2220,7 +2253,7 @@ _pages: summary: "สรุปเพจ" alignCenter: "เซ็นเตอร์" hideTitleWhenPinned: "ซ่อนชื่อหน้าเพจเมื่อปักหมุดไว้ที่โปรไฟล์" - font: "ตัวอักษร" + font: "แบบอักษร" fontSerif: "Serif" fontSansSerif: "Sans Serif" eyeCatchingImageSet: "ตั้งค่าภาพขนาดย่อ" @@ -2246,27 +2279,28 @@ _relayStatus: accepted: "ได้รับการอนุมัติ" rejected: "ถูกปฏิเสธ" _notification: - fileUploaded: "ไฟล์ถูกอัพโหลดแล้วน่ะ" + fileUploaded: "ไฟล์ถูกอัปโหลดแล้ว" youGotMention: "{name} กล่าวถึงคุณ" youGotReply: "{name} ตอบกลับถึงคุณ" - youGotQuote: "{name} อ้างถึงคุณ" + youGotQuote: "{name} อ้างอิงคุณ" youRenoted: "รีโน้ตจาก {name}" youWereFollowed: "ได้ติดตามคุณ" - youReceivedFollowRequest: "คุณมีคำขอติดตามใหม่น่ะ" - yourFollowRequestAccepted: "คำขอติดตามของคุณได้รับการยอมรับแล้วน่ะ" - pollEnded: "โพลสำรวจความคิดเห็นผลลัพธ์มีพร้อมใช้งาน" + youReceivedFollowRequest: "ได้รับคำขอติดตาม" + yourFollowRequestAccepted: "คำขอติดตามได้รับการอนุมัติแล้ว" + pollEnded: "ผลโพลออกมาแล้ว" newNote: "โพสต์ใหม่" unreadAntennaNote: "เสาอากาศ {name}" roleAssigned: "ได้รับบทบาท" - emptyPushNotificationMessage: "การแจ้งเตือนแบบพุชได้รับการอัพเดทแล้ว" + emptyPushNotificationMessage: "อัปเดตการแจ้งเตือนแบบพุชแล้ว" achievementEarned: "รับความสำเร็จ" testNotification: "ทดสอบการแจ้งเตือน" checkNotificationBehavior: "กดเพื่อดูลักษณะการแจ้งเตือน" sendTestNotification: "ส่งทดสอบการแจ้งเตือน" notificationWillBeDisplayedLikeThis: "การแจ้งเตือนมีลักษณะแบบนี้" reactedBySomeUsers: "ถูกรีแอคชั่นโดยผู้ใช้ {n} ราย" - renotedBySomeUsers: "Renote จากผู้ใช้จำนวน {n} ราย" + renotedBySomeUsers: "รีโน้ตจากผู้ใช้ {n} ราย" followedBySomeUsers: "มีผู้ติดตาม {n} ราย" + flushNotification: "ล้างประวัติการแจ้งเตือน" _types: all: "ทั้งหมด" note: "โน้ตใหม่" @@ -2276,9 +2310,9 @@ _notification: renote: "รีโน้ต" quote: "อ้างคำพูด" reaction: "รีแอคชั่น" - pollEnded: "โพลนี้สิ้นสุดลงแล้ว" - receiveFollowRequest: "ได้รับคำขอติดตาม\n" - followRequestAccepted: "ยอมรับคำขอติดตาม" + pollEnded: "โพลสิ้นสุดแล้ว" + receiveFollowRequest: "ได้รับคำร้องขอติดตาม" + followRequestAccepted: "อนุมัติให้ติดตามแล้ว" roleAssigned: "ให้บทบาท" achievementEarned: "ปลดล็อกความสำเร็จแล้ว" app: "การแจ้งเตือนจากแอปที่มีลิงก์" @@ -2315,7 +2349,7 @@ _deck: list: "รายการ" channel: "ช่อง" mentions: "พูดถึง" - direct: "ไดเร็ค" + direct: "ไดเร็กต์" roleTimeline: "บทบาทไทม์ไลน์" _dialog: charactersExceeded: "คุณกำลังมีตัวอักขระเกินขีดจำกัดสูงสุดแล้วนะ! ปัจจุบันอยู่ที่ {current} จาก {max}" @@ -2346,8 +2380,8 @@ _moderationLogTypes: updateRole: "อัปเดตบทบาทแล้ว" assignRole: "ได้รับมอบหมายบทบาท" unassignRole: "ถอดออกจากบทบาทแล้ว" - suspend: "ถูกระงับ" - unsuspend: "เลิกถูกระงับ" + suspend: "ระงับ" + unsuspend: "เลิกระงับ" addCustomEmoji: "เพิ่มเอโมจิที่กำหนดเองแล้ว" updateCustomEmoji: "อัปเดตเอโมจิที่กำหนดเองแล้ว" deleteCustomEmoji: "ลบเอโมจิที่กำหนดเองออกแล้ว" @@ -2362,12 +2396,13 @@ _moderationLogTypes: deleteGlobalAnnouncement: "ลบประกาศทั่วโลกออกแล้ว" deleteUserAnnouncement: "ลบประกาศผู้ใช้ออกแล้ว" resetPassword: "รีเซ็ตรหัสผ่าน" - suspendRemoteInstance: "อินสแตนซ์ระยะไกลถูกระงับ" - unsuspendRemoteInstance: "อินสแตนซ์ระยะไกลเลิกการระงับ" + suspendRemoteInstance: "ระงับอินสแตนซ์ระยะไกล" + unsuspendRemoteInstance: "เลิกระงับอินสแตนซ์ระยะไกล" + updateRemoteInstanceNote: "อัปเดตโน้ตการกลั่นกรองของอินสแตนซ์ระยะไกลแล้ว" markSensitiveDriveFile: "ทำเครื่องหมายไฟล์ว่ามีเนื้อหาละเอียดอ่อน" unmarkSensitiveDriveFile: "ยกเลิกทำเครื่องหมายไฟล์ว่ามีเนื้อหาละเอียดอ่อน" resolveAbuseReport: "รายงานได้รับการแก้ไขแล้ว" - createInvitation: "สร้างคำเชิญ" + createInvitation: "สร้างรหัสเชิญ" createAd: "สร้างโฆษณาแล้ว" deleteAd: "ลบโฆษณาออกแล้ว" updateAd: "อัปเดตโฆษณาแล้ว" @@ -2438,6 +2473,55 @@ _dataSaver: _code: title: "ไฮไลต์โค้ด" description: "หากใช้สัญลักษณ์ไฮไลต์โค้ดใน MFM ฯลฯ สัญลักษณ์เหล่านั้นจะไม่โหลดจนกว่าจะแตะ การไฮไลต์ไวยากรณ์(syntax)จำเป็นต้องดาวน์โหลดไฟล์คำจำกัดความของไฮไลต์สำหรับแต่ละภาษา ดังนั้นการปิดใช้งานการโหลดไฟล์เหล่านี้โดยอัตโนมัติจึงคาดว่าจะช่วยลดปริมาณข้อมูลการสื่อสารได้" +_hemisphere: + N: "ซีกโลกเหนือ" + S: "ซีกโลกใต้" + caption: "ใช้เพื่อกำหนดฤดูกาลของไคลเอ็นต์" _reversi: + reversi: "รีเวอร์ซี" + gameSettings: "ตั้งค่าการเล่น" + chooseBoard: "เลือกกระดาน" + blackOrWhite: "ดำ/ขาว" + blackIs: "{name}เป็นสีดำ" + rules: "กฎ" + thisGameIsStartedSoon: "การเล่นจะเริ่มแล้ว" + waitingForOther: "กำลังรออีกฝ่ายเตรียมตัวให้เสร็จ" + waitingForMe: "กำลังรอฝ่ายคุณเตรียมตัวให้เสร็จ" + waitingBoth: "กรุณาเตรียมตัว" + ready: "เตรียมตัวพร้อมแล้ว" + cancelReady: "ยกเลิกการเตรียมตัวพร้อม" + opponentTurn: "ตาอีกฝ่าย" + myTurn: "ตาของคุณ" + turnOf: "ตาของ{name}" + pastTurnOf: "ตาของ{name}" + surrender: "ยอมแพ้" + surrendered: "ยอมแพ้แล้ว" + timeout: "หมดเวลาแล้ว" + drawn: "เสมอ" + won: "{name}ชนะ" + black: "ดำ" + white: "ขาว" total: "รวมทั้งหมด" + turnCount: "ตาที่{count}" + myGames: "การเล่นของตัวเอง" + allGames: "การเล่นของทุกคน" + ended: "จบ" + playing: "กำลังเล่น" + isLlotheo: "คนที่มีตัวหมากน้อยกว่าชนะ (Roseo)" + loopedMap: "ลูปแมป" + canPutEverywhere: "โหมดที่สามารถวางได้ทุกที่" + timeLimitForEachTurn: "จำกัดเวลาต่อแต่ละตา" + freeMatch: "ฟรีแมตช์" + lookingForPlayer: "กำลังมองหาคู่ต่อสู้อยู่" + gameCanceled: "ยกเลิกการเล่นแล้ว" + shareToTlTheGameWhenStart: "โพสต์ลงไทม์ไลน์เมื่อเริ่มการเล่น" + iStartedAGame: "เริ่มเล่นหมากรีเวอร์ซีแล้ว! #MisskeyReversi" + opponentHasSettingsChanged: "อีกฝ่ายเปลี่ยนการตั้งค่า" + allowIrregularRules: "อนุญาตกฎที่ไม่ปรกติ (โหมดฟรีทุกอย่าง)" + disallowIrregularRules: "ไม่อนุญาตกฎที่ไม่ปรกติ" + showBoardLabels: "แสดงหมายเลขแถว/คอลัมน์บนกระดาน" + useAvatarAsStone: "ใช้รูปอวตารเป็นหมาก" +_offlineScreen: + title: "ออฟไลน์ - ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้" + header: "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 7679ad56d7..df36f43c06 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -911,6 +911,7 @@ youFollowing: "Підписки" icon: "Аватар" replies: "Відповісти" renotes: "Поширити" +sourceCode: "Вихідний код" flip: "Перевернути" lastNDays: "Останні {n} днів" _achievements: diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index 6de15fc11f..59883f4a6c 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -1045,8 +1045,10 @@ loadReplies: "Hiển thị các trả lời" pinnedList: "Các mục đã được ghim" keepScreenOn: "Giữ màn hình luôn bật" verifiedLink: "Chúng tôi đã xác nhận bạn là chủ sở hữu của đường dẫn này" +sourceCode: "Mã nguồn" flip: "Lật" lastNDays: "{n} ngày trước" +surrender: "Từ chối" _announcement: forExistingUsers: "Chỉ những người dùng đã tồn tại" forExistingUsersDescription: "Nếu được bật, thông báo này sẽ chỉ hiển thị với những người dùng đã tồn tại vào lúc thông báo được tạo. Nếu tắt đi, những tài khoản mới đăng ký sau khi thông báo được đăng lên cũng sẽ thấy nó." diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index d14a77f5aa..17ad6e7150 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -11,7 +11,7 @@ password: "密码" forgotPassword: "忘记密码" fetchingAsApObject: "在联邦宇宙查询中..." ok: "OK" -gotIt: "我明白了" +gotIt: "好" cancel: "取消" noThankYou: "不用,谢谢" enterUsername: "输入用户名" @@ -336,7 +336,7 @@ displayOfSensitiveMedia: "显示敏感媒体" whenServerDisconnected: "与服务器连接中断时" disconnectedFromServer: "已和服务器断开连接" reload: "重新加载" -doNothing: "关闭弹窗" +doNothing: "关闭" reloadConfirm: "确定要重新加载吗?" watch: "关注" unwatch: "取消关注" @@ -991,6 +991,7 @@ neverShow: "不再显示" remindMeLater: "稍后提醒我" didYouLikeMisskey: "您喜欢 Misskey 吗?" pleaseDonate: "Misskey 是 {host} 所使用的免费软件。为了今后也能够维持 Misskey 的开发,请在有余力的情况下进行捐助!" +correspondingSourceIsAvailable: "对应的源代码可在{anchor}找到" roles: "角色" role: "角色" noRole: "角色不存在" @@ -1041,6 +1042,9 @@ resetPasswordConfirm: "确定重置密码?" sensitiveWords: "敏感词" sensitiveWordsDescription: "将包含设置词的帖子的可见范围设置为首页。可以通过用换行符分隔来设置多个。" sensitiveWordsDescription2: "AND 条件用空格分隔,正则表达式用斜线包裹。" +prohibitedWords: "禁用词" +prohibitedWordsDescription: "发布包含设定词汇的帖子时将出错。可用换行设定多个关键字" +prohibitedWordsDescription2: "AND 条件用空格分隔,正则表达式用斜线包裹。" hiddenTags: "隐藏标签" hiddenTagsDescription: "设定的标签将不会在时间线上显示。可使用换行来设置多个标签。" notesSearchNotAvailable: "帖子检索不可用" @@ -1113,7 +1117,7 @@ branding: "品牌" enableServerMachineStats: "公开服务器硬件统计信息" enableIdenticonGeneration: "启用生成用户 Identicon" turnOffToImprovePerformance: "关闭该选项可以提高性能。" -createInviteCode: "发行邀请码" +createInviteCode: "生成邀请码" createWithOptions: "使用选项来创建" createCount: "发行数" inviteCodeCreated: "已创建邀请码" @@ -1125,7 +1129,7 @@ noExpirationDate: "不设置有效日期" inviteCodeUsedAt: "邀请码被使用的日期和时间" registeredUserUsingInviteCode: "使用了邀请码的用户" waitingForMailAuth: "等待验证电子邮件" -inviteCodeCreator: "发行邀请码的用户" +inviteCodeCreator: "生成邀请码的用户" usedAt: "使用时间" unused: "未使用" used: "已使用" @@ -1156,6 +1160,7 @@ showRenotes: "显示转帖" edited: "已编辑" notificationRecieveConfig: "通知接收设置" mutualFollow: "互相关注" +followingOrFollower: "关注中或关注者" fileAttachedOnly: "仅限媒体" showRepliesToOthersInTimeline: "在时间线中包含给别人的回复" hideRepliesToOthersInTimeline: "在时间线中隐藏给别人的回复" @@ -1164,6 +1169,13 @@ hideRepliesToOthersInTimelineAll: "在时间线中隐藏现在关注的所有人 confirmShowRepliesAll: "此操作不可撤销。确认要在时间线中包含现在关注的所有人的回复吗?" confirmHideRepliesAll: "此操作不可撤销。确认要在时间线中隐藏现在关注的所有人的回复吗?" externalServices: "外部服务" +sourceCode: "源代码" +sourceCodeIsNotYetProvided: "还未提供源代码。要解决此问题请联系管理员。" +repositoryUrl: "仓库地址" +repositoryUrlDescription: "若源代码所在的仓库是公开的,请填入对应的 URL。若是按原样使用 Misskey(并未追加或者修改代码)的情况请填入 https://github.com/misskey-dev/misskey。" +repositoryUrlOrTarballRequired: "若仓库并未公开,则需要提供 tarball 作为替代。详情请看 .config/example.yml。" +feedback: "反馈" +feedbackUrl: "反馈地址" impressum: "运营商信息" impressumUrl: "运营商信息地址" impressumDescription: "德国等国家和地区有义务展示此类信息(Impressum)。" @@ -1185,6 +1197,7 @@ useGroupedNotifications: "分组显示通知" signupPendingError: "确认电子邮件时出现错误。链接可能已过期。" cwNotationRequired: "在启用「隐藏内容」时必须输入注释" doReaction: "回应" +code: "代码" reloadRequiredToApplySettings: "需要重新载入来使设置生效" remainingN: "剩余:{n}" overwriteContentConfirm: "将覆盖现有内容。确定吗?" @@ -1192,19 +1205,38 @@ seasonalScreenEffect: "应景的画面效果" decorate: "装饰" addMfmFunction: "添加装饰" enableQuickAddMfmFunction: "显示高级 MFM 选择器" +bubbleGame: "泡泡游戏" sfx: "音效" soundWillBePlayed: "声音将会播放" -showReplay: "查看重播" +showReplay: "观看回放" replay: "重播" replaying: "重播中" +endReplay: "结束回放" +copyReplayData: "复制回放数据" ranking: "排行榜" lastNDays: "最近 {n} 天" backToTitle: "返回标题" hemisphere: "居住地区" withSensitive: "显示包含敏感媒体的帖子" +userSaysSomethingSensitive: "含 {name} 敏感文件的帖子" enableHorizontalSwipe: "滑动切换标签页" +loading: "读取中" +surrender: "取消" +gameRetry: "重试" _bubbleGame: howToPlay: "游戏说明" + hold: "抓住" + _score: + score: "得分" + scoreYen: "赚到的钱" + highScore: "最高分" + maxChain: "最高连击数" + yen: "{yen} 日元" + estimatedQty: "约 {qty} 个" + _howToPlay: + section1: "对准位置将Emoji投入盒子。" + section2: "相同的Emoji相互接触合成后会得到新的Emoji,以此获得分数。" + section3: "如果Emoji从箱子中溢出游戏将会结束。在防止Emoji溢出的同时,不断合成新的Emoji,来获取更高的分数吧!" _announcement: forExistingUsers: "仅限现有用户" forExistingUsersDescription: "若启用,该公告将仅对创建此公告时存在的用户可见。 如果禁用,则在创建此公告后注册的用户也可以看到该公告。" @@ -1289,8 +1321,8 @@ _initialTutorial: description: "对于服务器方针所要求要求的,又或者不适合直接展示的附件,请添加「敏感」标记。\n" tryThisFile: "试试看,将附加到此窗口的图像标注为敏感!" _exampleNote: - note: "不该打开纳豆的盖子的……" - method: "要标注附件为敏感内容,请单击该文件以打开菜单,然后单击“设置为敏感”。" + note: "拆纳豆包装时出错了…" + method: "要标注附件为敏感内容,请单击该文件以打开菜单,然后单击“标记为敏感内容”。" sensitiveSucceeded: "附加文件时,请遵循服务器的条款来设置正确敏感设定。\n" doItToContinue: "将图像标记为敏感后才能够继续" _done: @@ -1577,6 +1609,10 @@ _achievements: description: "完成了教学" _bubbleGameExplodingHead: title: "🤯" + description: "你合成出了游戏里最大的Emoji" + _bubbleGameDoubleExplodingHead: + title: "两个🤯" + description: "你合成出了2个游戏里最大的Emoji" _role: new: "创建角色" edit: "编辑角色" @@ -1617,8 +1653,9 @@ _role: gtlAvailable: "查看全局时间线" ltlAvailable: "查看本地时间线" canPublicNote: "允许公开发帖" + mentionMax: "帖子内最多提及数" canInvite: "发放服务器邀请码" - inviteLimit: "可发行邀请码的数量" + inviteLimit: "可生成邀请码的数量" inviteLimitCycle: "邀请码的发行间隔" inviteExpirationTime: "邀请码的有效日期" canManageCustomEmojis: "管理自定义表情符号" @@ -1640,6 +1677,7 @@ _role: canUseTranslator: "使用翻译功能" avatarDecorationLimit: "可添加头像挂件的最大个数" _condition: + roleAssignedTo: "已分配给手动角色" isLocal: "是本地用户" isRemote: "是远程用户" createdLessThan: "账户创建时间少于" @@ -1740,6 +1778,8 @@ _aboutMisskey: contributors: "主要贡献者" allContributors: "全体贡献者" source: "源代码" + original: "原版" + thisIsModifiedVersion: "{name}正在使用修改后的 Misskey。" translation: "翻译 Misskey" donate: "赞助 Misskey" morePatrons: "还有很多其它的人也在支持我们,非常感谢🥰" @@ -2002,7 +2042,7 @@ _permissions: "read:admin:stream": "使用管理员用的 Websocket API" "write:admin:ad": "编辑广告" "read:admin:ad": "查看广告" - "write:invite-codes": "发行邀请码" + "write:invite-codes": "生成邀请码" "read:invite-codes": "获取已发行的邀请码" "write:clip-favorite": "编辑便签的点赞" "read:clip-favorite": "查看便签的点赞" @@ -2258,6 +2298,7 @@ _notification: reactedBySomeUsers: "{n} 人回应了" renotedBySomeUsers: "{n} 人转发了" followedBySomeUsers: "被 {n} 人关注" + flushNotification: "重置通知历史" _types: all: "全部" note: "用户的新帖子" @@ -2355,10 +2396,11 @@ _moderationLogTypes: resetPassword: "重置密码" suspendRemoteInstance: "停止远程服务器" unsuspendRemoteInstance: "恢复远程服务器" + updateRemoteInstanceNote: "更新远程服务器的管理笔记" markSensitiveDriveFile: "标记网盘文件为敏感媒体" unmarkSensitiveDriveFile: "取消标记网盘文件为敏感媒体" resolveAbuseReport: "处理举报" - createInvitation: "发行邀请码" + createInvitation: "生成邀请码" createAd: "创建了广告" deleteAd: "删除了广告" updateAd: "更新了广告" @@ -2435,7 +2477,45 @@ _hemisphere: caption: "在某些客户端设置中用来确定季节" _reversi: reversi: "黑白棋" + gameSettings: "对局设置" + blackOrWhite: "先手/后手" + blackIs: "{name}执黑(先手)" + rules: "规则" + thisGameIsStartedSoon: "对局即将开始" + waitingForOther: "等待对手准备" + waitingForMe: "等待你的准备" + waitingBoth: "请准备" + ready: "准备就绪" + cancelReady: "重新准备" + opponentTurn: "对手的回合" + myTurn: "你的回合" + turnOf: "{name}的回合" + pastTurnOf: "{name}的回合" + surrender: "认输" + surrendered: "已认输" + timeout: "超时" + drawn: "平局" + won: "{name}获胜" + black: "黑" + white: "白" total: "总计" + turnCount: "第{count}回合" + myGames: "我的对局" + allGames: "所有对局" + ended: "结束" + playing: "对局中" + canPutEverywhere: "无限制放置模式" + timeLimitForEachTurn: "1回合的时间限制" + freeMatch: "自由匹配" + lookingForPlayer: "正在寻找对手" + gameCanceled: "对局被取消了" + shareToTlTheGameWhenStart: "开始时在时间线发布对局" + iStartedAGame: "对局开始!#MisskeyReversi" + opponentHasSettingsChanged: "对手更改了设定" + allowIrregularRules: "允许非常规规则(完全自由)" + disallowIrregularRules: "禁止非常规规则" + showBoardLabels: "显示行号和列号" + useAvatarAsStone: "用头像作为棋子" _offlineScreen: title: "离线——无法连接到服务器" header: "无法连接到服务器" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 59f2ed6d2d..5cdecc10ac 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -66,7 +66,7 @@ showMore: "載入更多" showLess: "關閉" youGotNewFollower: "您有新的追隨者" receiveFollowRequest: "您有新的追隨請求" -followRequestAccepted: "追隨請求已接受" +followRequestAccepted: "追隨請求已被接受" mention: "提及" mentions: "提及" directNotes: "私訊" @@ -604,7 +604,7 @@ inboxUrl: "收件夾URL" addedRelays: "已加入的中繼器" serviceworkerInfo: "如要使用推播通知,需要啟用此選項並設定金鑰。" deletedNote: "已刪除的貼文" -invisibleNote: "私密的貼文" +invisibleNote: "私人貼文" enableInfiniteScroll: "啟用自動滾動頁面模式" visibility: "可見性" poll: "票選活動" @@ -991,6 +991,7 @@ neverShow: "不再顯示" remindMeLater: "以後再說" didYouLikeMisskey: "您喜歡 Misskey 嗎?" pleaseDonate: "Misskey 是由 {host} 使用的免費軟體。請贊助我們,讓開發得以持續!" +correspondingSourceIsAvailable: "對應的原始碼可以在 {anchor} 處找到。" roles: "角色" role: "角色" noRole: "沒有角色" @@ -1041,6 +1042,9 @@ resetPasswordConfirm: "重設密碼?" sensitiveWords: "敏感詞" sensitiveWordsDescription: "將含有設定詞彙的貼文可見性設為發送至首頁。可以用換行來進行複數的設定。" sensitiveWordsDescription2: "空格代表「以及」(AND),斜線包圍關鍵字代表使用正規表達式。" +prohibitedWords: "禁語" +prohibitedWordsDescription: "當要發布包含禁語的貼文時,會出現錯誤。可以用換行分隔來設定多個禁語。" +prohibitedWordsDescription2: "空格代表「以及」(AND),斜線包圍關鍵字代表使用正規表達式。" hiddenTags: "隱藏標籤" hiddenTagsDescription: "設定的標籤不會在趨勢中顯示,換行可以設定多個標籤。" notesSearchNotAvailable: "無法使用搜尋貼文功能。" @@ -1156,6 +1160,7 @@ showRenotes: "顯示其他人的轉發貼文" edited: "已編輯" notificationRecieveConfig: "接受通知的設定" mutualFollow: "互相追隨" +followingOrFollower: "追隨中或追隨者" fileAttachedOnly: "顯示包含附件的貼文" showRepliesToOthersInTimeline: "顯示給其他人的回覆" hideRepliesToOthersInTimeline: "在時間軸上隱藏給其他人的回覆" @@ -1164,6 +1169,13 @@ hideRepliesToOthersInTimelineAll: "在時間軸不包含追隨中所有人的回 confirmShowRepliesAll: "進行此操作後無法復原。您真的希望時間軸「包含」您目前追隨的所有人的回覆嗎?" confirmHideRepliesAll: "進行此操作後無法復原。您真的希望時間軸「不包含」您目前追隨的所有人的回覆嗎?" externalServices: "外部服務" +sourceCode: "原始碼" +sourceCodeIsNotYetProvided: "尚未提供原始碼,請洽詢管理員解決這個問題。" +repositoryUrl: "儲存庫 URL" +repositoryUrlDescription: "如果存在可公開取得原始碼的儲存庫,請輸入其 URL。 如果您按原樣使用 Misskey(不對原始碼進行任何更改),請輸入 https://github.com/misskey-dev/misskey。" +repositoryUrlOrTarballRequired: "如果儲存庫不是公開的,則必須提供 tarball。 詳細資訊請參閱 .config/example.yml。" +feedback: "意見回饋" +feedbackUrl: "意見回饋 URL" impressum: "營運者資訊" impressumUrl: "營運者資訊網址" impressumDescription: "在德國與部份地區必須要明確顯示營運者資訊。" @@ -1192,13 +1204,15 @@ overwriteContentConfirm: "確定要覆蓋目前的內容嗎?" seasonalScreenEffect: "隨季節變換畫面的呈現" decorate: "設置頭像裝飾" addMfmFunction: "插入MFM功能語法" -enableQuickAddMfmFunction: "顯示高級MFM選擇器" +enableQuickAddMfmFunction: "顯示高級 MFM 選擇器" bubbleGame: "氣泡遊戲" sfx: "音效" soundWillBePlayed: "將播放音效" showReplay: "觀看重播" replay: "重播" replaying: "重播中" +endReplay: "退出重播" +copyReplayData: "複製重播資料" ranking: "排行榜" lastNDays: "過去 {n} 天" backToTitle: "回到遊戲標題頁" @@ -1206,8 +1220,20 @@ hemisphere: "您居住的地區" withSensitive: "顯示包含敏感檔案的貼文" userSaysSomethingSensitive: "包含 {name} 敏感檔案的貼文" enableHorizontalSwipe: "滑動切換時間軸" +loading: "載入中" +surrender: "退出" +gameRetry: "再試一次" _bubbleGame: howToPlay: "玩法說明" + hold: "保留" + _score: + score: "分數" + scoreYen: "賺取的金額" + highScore: "最高分" + maxChain: "最大結合數" + yen: "{yen} 日圓" + estimatedQty: "{qty}個" + scoreSweets: "飯糰 {onigiriQtyWithUnit}" _howToPlay: section1: "調整位置並將物體放入盒子中。" section2: "當相同類型的物體黏在一起時,它們會變成不同的物體,您就會得到分數。" @@ -1221,7 +1247,7 @@ _announcement: tooManyActiveAnnouncementDescription: "有過多公告可能會影響使用者體驗。請考慮歸檔已結束的公告。" readConfirmTitle: "標記為已讀嗎?" readConfirmText: "閱讀「{title}」的內容並標記為已讀。" - shouldNotBeUsedToPresentPermanentInfo: "由於可能會破壞使用者體驗,尤其是對於新使用者而言,我們建議使用公告來發布有時效性的資訊而不是固定不變的資訊。" + shouldNotBeUsedToPresentPermanentInfo: "為了避免損害新用戶的使用體驗,建議使用公告來發布即時性的訊息,而不是用於固定不變的資訊。" dialogAnnouncementUxWarn: "如果同時有 2 個以上對話方塊形式的公告存在,對於使用者體驗很可能會有不良的影響,因此建議謹慎使用。" silence: "不發送通知" silenceDescription: "啟用此選項後,將不會發送此公告的通知,並且無需將其標記為已讀。" @@ -1611,7 +1637,7 @@ _role: baseRole: "基本角色" useBaseValue: "使用基本角色的值" chooseRoleToAssign: "選擇要指派的角色" - iconUrl: "圖示的URL" + iconUrl: "圖示的 URL" asBadge: "顯示為徽章" descriptionOfAsBadge: "開啟的話,角色圖示會顯示在使用者名稱旁邊。" isExplorable: "讓使用者更容易找到您" @@ -1629,6 +1655,7 @@ _role: gtlAvailable: "瀏覽全域時間軸" ltlAvailable: "瀏覽本地時間軸" canPublicNote: "允許公開貼文" + mentionMax: "貼文內的最大提及數" canInvite: "發行伺服器邀請碼" inviteLimit: "可建立邀請碼的數量" inviteLimitCycle: "邀請碼的發放間隔" @@ -1652,6 +1679,7 @@ _role: canUseTranslator: "使用翻譯功能" avatarDecorationLimit: "頭像裝飾的最大設置量" _condition: + roleAssignedTo: "手動指派角色完成" isLocal: "本地使用者" isRemote: "遠端使用者" createdLessThan: "帳戶加入時間不超過" @@ -1752,6 +1780,8 @@ _aboutMisskey: contributors: "主要貢獻者" allContributors: "全體貢獻人員" source: "原始碼" + original: "原始" + thisIsModifiedVersion: "{name} 使用原始 Misskey 的修改版本。" translation: "翻譯 Misskey" donate: "贊助 Misskey" morePatrons: "還有許許多多幫助我們的其他人,非常感謝你們。 🥰" @@ -2093,7 +2123,7 @@ _poll: deadlineTime: "小時" duration: "時長" votesCount: "{n} 票" - totalVotes: "一共{n}票" + totalVotes: "合計 {n} 票" vote: "投票" showResult: "顯示結果" voted: "已投票" @@ -2270,6 +2300,7 @@ _notification: reactedBySomeUsers: "{n}人做出了反應" renotedBySomeUsers: "{n}人做了轉發" followedBySomeUsers: "被{n}人追隨了" + flushNotification: "重置通知歷史紀錄" _types: all: "全部 " note: "使用者的最新貼文" @@ -2355,7 +2386,7 @@ _moderationLogTypes: updateCustomEmoji: "更新自訂表情符號" deleteCustomEmoji: "刪除自訂表情符號" updateServerSettings: "更新伺服器設定" - updateUserNote: "更新管理筆記" + updateUserNote: "更新了使用者的管理筆記" deleteDriveFile: "刪除檔案" deleteNote: "刪除貼文" createGlobalAnnouncement: "建立全網通知" @@ -2367,6 +2398,7 @@ _moderationLogTypes: resetPassword: "重設密碼" suspendRemoteInstance: "封鎖遠端伺服器" unsuspendRemoteInstance: "解除封鎖遠端伺服器" + updateRemoteInstanceNote: "更新了遠端伺服器的管理筆記" markSensitiveDriveFile: "標記為敏感檔案" unmarkSensitiveDriveFile: "撤銷標記為敏感檔案" resolveAbuseReport: "解決檢舉" @@ -2487,6 +2519,8 @@ _reversi: opponentHasSettingsChanged: "對手更改了設定" allowIrregularRules: "允許異常規則(完全自由)" disallowIrregularRules: "不允許異常規則" + showBoardLabels: "在棋盤上顯示行、列號" + useAvatarAsStone: "用大頭貼當作棋子" _offlineScreen: title: "離線-無法連接伺服器" header: "無法連接伺服器" diff --git a/package.json b/package.json index 77c7b92270..41b865456d 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "misskey", - "version": "2024.2.0-beta.7", + "version": "2024.3.1", "codename": "nasubi", "repository": { "type": "git", "url": "https://github.com/misskey-dev/misskey.git" }, - "packageManager": "pnpm@8.12.1", + "packageManager": "pnpm@8.15.4", "workspaces": [ "packages/frontend", "packages/backend", @@ -21,7 +21,7 @@ "build-assets": "node ./scripts/build-assets.mjs", "build": "pnpm build-pre && pnpm -r build && pnpm build-assets", "build-storybook": "pnpm --filter frontend build-storybook", - "build-misskey-js-with-types": "pnpm --filter backend build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api", + "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api", "start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js", "start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js", "init": "pnpm migrate", @@ -48,21 +48,24 @@ "lodash": "4.17.21" }, "dependencies": { + "cssnano": "6.0.5", "execa": "8.0.1", - "cssnano": "6.0.3", + "fast-glob": "3.3.2", + "ignore-walk": "6.0.4", "js-yaml": "4.1.0", - "postcss": "8.4.33", - "terser": "5.27.0", + "postcss": "8.4.35", + "tar": "6.2.0", + "terser": "5.28.1", "typescript": "5.3.3" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "6.18.1", - "@typescript-eslint/parser": "6.18.1", + "@typescript-eslint/eslint-plugin": "7.1.0", + "@typescript-eslint/parser": "7.1.0", "cross-env": "7.0.3", - "cypress": "13.6.3", - "eslint": "8.56.0", - "start-server-and-test": "2.0.3", - "ncp": "2.0.0" + "cypress": "13.6.6", + "eslint": "8.57.0", + "ncp": "2.0.0", + "start-server-and-test": "2.0.3" }, "optionalDependencies": { "@tensorflow/tfjs-core": "4.4.0" diff --git a/packages/backend/check_connect.js b/packages/backend/check_connect.js index ea988a7f69..d88e649c09 100644 --- a/packages/backend/check_connect.js +++ b/packages/backend/check_connect.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/generate_api_json.js b/packages/backend/generate_api_json.js index 5819c60a5f..4079b3bb0a 100644 --- a/packages/backend/generate_api_json.js +++ b/packages/backend/generate_api_json.js @@ -3,6 +3,6 @@ import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js' import { writeFileSync } from "node:fs"; const config = loadConfig(); -const spec = genOpenapiSpec(config); +const spec = genOpenapiSpec(config, true); writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8'); \ No newline at end of file diff --git a/packages/backend/migration/1000000000000-Init.js b/packages/backend/migration/1000000000000-Init.js index 6f04b52ae1..c06885fd40 100644 --- a/packages/backend/migration/1000000000000-Init.js +++ b/packages/backend/migration/1000000000000-Init.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1556348509290-Pages.js b/packages/backend/migration/1556348509290-Pages.js index 05d801227b..c7542e808c 100644 --- a/packages/backend/migration/1556348509290-Pages.js +++ b/packages/backend/migration/1556348509290-Pages.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1556746559567-UserProfile.js b/packages/backend/migration/1556746559567-UserProfile.js index 7cc1ba0083..13ff6ce6bf 100644 --- a/packages/backend/migration/1556746559567-UserProfile.js +++ b/packages/backend/migration/1556746559567-UserProfile.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1557476068003-PinnedUsers.js b/packages/backend/migration/1557476068003-PinnedUsers.js index 12f0b8fc6a..f2f1deae2f 100644 --- a/packages/backend/migration/1557476068003-PinnedUsers.js +++ b/packages/backend/migration/1557476068003-PinnedUsers.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1557761316509-AddSomeUrls.js b/packages/backend/migration/1557761316509-AddSomeUrls.js index 244f64f8ef..eaf78b85b6 100644 --- a/packages/backend/migration/1557761316509-AddSomeUrls.js +++ b/packages/backend/migration/1557761316509-AddSomeUrls.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1557932705754-ObjectStorageSetting.js b/packages/backend/migration/1557932705754-ObjectStorageSetting.js index 736dcafaac..0e1ef321ab 100644 --- a/packages/backend/migration/1557932705754-ObjectStorageSetting.js +++ b/packages/backend/migration/1557932705754-ObjectStorageSetting.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1558072954435-PageLike.js b/packages/backend/migration/1558072954435-PageLike.js index d9502a6e03..a08f68a0e6 100644 --- a/packages/backend/migration/1558072954435-PageLike.js +++ b/packages/backend/migration/1558072954435-PageLike.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1558103093633-UserGroup.js b/packages/backend/migration/1558103093633-UserGroup.js index b3cc6eb949..f762dc2371 100644 --- a/packages/backend/migration/1558103093633-UserGroup.js +++ b/packages/backend/migration/1558103093633-UserGroup.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1558257926829-UserGroupInvite.js b/packages/backend/migration/1558257926829-UserGroupInvite.js index a87173cdfe..853b52d17d 100644 --- a/packages/backend/migration/1558257926829-UserGroupInvite.js +++ b/packages/backend/migration/1558257926829-UserGroupInvite.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1558266512381-UserListJoining.js b/packages/backend/migration/1558266512381-UserListJoining.js index bc94b7f425..e161d52f12 100644 --- a/packages/backend/migration/1558266512381-UserListJoining.js +++ b/packages/backend/migration/1558266512381-UserListJoining.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1561706992953-webauthn.js b/packages/backend/migration/1561706992953-webauthn.js index fa9b1188ca..4c81035ff1 100644 --- a/packages/backend/migration/1561706992953-webauthn.js +++ b/packages/backend/migration/1561706992953-webauthn.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1561873850023-ChartIndexes.js b/packages/backend/migration/1561873850023-ChartIndexes.js index c7e93ba7b7..3f190ce143 100644 --- a/packages/backend/migration/1561873850023-ChartIndexes.js +++ b/packages/backend/migration/1561873850023-ChartIndexes.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1562422242907-PasswordLessLogin.js b/packages/backend/migration/1562422242907-PasswordLessLogin.js index 3df3a6f5f5..4c0fbbbc9f 100644 --- a/packages/backend/migration/1562422242907-PasswordLessLogin.js +++ b/packages/backend/migration/1562422242907-PasswordLessLogin.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1562444565093-PinnedPage.js b/packages/backend/migration/1562444565093-PinnedPage.js index 329d49bbed..89639399f0 100644 --- a/packages/backend/migration/1562444565093-PinnedPage.js +++ b/packages/backend/migration/1562444565093-PinnedPage.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1562448332510-PageTitleHideOption.js b/packages/backend/migration/1562448332510-PageTitleHideOption.js index e41db08090..70d54aa777 100644 --- a/packages/backend/migration/1562448332510-PageTitleHideOption.js +++ b/packages/backend/migration/1562448332510-PageTitleHideOption.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1562869971568-ModerationLog.js b/packages/backend/migration/1562869971568-ModerationLog.js index 2eb3015d5c..3dd9b22edf 100644 --- a/packages/backend/migration/1562869971568-ModerationLog.js +++ b/packages/backend/migration/1562869971568-ModerationLog.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1563757595828-UsedUsername.js b/packages/backend/migration/1563757595828-UsedUsername.js index 91d9d36b9d..258e5abab2 100644 --- a/packages/backend/migration/1563757595828-UsedUsername.js +++ b/packages/backend/migration/1563757595828-UsedUsername.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1565634203341-room.js b/packages/backend/migration/1565634203341-room.js index c2e5fca863..04c9749c1b 100644 --- a/packages/backend/migration/1565634203341-room.js +++ b/packages/backend/migration/1565634203341-room.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1571220798684-CustomEmojiCategory.js b/packages/backend/migration/1571220798684-CustomEmojiCategory.js index f211af67be..1fc78a65ff 100644 --- a/packages/backend/migration/1571220798684-CustomEmojiCategory.js +++ b/packages/backend/migration/1571220798684-CustomEmojiCategory.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1572760203493-nodeinfo.js b/packages/backend/migration/1572760203493-nodeinfo.js index c281b0b2db..ea7a67bc3e 100644 --- a/packages/backend/migration/1572760203493-nodeinfo.js +++ b/packages/backend/migration/1572760203493-nodeinfo.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1576269851876-TalkFederationId.js b/packages/backend/migration/1576269851876-TalkFederationId.js index 045f9ddb04..c49c716e7a 100644 --- a/packages/backend/migration/1576269851876-TalkFederationId.js +++ b/packages/backend/migration/1576269851876-TalkFederationId.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1576869585998-ProxyRemoteFiles.js b/packages/backend/migration/1576869585998-ProxyRemoteFiles.js index 0dde1ae70c..192dbe3485 100644 --- a/packages/backend/migration/1576869585998-ProxyRemoteFiles.js +++ b/packages/backend/migration/1576869585998-ProxyRemoteFiles.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1579267006611-v12.js b/packages/backend/migration/1579267006611-v12.js index 86f9da7e7a..9267be5630 100644 --- a/packages/backend/migration/1579267006611-v12.js +++ b/packages/backend/migration/1579267006611-v12.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1579270193251-v12-2.js b/packages/backend/migration/1579270193251-v12-2.js index 2593aca573..e2ca9709ea 100644 --- a/packages/backend/migration/1579270193251-v12-2.js +++ b/packages/backend/migration/1579270193251-v12-2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1579282808087-v12-3.js b/packages/backend/migration/1579282808087-v12-3.js index a816b2e82e..4098f041c8 100644 --- a/packages/backend/migration/1579282808087-v12-3.js +++ b/packages/backend/migration/1579282808087-v12-3.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1579544426412-v12-4.js b/packages/backend/migration/1579544426412-v12-4.js index 600dc270a5..1153993f35 100644 --- a/packages/backend/migration/1579544426412-v12-4.js +++ b/packages/backend/migration/1579544426412-v12-4.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1579977526288-v12-5.js b/packages/backend/migration/1579977526288-v12-5.js index 73f3343347..d9e1b48bb2 100644 --- a/packages/backend/migration/1579977526288-v12-5.js +++ b/packages/backend/migration/1579977526288-v12-5.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1579993013959-v12-6.js b/packages/backend/migration/1579993013959-v12-6.js index 5009e0aa88..9c249422a2 100644 --- a/packages/backend/migration/1579993013959-v12-6.js +++ b/packages/backend/migration/1579993013959-v12-6.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1580069531114-v12-7.js b/packages/backend/migration/1580069531114-v12-7.js index ff943ffa6b..ceee6b2031 100644 --- a/packages/backend/migration/1580069531114-v12-7.js +++ b/packages/backend/migration/1580069531114-v12-7.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1580148575182-v12-8.js b/packages/backend/migration/1580148575182-v12-8.js index 20b77b391f..6841dcc38f 100644 --- a/packages/backend/migration/1580148575182-v12-8.js +++ b/packages/backend/migration/1580148575182-v12-8.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1580154400017-v12-9.js b/packages/backend/migration/1580154400017-v12-9.js index f78dc47456..c01d8089d0 100644 --- a/packages/backend/migration/1580154400017-v12-9.js +++ b/packages/backend/migration/1580154400017-v12-9.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1580276619901-v12-10.js b/packages/backend/migration/1580276619901-v12-10.js index 09fa27ae83..be6e467fab 100644 --- a/packages/backend/migration/1580276619901-v12-10.js +++ b/packages/backend/migration/1580276619901-v12-10.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1580331224276-v12-11.js b/packages/backend/migration/1580331224276-v12-11.js index f118c34937..af817a8c8a 100644 --- a/packages/backend/migration/1580331224276-v12-11.js +++ b/packages/backend/migration/1580331224276-v12-11.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1580508795118-v12-12.js b/packages/backend/migration/1580508795118-v12-12.js index 4fba933a08..4bd855f7ab 100644 --- a/packages/backend/migration/1580508795118-v12-12.js +++ b/packages/backend/migration/1580508795118-v12-12.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1580543501339-v12-13.js b/packages/backend/migration/1580543501339-v12-13.js index 9344516309..be76c02163 100644 --- a/packages/backend/migration/1580543501339-v12-13.js +++ b/packages/backend/migration/1580543501339-v12-13.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1580864313253-v12-14.js b/packages/backend/migration/1580864313253-v12-14.js index 5034492a70..f8891a2b66 100644 --- a/packages/backend/migration/1580864313253-v12-14.js +++ b/packages/backend/migration/1580864313253-v12-14.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1581526429287-user-group-invitation.js b/packages/backend/migration/1581526429287-user-group-invitation.js index fc81813807..51703e2ba1 100644 --- a/packages/backend/migration/1581526429287-user-group-invitation.js +++ b/packages/backend/migration/1581526429287-user-group-invitation.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1581695816408-user-group-antenna.js b/packages/backend/migration/1581695816408-user-group-antenna.js index 8a212c092a..e6791ba1a4 100644 --- a/packages/backend/migration/1581695816408-user-group-antenna.js +++ b/packages/backend/migration/1581695816408-user-group-antenna.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1581708415836-drive-user-folder-id-index.js b/packages/backend/migration/1581708415836-drive-user-folder-id-index.js index 6594078db8..28ce4cc142 100644 --- a/packages/backend/migration/1581708415836-drive-user-folder-id-index.js +++ b/packages/backend/migration/1581708415836-drive-user-folder-id-index.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1581979837262-promo.js b/packages/backend/migration/1581979837262-promo.js index 585564a400..707c85fcb3 100644 --- a/packages/backend/migration/1581979837262-promo.js +++ b/packages/backend/migration/1581979837262-promo.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1582019042083-featured-injecttion.js b/packages/backend/migration/1582019042083-featured-injecttion.js index d270006277..f308f0a454 100644 --- a/packages/backend/migration/1582019042083-featured-injecttion.js +++ b/packages/backend/migration/1582019042083-featured-injecttion.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1582210532752-antenna-exclude.js b/packages/backend/migration/1582210532752-antenna-exclude.js index 12eee2364c..9b87e3ff39 100644 --- a/packages/backend/migration/1582210532752-antenna-exclude.js +++ b/packages/backend/migration/1582210532752-antenna-exclude.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1582875306439-note-reaction-length.js b/packages/backend/migration/1582875306439-note-reaction-length.js index a4413c9533..e801d1ac44 100644 --- a/packages/backend/migration/1582875306439-note-reaction-length.js +++ b/packages/backend/migration/1582875306439-note-reaction-length.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1585361548360-miauth.js b/packages/backend/migration/1585361548360-miauth.js index d073fa3d26..d5932c6083 100644 --- a/packages/backend/migration/1585361548360-miauth.js +++ b/packages/backend/migration/1585361548360-miauth.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1585385921215-custom-notification.js b/packages/backend/migration/1585385921215-custom-notification.js index a3336e0eca..35303b99e9 100644 --- a/packages/backend/migration/1585385921215-custom-notification.js +++ b/packages/backend/migration/1585385921215-custom-notification.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1585772678853-ap-url.js b/packages/backend/migration/1585772678853-ap-url.js index f67f5a4542..f978fc80b4 100644 --- a/packages/backend/migration/1585772678853-ap-url.js +++ b/packages/backend/migration/1585772678853-ap-url.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1586624197029-AddObjectStorageUseProxy.js b/packages/backend/migration/1586624197029-AddObjectStorageUseProxy.js index 16f7599b80..fde8629bba 100644 --- a/packages/backend/migration/1586624197029-AddObjectStorageUseProxy.js +++ b/packages/backend/migration/1586624197029-AddObjectStorageUseProxy.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1586641139527-remote-reaction.js b/packages/backend/migration/1586641139527-remote-reaction.js index 666bb42ca6..3e907af5f1 100644 --- a/packages/backend/migration/1586641139527-remote-reaction.js +++ b/packages/backend/migration/1586641139527-remote-reaction.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1586708940386-pageAiScript.js b/packages/backend/migration/1586708940386-pageAiScript.js index 3d0d0ab915..ce5007cea1 100644 --- a/packages/backend/migration/1586708940386-pageAiScript.js +++ b/packages/backend/migration/1586708940386-pageAiScript.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1588044505511-hCaptcha.js b/packages/backend/migration/1588044505511-hCaptcha.js index 22cc6672c5..aeacb653b3 100644 --- a/packages/backend/migration/1588044505511-hCaptcha.js +++ b/packages/backend/migration/1588044505511-hCaptcha.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1589023282116-pubRelay.js b/packages/backend/migration/1589023282116-pubRelay.js index ed010699e1..8739adb733 100644 --- a/packages/backend/migration/1589023282116-pubRelay.js +++ b/packages/backend/migration/1589023282116-pubRelay.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1595075960584-blurhash.js b/packages/backend/migration/1595075960584-blurhash.js index 967676531f..9752625cd2 100644 --- a/packages/backend/migration/1595075960584-blurhash.js +++ b/packages/backend/migration/1595075960584-blurhash.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1595077605646-blurhash-for-avatar-banner.js b/packages/backend/migration/1595077605646-blurhash-for-avatar-banner.js index 7df079ac05..fdff8c633a 100644 --- a/packages/backend/migration/1595077605646-blurhash-for-avatar-banner.js +++ b/packages/backend/migration/1595077605646-blurhash-for-avatar-banner.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1595676934834-instance-icon-url.js b/packages/backend/migration/1595676934834-instance-icon-url.js index 6bccff082b..5f834064c4 100644 --- a/packages/backend/migration/1595676934834-instance-icon-url.js +++ b/packages/backend/migration/1595676934834-instance-icon-url.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1595771249699-word-mute.js b/packages/backend/migration/1595771249699-word-mute.js index cfd0a5ccc1..f4fa1227e3 100644 --- a/packages/backend/migration/1595771249699-word-mute.js +++ b/packages/backend/migration/1595771249699-word-mute.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1595782306083-word-mute2.js b/packages/backend/migration/1595782306083-word-mute2.js index 64acf2b721..3c2062ec07 100644 --- a/packages/backend/migration/1595782306083-word-mute2.js +++ b/packages/backend/migration/1595782306083-word-mute2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1596548170836-channel.js b/packages/backend/migration/1596548170836-channel.js index a26991d4d8..ee6753a476 100644 --- a/packages/backend/migration/1596548170836-channel.js +++ b/packages/backend/migration/1596548170836-channel.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1596786425167-channel2.js b/packages/backend/migration/1596786425167-channel2.js index 4e87b11bb5..9e6ead4378 100644 --- a/packages/backend/migration/1596786425167-channel2.js +++ b/packages/backend/migration/1596786425167-channel2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1597230137744-objectStorageSetPublicRead.js b/packages/backend/migration/1597230137744-objectStorageSetPublicRead.js index 93e6f186d5..bc32d4a052 100644 --- a/packages/backend/migration/1597230137744-objectStorageSetPublicRead.js +++ b/packages/backend/migration/1597230137744-objectStorageSetPublicRead.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1597236229720-IncludingNotificationTypes.js b/packages/backend/migration/1597236229720-IncludingNotificationTypes.js index bda702d999..99686bd70e 100644 --- a/packages/backend/migration/1597236229720-IncludingNotificationTypes.js +++ b/packages/backend/migration/1597236229720-IncludingNotificationTypes.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1597385880794-add-sensitive-index.js b/packages/backend/migration/1597385880794-add-sensitive-index.js index ffb94895d7..a67810880b 100644 --- a/packages/backend/migration/1597385880794-add-sensitive-index.js +++ b/packages/backend/migration/1597385880794-add-sensitive-index.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1597459042300-channel-unread.js b/packages/backend/migration/1597459042300-channel-unread.js index 5b94d8296a..ced9b5265a 100644 --- a/packages/backend/migration/1597459042300-channel-unread.js +++ b/packages/backend/migration/1597459042300-channel-unread.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1597893996136-ChannelNoteIdDescIndex.js b/packages/backend/migration/1597893996136-ChannelNoteIdDescIndex.js index 543e511404..ca4eba385e 100644 --- a/packages/backend/migration/1597893996136-ChannelNoteIdDescIndex.js +++ b/packages/backend/migration/1597893996136-ChannelNoteIdDescIndex.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1600353287890-mutingNotificationTypes.js b/packages/backend/migration/1600353287890-mutingNotificationTypes.js index 4e0b8ad6eb..0996aa21f6 100644 --- a/packages/backend/migration/1600353287890-mutingNotificationTypes.js +++ b/packages/backend/migration/1600353287890-mutingNotificationTypes.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1603094348345-refine-abuse-user-report.js b/packages/backend/migration/1603094348345-refine-abuse-user-report.js index 4e052e07c2..354915b165 100644 --- a/packages/backend/migration/1603094348345-refine-abuse-user-report.js +++ b/packages/backend/migration/1603094348345-refine-abuse-user-report.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1603095701770-refine-abuse-user-report2.js b/packages/backend/migration/1603095701770-refine-abuse-user-report2.js index 2eb205c6e0..75dd3513b5 100644 --- a/packages/backend/migration/1603095701770-refine-abuse-user-report2.js +++ b/packages/backend/migration/1603095701770-refine-abuse-user-report2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1603776877564-instance-theme-color.js b/packages/backend/migration/1603776877564-instance-theme-color.js index 5f83bc14e6..c8ab89ab56 100644 --- a/packages/backend/migration/1603776877564-instance-theme-color.js +++ b/packages/backend/migration/1603776877564-instance-theme-color.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1603781553011-instance-favicon.js b/packages/backend/migration/1603781553011-instance-favicon.js index 758b86408f..7d793d4f1f 100644 --- a/packages/backend/migration/1603781553011-instance-favicon.js +++ b/packages/backend/migration/1603781553011-instance-favicon.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1604821689616-delete-auto-watch.js b/packages/backend/migration/1604821689616-delete-auto-watch.js index 917ef5b10c..8160877038 100644 --- a/packages/backend/migration/1604821689616-delete-auto-watch.js +++ b/packages/backend/migration/1604821689616-delete-auto-watch.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1605408848373-clip-description.js b/packages/backend/migration/1605408848373-clip-description.js index fedc603b3c..77a218791c 100644 --- a/packages/backend/migration/1605408848373-clip-description.js +++ b/packages/backend/migration/1605408848373-clip-description.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1605408971051-comments.js b/packages/backend/migration/1605408971051-comments.js index 8ab16859d2..494bfb7950 100644 --- a/packages/backend/migration/1605408971051-comments.js +++ b/packages/backend/migration/1605408971051-comments.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1605585339718-instance-pinned-pages.js b/packages/backend/migration/1605585339718-instance-pinned-pages.js index e6f3c2a785..15a0cecd19 100644 --- a/packages/backend/migration/1605585339718-instance-pinned-pages.js +++ b/packages/backend/migration/1605585339718-instance-pinned-pages.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1605965516823-instance-images.js b/packages/backend/migration/1605965516823-instance-images.js index 848b53f1ba..9cc2eb4032 100644 --- a/packages/backend/migration/1605965516823-instance-images.js +++ b/packages/backend/migration/1605965516823-instance-images.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1606191203881-no-crawle.js b/packages/backend/migration/1606191203881-no-crawle.js index 5c878f5a24..af04566eaa 100644 --- a/packages/backend/migration/1606191203881-no-crawle.js +++ b/packages/backend/migration/1606191203881-no-crawle.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1607151207216-instance-pinned-clip.js b/packages/backend/migration/1607151207216-instance-pinned-clip.js index 67db39fede..f85c3d42d7 100644 --- a/packages/backend/migration/1607151207216-instance-pinned-clip.js +++ b/packages/backend/migration/1607151207216-instance-pinned-clip.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1607353487793-isExplorable.js b/packages/backend/migration/1607353487793-isExplorable.js index 95ee07e917..e07fe6c306 100644 --- a/packages/backend/migration/1607353487793-isExplorable.js +++ b/packages/backend/migration/1607353487793-isExplorable.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1610277136869-registry.js b/packages/backend/migration/1610277136869-registry.js index c5fe2c5a62..1a10f23590 100644 --- a/packages/backend/migration/1610277136869-registry.js +++ b/packages/backend/migration/1610277136869-registry.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1610277585759-registry2.js b/packages/backend/migration/1610277585759-registry2.js index f734a235b0..46e56279f4 100644 --- a/packages/backend/migration/1610277585759-registry2.js +++ b/packages/backend/migration/1610277585759-registry2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1610283021566-registry3.js b/packages/backend/migration/1610283021566-registry3.js index c94546c732..402040f38b 100644 --- a/packages/backend/migration/1610283021566-registry3.js +++ b/packages/backend/migration/1610283021566-registry3.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1611354329133-followersUri.js b/packages/backend/migration/1611354329133-followersUri.js index 7e5f8c3093..15abb2a9d1 100644 --- a/packages/backend/migration/1611354329133-followersUri.js +++ b/packages/backend/migration/1611354329133-followersUri.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1611397665007-gallery.js b/packages/backend/migration/1611397665007-gallery.js index cd5c39cc10..cbd2b62c56 100644 --- a/packages/backend/migration/1611397665007-gallery.js +++ b/packages/backend/migration/1611397665007-gallery.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1611547387175-objectStorageS3ForcePathStyle.js b/packages/backend/migration/1611547387175-objectStorageS3ForcePathStyle.js index c0b1da1e53..c5440b7a48 100644 --- a/packages/backend/migration/1611547387175-objectStorageS3ForcePathStyle.js +++ b/packages/backend/migration/1611547387175-objectStorageS3ForcePathStyle.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1612619156584-announcement-email.js b/packages/backend/migration/1612619156584-announcement-email.js index f8277725f7..ddacab322b 100644 --- a/packages/backend/migration/1612619156584-announcement-email.js +++ b/packages/backend/migration/1612619156584-announcement-email.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1613155914446-emailNotificationTypes.js b/packages/backend/migration/1613155914446-emailNotificationTypes.js index 3afe491e48..d34ba7e826 100644 --- a/packages/backend/migration/1613155914446-emailNotificationTypes.js +++ b/packages/backend/migration/1613155914446-emailNotificationTypes.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1613181457597-user-lang.js b/packages/backend/migration/1613181457597-user-lang.js index 33e363477f..6ef5245953 100644 --- a/packages/backend/migration/1613181457597-user-lang.js +++ b/packages/backend/migration/1613181457597-user-lang.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1613503367223-use-bigint-for-driveUsage.js b/packages/backend/migration/1613503367223-use-bigint-for-driveUsage.js index 9c75c0ae54..8529ea3247 100644 --- a/packages/backend/migration/1613503367223-use-bigint-for-driveUsage.js +++ b/packages/backend/migration/1613503367223-use-bigint-for-driveUsage.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1615965918224-chart-v2.js b/packages/backend/migration/1615965918224-chart-v2.js index 2c0cacd1d9..deecde7227 100644 --- a/packages/backend/migration/1615965918224-chart-v2.js +++ b/packages/backend/migration/1615965918224-chart-v2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1615966519402-chart-v2-2.js b/packages/backend/migration/1615966519402-chart-v2-2.js index 8d6ebf6a81..7842a27108 100644 --- a/packages/backend/migration/1615966519402-chart-v2-2.js +++ b/packages/backend/migration/1615966519402-chart-v2-2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1618637372000-user-last-active-date.js b/packages/backend/migration/1618637372000-user-last-active-date.js index 8b4652898d..7caf179fa5 100644 --- a/packages/backend/migration/1618637372000-user-last-active-date.js +++ b/packages/backend/migration/1618637372000-user-last-active-date.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1618639857000-user-hide-online-status.js b/packages/backend/migration/1618639857000-user-hide-online-status.js index 1f19a7ebb4..2012962742 100644 --- a/packages/backend/migration/1618639857000-user-hide-online-status.js +++ b/packages/backend/migration/1618639857000-user-hide-online-status.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1619942102890-password-reset.js b/packages/backend/migration/1619942102890-password-reset.js index 9898011774..7784da2bce 100644 --- a/packages/backend/migration/1619942102890-password-reset.js +++ b/packages/backend/migration/1619942102890-password-reset.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1620019354680-ad.js b/packages/backend/migration/1620019354680-ad.js index 1ae66d71f4..7630ed01a1 100644 --- a/packages/backend/migration/1620019354680-ad.js +++ b/packages/backend/migration/1620019354680-ad.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1620364649428-ad2.js b/packages/backend/migration/1620364649428-ad2.js index b9b26be076..7959185685 100644 --- a/packages/backend/migration/1620364649428-ad2.js +++ b/packages/backend/migration/1620364649428-ad2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1621479946000-add-note-indexes.js b/packages/backend/migration/1621479946000-add-note-indexes.js index 299c1f6c02..f72bf8211e 100644 --- a/packages/backend/migration/1621479946000-add-note-indexes.js +++ b/packages/backend/migration/1621479946000-add-note-indexes.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1622679304522-user-profile-description-length.js b/packages/backend/migration/1622679304522-user-profile-description-length.js index 988456fe7d..7324175b46 100644 --- a/packages/backend/migration/1622679304522-user-profile-description-length.js +++ b/packages/backend/migration/1622679304522-user-profile-description-length.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1622681548499-log-message-length.js b/packages/backend/migration/1622681548499-log-message-length.js index e1fa22c88b..b4d8d497e3 100644 --- a/packages/backend/migration/1622681548499-log-message-length.js +++ b/packages/backend/migration/1622681548499-log-message-length.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1626509500668-fix-remote-file-proxy.js b/packages/backend/migration/1626509500668-fix-remote-file-proxy.js index 906e49cabb..9145247ab1 100644 --- a/packages/backend/migration/1626509500668-fix-remote-file-proxy.js +++ b/packages/backend/migration/1626509500668-fix-remote-file-proxy.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1629004542760-chart-reindex.js b/packages/backend/migration/1629004542760-chart-reindex.js index f1d08ecfe4..072cdec3c1 100644 --- a/packages/backend/migration/1629004542760-chart-reindex.js +++ b/packages/backend/migration/1629004542760-chart-reindex.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1629024377804-deepl-integration.js b/packages/backend/migration/1629024377804-deepl-integration.js index 465f1bcca9..5889196f15 100644 --- a/packages/backend/migration/1629024377804-deepl-integration.js +++ b/packages/backend/migration/1629024377804-deepl-integration.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1629288472000-fix-channel-userId.js b/packages/backend/migration/1629288472000-fix-channel-userId.js index 9f946ad550..d7907d05bd 100644 --- a/packages/backend/migration/1629288472000-fix-channel-userId.js +++ b/packages/backend/migration/1629288472000-fix-channel-userId.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1629512953000-user-is-deleted.js b/packages/backend/migration/1629512953000-user-is-deleted.js index 78bbd8bbee..94165e466b 100644 --- a/packages/backend/migration/1629512953000-user-is-deleted.js +++ b/packages/backend/migration/1629512953000-user-is-deleted.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1629778475000-deepl-integration2.js b/packages/backend/migration/1629778475000-deepl-integration2.js index b719dcf57f..a54daf8fb3 100644 --- a/packages/backend/migration/1629778475000-deepl-integration2.js +++ b/packages/backend/migration/1629778475000-deepl-integration2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1629833361000-AddShowTLReplies.js b/packages/backend/migration/1629833361000-AddShowTLReplies.js index 00aef6aeb8..b80e2ef67f 100644 --- a/packages/backend/migration/1629833361000-AddShowTLReplies.js +++ b/packages/backend/migration/1629833361000-AddShowTLReplies.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1629968054000_userInstanceBlocks.js b/packages/backend/migration/1629968054000_userInstanceBlocks.js index e8168e372e..e88fa8aece 100644 --- a/packages/backend/migration/1629968054000_userInstanceBlocks.js +++ b/packages/backend/migration/1629968054000_userInstanceBlocks.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1633068642000-email-required-for-signup.js b/packages/backend/migration/1633068642000-email-required-for-signup.js index 230227d364..d23db2052f 100644 --- a/packages/backend/migration/1633068642000-email-required-for-signup.js +++ b/packages/backend/migration/1633068642000-email-required-for-signup.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1633071909016-user-pending.js b/packages/backend/migration/1633071909016-user-pending.js index f0d037967f..db0f2fde1a 100644 --- a/packages/backend/migration/1633071909016-user-pending.js +++ b/packages/backend/migration/1633071909016-user-pending.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1634486652000-user-public-reactions.js b/packages/backend/migration/1634486652000-user-public-reactions.js index 09870c79c6..ce1818886a 100644 --- a/packages/backend/migration/1634486652000-user-public-reactions.js +++ b/packages/backend/migration/1634486652000-user-public-reactions.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1634902659689-delete-log.js b/packages/backend/migration/1634902659689-delete-log.js index e4e625536b..2e2267f9f4 100644 --- a/packages/backend/migration/1634902659689-delete-log.js +++ b/packages/backend/migration/1634902659689-delete-log.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1635500777168-note-thread-mute.js b/packages/backend/migration/1635500777168-note-thread-mute.js index 9f376c4795..d5fca59594 100644 --- a/packages/backend/migration/1635500777168-note-thread-mute.js +++ b/packages/backend/migration/1635500777168-note-thread-mute.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1636197624383-ff-visibility.js b/packages/backend/migration/1636197624383-ff-visibility.js index aa089d42ac..27faae1c92 100644 --- a/packages/backend/migration/1636197624383-ff-visibility.js +++ b/packages/backend/migration/1636197624383-ff-visibility.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1636697408073-remove-via-mobile.js b/packages/backend/migration/1636697408073-remove-via-mobile.js index c014ceb921..81f0b63443 100644 --- a/packages/backend/migration/1636697408073-remove-via-mobile.js +++ b/packages/backend/migration/1636697408073-remove-via-mobile.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1637320813000-forwarded-report.js b/packages/backend/migration/1637320813000-forwarded-report.js index 0d1f48beb4..8125468aae 100644 --- a/packages/backend/migration/1637320813000-forwarded-report.js +++ b/packages/backend/migration/1637320813000-forwarded-report.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1639325650583-chart-v3.js b/packages/backend/migration/1639325650583-chart-v3.js index e6209e2b70..2255476394 100644 --- a/packages/backend/migration/1639325650583-chart-v3.js +++ b/packages/backend/migration/1639325650583-chart-v3.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1642611822809-emoji-url.js b/packages/backend/migration/1642611822809-emoji-url.js index 212fc957ad..421614b408 100644 --- a/packages/backend/migration/1642611822809-emoji-url.js +++ b/packages/backend/migration/1642611822809-emoji-url.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1642613870898-drive-file-webpublic-type.js b/packages/backend/migration/1642613870898-drive-file-webpublic-type.js index e50770fff3..e61a3fc49e 100644 --- a/packages/backend/migration/1642613870898-drive-file-webpublic-type.js +++ b/packages/backend/migration/1642613870898-drive-file-webpublic-type.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1643963705770-chart-v4.js b/packages/backend/migration/1643963705770-chart-v4.js index af0bd18e58..77355cd7f3 100644 --- a/packages/backend/migration/1643963705770-chart-v4.js +++ b/packages/backend/migration/1643963705770-chart-v4.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1643966656277-chart-v5.js b/packages/backend/migration/1643966656277-chart-v5.js index b3389a6539..54e4705e56 100644 --- a/packages/backend/migration/1643966656277-chart-v5.js +++ b/packages/backend/migration/1643966656277-chart-v5.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1643967331284-chart-v6.js b/packages/backend/migration/1643967331284-chart-v6.js index 1197bdd717..aa64bc9faa 100644 --- a/packages/backend/migration/1643967331284-chart-v6.js +++ b/packages/backend/migration/1643967331284-chart-v6.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644010796173-convert-hard-mutes.js b/packages/backend/migration/1644010796173-convert-hard-mutes.js index 1a5316ac05..9aec21b5ff 100644 --- a/packages/backend/migration/1644010796173-convert-hard-mutes.js +++ b/packages/backend/migration/1644010796173-convert-hard-mutes.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644058404077-chart-v7.js b/packages/backend/migration/1644058404077-chart-v7.js index a850d5f48f..a09fff1bc7 100644 --- a/packages/backend/migration/1644058404077-chart-v7.js +++ b/packages/backend/migration/1644058404077-chart-v7.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644059847460-chart-v8.js b/packages/backend/migration/1644059847460-chart-v8.js index 2e20159ba9..43b95926b6 100644 --- a/packages/backend/migration/1644059847460-chart-v8.js +++ b/packages/backend/migration/1644059847460-chart-v8.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644060125705-chart-v9.js b/packages/backend/migration/1644060125705-chart-v9.js index d1d9469ea2..dc99f3c8f8 100644 --- a/packages/backend/migration/1644060125705-chart-v9.js +++ b/packages/backend/migration/1644060125705-chart-v9.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644073149413-chart-v10.js b/packages/backend/migration/1644073149413-chart-v10.js index 466ae59837..4d36235729 100644 --- a/packages/backend/migration/1644073149413-chart-v10.js +++ b/packages/backend/migration/1644073149413-chart-v10.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644095659741-chart-v11.js b/packages/backend/migration/1644095659741-chart-v11.js index 5c98e25d86..80bacbf710 100644 --- a/packages/backend/migration/1644095659741-chart-v11.js +++ b/packages/backend/migration/1644095659741-chart-v11.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644328606241-chart-v12.js b/packages/backend/migration/1644328606241-chart-v12.js index 2a7272fd22..15c0dd9040 100644 --- a/packages/backend/migration/1644328606241-chart-v12.js +++ b/packages/backend/migration/1644328606241-chart-v12.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644331238153-chart-v13.js b/packages/backend/migration/1644331238153-chart-v13.js index 7e33b0a8e9..0c2db66f27 100644 --- a/packages/backend/migration/1644331238153-chart-v13.js +++ b/packages/backend/migration/1644331238153-chart-v13.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644344266289-chart-v14.js b/packages/backend/migration/1644344266289-chart-v14.js index 2050d54591..0f4688ab77 100644 --- a/packages/backend/migration/1644344266289-chart-v14.js +++ b/packages/backend/migration/1644344266289-chart-v14.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644395759931-instance-theme-color.js b/packages/backend/migration/1644395759931-instance-theme-color.js index ac842e4fe5..fd7356e68a 100644 --- a/packages/backend/migration/1644395759931-instance-theme-color.js +++ b/packages/backend/migration/1644395759931-instance-theme-color.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644481657998-chart-v15.js b/packages/backend/migration/1644481657998-chart-v15.js index ad5589df8b..964bea3d07 100644 --- a/packages/backend/migration/1644481657998-chart-v15.js +++ b/packages/backend/migration/1644481657998-chart-v15.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1644551208096-following-indexes.js b/packages/backend/migration/1644551208096-following-indexes.js index 795b8e900e..8d1d4890dc 100644 --- a/packages/backend/migration/1644551208096-following-indexes.js +++ b/packages/backend/migration/1644551208096-following-indexes.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1645340161439-remove-max-note-text-length.js b/packages/backend/migration/1645340161439-remove-max-note-text-length.js index 84eaeddfa4..1cf6b0801b 100644 --- a/packages/backend/migration/1645340161439-remove-max-note-text-length.js +++ b/packages/backend/migration/1645340161439-remove-max-note-text-length.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1645599900873-federation-chart-pubsub.js b/packages/backend/migration/1645599900873-federation-chart-pubsub.js index 4f9f501cca..3042c8ecd9 100644 --- a/packages/backend/migration/1645599900873-federation-chart-pubsub.js +++ b/packages/backend/migration/1645599900873-federation-chart-pubsub.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1646143552768-instance-default-theme.js b/packages/backend/migration/1646143552768-instance-default-theme.js index 3532916304..8f0755e3a2 100644 --- a/packages/backend/migration/1646143552768-instance-default-theme.js +++ b/packages/backend/migration/1646143552768-instance-default-theme.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1646387162108-mute-expires-at.js b/packages/backend/migration/1646387162108-mute-expires-at.js index 868f5c87ef..412db14881 100644 --- a/packages/backend/migration/1646387162108-mute-expires-at.js +++ b/packages/backend/migration/1646387162108-mute-expires-at.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1646549089451-poll-ended-notification.js b/packages/backend/migration/1646549089451-poll-ended-notification.js index fa7327ff9c..6c481c6ac6 100644 --- a/packages/backend/migration/1646549089451-poll-ended-notification.js +++ b/packages/backend/migration/1646549089451-poll-ended-notification.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1646633030285-chart-federation-active.js b/packages/backend/migration/1646633030285-chart-federation-active.js index b9863746ad..13d54c3180 100644 --- a/packages/backend/migration/1646633030285-chart-federation-active.js +++ b/packages/backend/migration/1646633030285-chart-federation-active.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1646655454495-remove-instance-drive-columns.js b/packages/backend/migration/1646655454495-remove-instance-drive-columns.js index 8fd96ed4c6..04d6fce887 100644 --- a/packages/backend/migration/1646655454495-remove-instance-drive-columns.js +++ b/packages/backend/migration/1646655454495-remove-instance-drive-columns.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1646732390560-chart-federation-active-sub-pub.js b/packages/backend/migration/1646732390560-chart-federation-active-sub-pub.js index 1b28d012ae..289b929ad9 100644 --- a/packages/backend/migration/1646732390560-chart-federation-active-sub-pub.js +++ b/packages/backend/migration/1646732390560-chart-federation-active-sub-pub.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1648548247382-webhook.js b/packages/backend/migration/1648548247382-webhook.js index fc2a691918..f31d3c5bb5 100644 --- a/packages/backend/migration/1648548247382-webhook.js +++ b/packages/backend/migration/1648548247382-webhook.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1648816172177-webhook-2.js b/packages/backend/migration/1648816172177-webhook-2.js index a7bccff82d..4d1b293b2c 100644 --- a/packages/backend/migration/1648816172177-webhook-2.js +++ b/packages/backend/migration/1648816172177-webhook-2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1651224615271-foreign-key.js b/packages/backend/migration/1651224615271-foreign-key.js index 12e4646329..fa51bb5e31 100644 --- a/packages/backend/migration/1651224615271-foreign-key.js +++ b/packages/backend/migration/1651224615271-foreign-key.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1652859567549-uniform-themecolor.js b/packages/backend/migration/1652859567549-uniform-themecolor.js index 422e63dfec..754e089824 100644 --- a/packages/backend/migration/1652859567549-uniform-themecolor.js +++ b/packages/backend/migration/1652859567549-uniform-themecolor.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1655368940105-nsfw-detection.js b/packages/backend/migration/1655368940105-nsfw-detection.js index ad37ff6f83..d2d0d00117 100644 --- a/packages/backend/migration/1655368940105-nsfw-detection.js +++ b/packages/backend/migration/1655368940105-nsfw-detection.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1655371960534-nsfw-detection-2.js b/packages/backend/migration/1655371960534-nsfw-detection-2.js index e6cc266178..e5adbddca4 100644 --- a/packages/backend/migration/1655371960534-nsfw-detection-2.js +++ b/packages/backend/migration/1655371960534-nsfw-detection-2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1655388169582-nsfw-detection-3.js b/packages/backend/migration/1655388169582-nsfw-detection-3.js index 40362cc20c..12fc281327 100644 --- a/packages/backend/migration/1655388169582-nsfw-detection-3.js +++ b/packages/backend/migration/1655388169582-nsfw-detection-3.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1655393015659-nsfw-detection-4.js b/packages/backend/migration/1655393015659-nsfw-detection-4.js index d74fe9c929..39fb175679 100644 --- a/packages/backend/migration/1655393015659-nsfw-detection-4.js +++ b/packages/backend/migration/1655393015659-nsfw-detection-4.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1655813815729-driveCapacityOverrideMb.js b/packages/backend/migration/1655813815729-driveCapacityOverrideMb.js index 7e97f9dc74..e64c8c1b82 100644 --- a/packages/backend/migration/1655813815729-driveCapacityOverrideMb.js +++ b/packages/backend/migration/1655813815729-driveCapacityOverrideMb.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1655918165614-user-ip.js b/packages/backend/migration/1655918165614-user-ip.js index ccb3ceb49d..668c6d909b 100644 --- a/packages/backend/migration/1655918165614-user-ip.js +++ b/packages/backend/migration/1655918165614-user-ip.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1656122560740-file-ip.js b/packages/backend/migration/1656122560740-file-ip.js index dc02df0e68..e5efaf3d9f 100644 --- a/packages/backend/migration/1656122560740-file-ip.js +++ b/packages/backend/migration/1656122560740-file-ip.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1656251734807-nsfw-detection-5.js b/packages/backend/migration/1656251734807-nsfw-detection-5.js index 06da9251b1..9b36bd76eb 100644 --- a/packages/backend/migration/1656251734807-nsfw-detection-5.js +++ b/packages/backend/migration/1656251734807-nsfw-detection-5.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1656328812281-ip-2.js b/packages/backend/migration/1656328812281-ip-2.js index 1b53e697de..39fcd1d83d 100644 --- a/packages/backend/migration/1656328812281-ip-2.js +++ b/packages/backend/migration/1656328812281-ip-2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1656408772602-nsfw-detection-6.js b/packages/backend/migration/1656408772602-nsfw-detection-6.js index 0adc8bb793..efadd22e5d 100644 --- a/packages/backend/migration/1656408772602-nsfw-detection-6.js +++ b/packages/backend/migration/1656408772602-nsfw-detection-6.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1656772790599-user-moderation-note.js b/packages/backend/migration/1656772790599-user-moderation-note.js index 63a993851f..ef2f0f6522 100644 --- a/packages/backend/migration/1656772790599-user-moderation-note.js +++ b/packages/backend/migration/1656772790599-user-moderation-note.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1657346559800-active-email-validation.js b/packages/backend/migration/1657346559800-active-email-validation.js index 44b1f3f4fa..e8d5b29cdf 100644 --- a/packages/backend/migration/1657346559800-active-email-validation.js +++ b/packages/backend/migration/1657346559800-active-email-validation.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1664694635394-turnstile.js b/packages/backend/migration/1664694635394-turnstile.js index 3ec6da9136..a9baf4c657 100644 --- a/packages/backend/migration/1664694635394-turnstile.js +++ b/packages/backend/migration/1664694635394-turnstile.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1665091090561-add-renote-muting.js b/packages/backend/migration/1665091090561-add-renote-muting.js index a22d7037f3..5748572517 100644 --- a/packages/backend/migration/1665091090561-add-renote-muting.js +++ b/packages/backend/migration/1665091090561-add-renote-muting.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1669138716634-whetherPushNotifyToSendReadMessage.js b/packages/backend/migration/1669138716634-whetherPushNotifyToSendReadMessage.js index a317468ac9..431241897d 100644 --- a/packages/backend/migration/1669138716634-whetherPushNotifyToSendReadMessage.js +++ b/packages/backend/migration/1669138716634-whetherPushNotifyToSendReadMessage.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1671924750884-RetentionAggregation.js b/packages/backend/migration/1671924750884-RetentionAggregation.js index 5057bf1060..67079bb7a1 100644 --- a/packages/backend/migration/1671924750884-RetentionAggregation.js +++ b/packages/backend/migration/1671924750884-RetentionAggregation.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1671926422832-RetentionAggregation2.js b/packages/backend/migration/1671926422832-RetentionAggregation2.js index 665e24d721..f26e0f7d2e 100644 --- a/packages/backend/migration/1671926422832-RetentionAggregation2.js +++ b/packages/backend/migration/1671926422832-RetentionAggregation2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1672562400597-PerUserPvChart.js b/packages/backend/migration/1672562400597-PerUserPvChart.js index 1fbe1eb14a..844f665a8b 100644 --- a/packages/backend/migration/1672562400597-PerUserPvChart.js +++ b/packages/backend/migration/1672562400597-PerUserPvChart.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1672703171386-remove-latestRequestSentAt.js b/packages/backend/migration/1672703171386-remove-latestRequestSentAt.js index f053e5c20c..fa73fc8977 100644 --- a/packages/backend/migration/1672703171386-remove-latestRequestSentAt.js +++ b/packages/backend/migration/1672703171386-remove-latestRequestSentAt.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js b/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js index b71f7e1306..abf209162b 100644 --- a/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js +++ b/packages/backend/migration/1672704017999-remove-lastCommunicatedAt.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1672704136584-remove-latestStatus.js b/packages/backend/migration/1672704136584-remove-latestStatus.js index f08ed96a45..d75344c053 100644 --- a/packages/backend/migration/1672704136584-remove-latestStatus.js +++ b/packages/backend/migration/1672704136584-remove-latestStatus.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1672822262496-Flash.js b/packages/backend/migration/1672822262496-Flash.js index e45055b3cc..fd3f77d893 100644 --- a/packages/backend/migration/1672822262496-Flash.js +++ b/packages/backend/migration/1672822262496-Flash.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1673336077243-PollChoiceLength.js b/packages/backend/migration/1673336077243-PollChoiceLength.js index 8c4a5007e4..7bd65149d6 100644 --- a/packages/backend/migration/1673336077243-PollChoiceLength.js +++ b/packages/backend/migration/1673336077243-PollChoiceLength.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1673500412259-Role.js b/packages/backend/migration/1673500412259-Role.js index 2bf6a7f4e8..6bfb31e08e 100644 --- a/packages/backend/migration/1673500412259-Role.js +++ b/packages/backend/migration/1673500412259-Role.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1673515526953-RoleColor.js b/packages/backend/migration/1673515526953-RoleColor.js index 693dcfb0b6..b856e4183b 100644 --- a/packages/backend/migration/1673515526953-RoleColor.js +++ b/packages/backend/migration/1673515526953-RoleColor.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1673522856499-RoleIroiro.js b/packages/backend/migration/1673522856499-RoleIroiro.js index 10a6eef162..40635e50d8 100644 --- a/packages/backend/migration/1673522856499-RoleIroiro.js +++ b/packages/backend/migration/1673522856499-RoleIroiro.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1673524604156-RoleLastUsedAt.js b/packages/backend/migration/1673524604156-RoleLastUsedAt.js index 5bbd0c39ac..3bbb8000d8 100644 --- a/packages/backend/migration/1673524604156-RoleLastUsedAt.js +++ b/packages/backend/migration/1673524604156-RoleLastUsedAt.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1673570377815-RoleConditional.js b/packages/backend/migration/1673570377815-RoleConditional.js index d2b25d121e..354fd6c66a 100644 --- a/packages/backend/migration/1673570377815-RoleConditional.js +++ b/packages/backend/migration/1673570377815-RoleConditional.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1673575973645-MetaClean.js b/packages/backend/migration/1673575973645-MetaClean.js index 7671785d94..684d62e8e9 100644 --- a/packages/backend/migration/1673575973645-MetaClean.js +++ b/packages/backend/migration/1673575973645-MetaClean.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1673783015567-Policies.js b/packages/backend/migration/1673783015567-Policies.js index 4f76752c9f..8674306620 100644 --- a/packages/backend/migration/1673783015567-Policies.js +++ b/packages/backend/migration/1673783015567-Policies.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1673812883772-firstRetrievedAt.js b/packages/backend/migration/1673812883772-firstRetrievedAt.js index 82990e30b6..4111cc4ad0 100644 --- a/packages/backend/migration/1673812883772-firstRetrievedAt.js +++ b/packages/backend/migration/1673812883772-firstRetrievedAt.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1674086433654-flashScriptLength.js b/packages/backend/migration/1674086433654-flashScriptLength.js index 996fe8c691..cdfb812ba0 100644 --- a/packages/backend/migration/1674086433654-flashScriptLength.js +++ b/packages/backend/migration/1674086433654-flashScriptLength.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1674118260469-achievement.js b/packages/backend/migration/1674118260469-achievement.js index 5d79dc669e..072cf81ec3 100644 --- a/packages/backend/migration/1674118260469-achievement.js +++ b/packages/backend/migration/1674118260469-achievement.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1674255666603-loggedInDates.js b/packages/backend/migration/1674255666603-loggedInDates.js index a6cf4b400f..a2a217da95 100644 --- a/packages/backend/migration/1674255666603-loggedInDates.js +++ b/packages/backend/migration/1674255666603-loggedInDates.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1675053125067-fixforeignkeyreports.js b/packages/backend/migration/1675053125067-fixforeignkeyreports.js index d24dc5ec5a..2ca383f563 100644 --- a/packages/backend/migration/1675053125067-fixforeignkeyreports.js +++ b/packages/backend/migration/1675053125067-fixforeignkeyreports.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1675404035646-cleanup.js b/packages/backend/migration/1675404035646-cleanup.js index c4e4332bbc..5cd5f5534a 100644 --- a/packages/backend/migration/1675404035646-cleanup.js +++ b/packages/backend/migration/1675404035646-cleanup.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1675557528704-role-icon-badge.js b/packages/backend/migration/1675557528704-role-icon-badge.js index ee39c07a51..48684075d1 100644 --- a/packages/backend/migration/1675557528704-role-icon-badge.js +++ b/packages/backend/migration/1675557528704-role-icon-badge.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1676434944993-drop-group.js b/packages/backend/migration/1676434944993-drop-group.js index 1db2d5818f..2df8a2d789 100644 --- a/packages/backend/migration/1676434944993-drop-group.js +++ b/packages/backend/migration/1676434944993-drop-group.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1676438468213-ad3.js b/packages/backend/migration/1676438468213-ad3.js index 8347f56b95..83ca5828e3 100644 --- a/packages/backend/migration/1676438468213-ad3.js +++ b/packages/backend/migration/1676438468213-ad3.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1677054292210-ad4.js b/packages/backend/migration/1677054292210-ad4.js index 037e21059c..11c42dd354 100644 --- a/packages/backend/migration/1677054292210-ad4.js +++ b/packages/backend/migration/1677054292210-ad4.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1677570181236-role-assignment-expires-at.js b/packages/backend/migration/1677570181236-role-assignment-expires-at.js index e44bca1d20..6fe32ffeb0 100644 --- a/packages/backend/migration/1677570181236-role-assignment-expires-at.js +++ b/packages/backend/migration/1677570181236-role-assignment-expires-at.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1678164627293-per-note-reaction-acceptance.js b/packages/backend/migration/1678164627293-per-note-reaction-acceptance.js index c85aafbd4c..44c807499c 100644 --- a/packages/backend/migration/1678164627293-per-note-reaction-acceptance.js +++ b/packages/backend/migration/1678164627293-per-note-reaction-acceptance.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1678426061773-tweak-varchar-length.js b/packages/backend/migration/1678426061773-tweak-varchar-length.js index 2541f99a19..74c4fd6715 100644 --- a/packages/backend/migration/1678426061773-tweak-varchar-length.js +++ b/packages/backend/migration/1678426061773-tweak-varchar-length.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1678427401214-remove-unused.js b/packages/backend/migration/1678427401214-remove-unused.js index 59f42da080..e398b3700c 100644 --- a/packages/backend/migration/1678427401214-remove-unused.js +++ b/packages/backend/migration/1678427401214-remove-unused.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1678602320354-role-display-order.js b/packages/backend/migration/1678602320354-role-display-order.js index 0ab7b0c3e2..d3cc9792ca 100644 --- a/packages/backend/migration/1678602320354-role-display-order.js +++ b/packages/backend/migration/1678602320354-role-display-order.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1678694614599-sensitive-words.js b/packages/backend/migration/1678694614599-sensitive-words.js index 5f69424eca..13361f597e 100644 --- a/packages/backend/migration/1678694614599-sensitive-words.js +++ b/packages/backend/migration/1678694614599-sensitive-words.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1678869617549-retention-date-key.js b/packages/backend/migration/1678869617549-retention-date-key.js index 55bf6248e6..1b995385b0 100644 --- a/packages/backend/migration/1678869617549-retention-date-key.js +++ b/packages/backend/migration/1678869617549-retention-date-key.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1678945242650-add-props-for-custom-emoji.js b/packages/backend/migration/1678945242650-add-props-for-custom-emoji.js index 0054e78f88..5d1218be12 100644 --- a/packages/backend/migration/1678945242650-add-props-for-custom-emoji.js +++ b/packages/backend/migration/1678945242650-add-props-for-custom-emoji.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1678953978856-clip-favorite.js b/packages/backend/migration/1678953978856-clip-favorite.js index 13145497bb..9d706c4dae 100644 --- a/packages/backend/migration/1678953978856-clip-favorite.js +++ b/packages/backend/migration/1678953978856-clip-favorite.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1679309757174-antenna-active.js b/packages/backend/migration/1679309757174-antenna-active.js index 0b2bcc69ff..dadea25a7c 100644 --- a/packages/backend/migration/1679309757174-antenna-active.js +++ b/packages/backend/migration/1679309757174-antenna-active.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1679639483253-enableChartsForRemoteUser.js b/packages/backend/migration/1679639483253-enableChartsForRemoteUser.js index 68576064f2..f2a13100e2 100644 --- a/packages/backend/migration/1679639483253-enableChartsForRemoteUser.js +++ b/packages/backend/migration/1679639483253-enableChartsForRemoteUser.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1679651580149-cleanup.js b/packages/backend/migration/1679651580149-cleanup.js index 7049891cf0..efee339c46 100644 --- a/packages/backend/migration/1679651580149-cleanup.js +++ b/packages/backend/migration/1679651580149-cleanup.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1679652081809-enableChartsForFederatedInstances.js b/packages/backend/migration/1679652081809-enableChartsForFederatedInstances.js index f3a07cbd1d..67be10e6fd 100644 --- a/packages/backend/migration/1679652081809-enableChartsForFederatedInstances.js +++ b/packages/backend/migration/1679652081809-enableChartsForFederatedInstances.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1680228513388-channelFavorite.js b/packages/backend/migration/1680228513388-channelFavorite.js index 58eb7359f2..866173305e 100644 --- a/packages/backend/migration/1680228513388-channelFavorite.js +++ b/packages/backend/migration/1680228513388-channelFavorite.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1680238118084-channelNotePining.js b/packages/backend/migration/1680238118084-channelNotePining.js index f1f192d7bb..78bafc0237 100644 --- a/packages/backend/migration/1680238118084-channelNotePining.js +++ b/packages/backend/migration/1680238118084-channelNotePining.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1680491187535-cleanup.js b/packages/backend/migration/1680491187535-cleanup.js index 006b403bd1..f0b1bccdab 100644 --- a/packages/backend/migration/1680491187535-cleanup.js +++ b/packages/backend/migration/1680491187535-cleanup.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1680582195041-cleanup.js b/packages/backend/migration/1680582195041-cleanup.js index 7d941be8cf..83d04b6186 100644 --- a/packages/backend/migration/1680582195041-cleanup.js +++ b/packages/backend/migration/1680582195041-cleanup.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1680702787050-UserMemo.js b/packages/backend/migration/1680702787050-UserMemo.js index 104d66ce24..3f7afe8657 100644 --- a/packages/backend/migration/1680702787050-UserMemo.js +++ b/packages/backend/migration/1680702787050-UserMemo.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1680775031481-avatar-url-and-banner-url.js b/packages/backend/migration/1680775031481-avatar-url-and-banner-url.js index c613ee511e..49295e70eb 100644 --- a/packages/backend/migration/1680775031481-avatar-url-and-banner-url.js +++ b/packages/backend/migration/1680775031481-avatar-url-and-banner-url.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1680931179228-account-move.js b/packages/backend/migration/1680931179228-account-move.js index 203d838f57..a8b5e4df68 100644 --- a/packages/backend/migration/1680931179228-account-move.js +++ b/packages/backend/migration/1680931179228-account-move.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1681400427971-serverRules.js b/packages/backend/migration/1681400427971-serverRules.js index 70a74ebfff..176783b50a 100644 --- a/packages/backend/migration/1681400427971-serverRules.js +++ b/packages/backend/migration/1681400427971-serverRules.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1681870960239-RoleTLSetting.js b/packages/backend/migration/1681870960239-RoleTLSetting.js index 07b9bc4e35..2999051a3b 100644 --- a/packages/backend/migration/1681870960239-RoleTLSetting.js +++ b/packages/backend/migration/1681870960239-RoleTLSetting.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1682190963894-movedAt.js b/packages/backend/migration/1682190963894-movedAt.js index cc33da8747..852cf58969 100644 --- a/packages/backend/migration/1682190963894-movedAt.js +++ b/packages/backend/migration/1682190963894-movedAt.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1682754135458-preservedUsernames.js b/packages/backend/migration/1682754135458-preservedUsernames.js index 61723e4abd..8aae3c2054 100644 --- a/packages/backend/migration/1682754135458-preservedUsernames.js +++ b/packages/backend/migration/1682754135458-preservedUsernames.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1682985520254-channelColor.js b/packages/backend/migration/1682985520254-channelColor.js index 43f1f48334..3c7f3101a5 100644 --- a/packages/backend/migration/1682985520254-channelColor.js +++ b/packages/backend/migration/1682985520254-channelColor.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1683328299359-channelArchive.js b/packages/backend/migration/1683328299359-channelArchive.js index 759dcbfdae..10a87246de 100644 --- a/packages/backend/migration/1683328299359-channelArchive.js +++ b/packages/backend/migration/1683328299359-channelArchive.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1683682889948-prevent-ai-larning.js b/packages/backend/migration/1683682889948-prevent-ai-larning.js index 1dc3eec21f..167c9f71d2 100644 --- a/packages/backend/migration/1683682889948-prevent-ai-larning.js +++ b/packages/backend/migration/1683682889948-prevent-ai-larning.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1683683083083-public-reactions-default-true.js b/packages/backend/migration/1683683083083-public-reactions-default-true.js index 32cbe33b2f..f416e5ffa7 100644 --- a/packages/backend/migration/1683683083083-public-reactions-default-true.js +++ b/packages/backend/migration/1683683083083-public-reactions-default-true.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1683789676867-fix-typo.js b/packages/backend/migration/1683789676867-fix-typo.js index 5cd686e2f1..d647d20e62 100644 --- a/packages/backend/migration/1683789676867-fix-typo.js +++ b/packages/backend/migration/1683789676867-fix-typo.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1683847157541-UserList.js b/packages/backend/migration/1683847157541-UserList.js index f9e79a43a1..14a52d64f8 100644 --- a/packages/backend/migration/1683847157541-UserList.js +++ b/packages/backend/migration/1683847157541-UserList.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1683869758873-UserListFavorites.js b/packages/backend/migration/1683869758873-UserListFavorites.js index aef4597a75..aae4056845 100644 --- a/packages/backend/migration/1683869758873-UserListFavorites.js +++ b/packages/backend/migration/1683869758873-UserListFavorites.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1684206886988-remove-showTimelineReplies.js b/packages/backend/migration/1684206886988-remove-showTimelineReplies.js index a0798f85c6..398f9f0803 100644 --- a/packages/backend/migration/1684206886988-remove-showTimelineReplies.js +++ b/packages/backend/migration/1684206886988-remove-showTimelineReplies.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1684386446061-emoji-improve.js b/packages/backend/migration/1684386446061-emoji-improve.js index 7bded84cc9..e7e94769b8 100644 --- a/packages/backend/migration/1684386446061-emoji-improve.js +++ b/packages/backend/migration/1684386446061-emoji-improve.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1685973839966-errorImageUrl.js b/packages/backend/migration/1685973839966-errorImageUrl.js index c4a1567b9b..ca685ef088 100644 --- a/packages/backend/migration/1685973839966-errorImageUrl.js +++ b/packages/backend/migration/1685973839966-errorImageUrl.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1688280713783-add-meta-options.js b/packages/backend/migration/1688280713783-add-meta-options.js index ade8378c00..77d1934925 100644 --- a/packages/backend/migration/1688280713783-add-meta-options.js +++ b/packages/backend/migration/1688280713783-add-meta-options.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1688720440658-refactor-invite-system.js b/packages/backend/migration/1688720440658-refactor-invite-system.js index 20f178612d..ea192a1950 100644 --- a/packages/backend/migration/1688720440658-refactor-invite-system.js +++ b/packages/backend/migration/1688720440658-refactor-invite-system.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1688880985544-add-index-to-relations.js b/packages/backend/migration/1688880985544-add-index-to-relations.js index 6daac20329..c18903641c 100644 --- a/packages/backend/migration/1688880985544-add-index-to-relations.js +++ b/packages/backend/migration/1688880985544-add-index-to-relations.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1689102832143-nsfw-cache.js b/packages/backend/migration/1689102832143-nsfw-cache.js index 419588296e..90d453418b 100644 --- a/packages/backend/migration/1689102832143-nsfw-cache.js +++ b/packages/backend/migration/1689102832143-nsfw-cache.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1690782653311-SensitiveChannel.js b/packages/backend/migration/1690782653311-SensitiveChannel.js index e76dda5180..afec1a2153 100644 --- a/packages/backend/migration/1690782653311-SensitiveChannel.js +++ b/packages/backend/migration/1690782653311-SensitiveChannel.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1690796169261-play-visibility.js b/packages/backend/migration/1690796169261-play-visibility.js index c57fa7a109..5e5843bfee 100644 --- a/packages/backend/migration/1690796169261-play-visibility.js +++ b/packages/backend/migration/1690796169261-play-visibility.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1691959191872-passkey-support.js b/packages/backend/migration/1691959191872-passkey-support.js index 55b571d60d..1da9bdb363 100644 --- a/packages/backend/migration/1691959191872-passkey-support.js +++ b/packages/backend/migration/1691959191872-passkey-support.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1694850832075-server-icons-and-manifest.js b/packages/backend/migration/1694850832075-server-icons-and-manifest.js index 1bd8979d9b..235bf05744 100644 --- a/packages/backend/migration/1694850832075-server-icons-and-manifest.js +++ b/packages/backend/migration/1694850832075-server-icons-and-manifest.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1694915420864-clipped-count.js b/packages/backend/migration/1694915420864-clipped-count.js index 1ad8e04ce0..6d70aaecf1 100644 --- a/packages/backend/migration/1694915420864-clipped-count.js +++ b/packages/backend/migration/1694915420864-clipped-count.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1695944637565-notificationRecieveConfig.js b/packages/backend/migration/1695944637565-notificationRecieveConfig.js index 42d3dce5d6..04a40993c0 100644 --- a/packages/backend/migration/1695944637565-notificationRecieveConfig.js +++ b/packages/backend/migration/1695944637565-notificationRecieveConfig.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1696003580220-AddSomeUrls.js b/packages/backend/migration/1696003580220-AddSomeUrls.js index 683aa5eeed..213e39e7af 100644 --- a/packages/backend/migration/1696003580220-AddSomeUrls.js +++ b/packages/backend/migration/1696003580220-AddSomeUrls.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1696222183852-withReplies.js b/packages/backend/migration/1696222183852-withReplies.js index 9f65d5f6a1..84a5511d17 100644 --- a/packages/backend/migration/1696222183852-withReplies.js +++ b/packages/backend/migration/1696222183852-withReplies.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1696373953614-meta-cache-settings.js b/packages/backend/migration/1696373953614-meta-cache-settings.js index f994b76ef2..cbbe471d45 100644 --- a/packages/backend/migration/1696373953614-meta-cache-settings.js +++ b/packages/backend/migration/1696373953614-meta-cache-settings.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1696388600237-revert-note-edit.js b/packages/backend/migration/1696388600237-revert-note-edit.js index 83bc552c35..d353c851db 100644 --- a/packages/backend/migration/1696388600237-revert-note-edit.js +++ b/packages/backend/migration/1696388600237-revert-note-edit.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1696405744672-clean-up.js b/packages/backend/migration/1696405744672-clean-up.js index 5ec89b08f4..4e1ee6cd61 100644 --- a/packages/backend/migration/1696405744672-clean-up.js +++ b/packages/backend/migration/1696405744672-clean-up.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1696569742153-clean-up.js b/packages/backend/migration/1696569742153-clean-up.js index de48fab5aa..b7c981bab2 100644 --- a/packages/backend/migration/1696569742153-clean-up.js +++ b/packages/backend/migration/1696569742153-clean-up.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1696581429196-clean-up.js b/packages/backend/migration/1696581429196-clean-up.js index da69b4e9de..b6723f3430 100644 --- a/packages/backend/migration/1696581429196-clean-up.js +++ b/packages/backend/migration/1696581429196-clean-up.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1696743032098-AdsOnStream.js b/packages/backend/migration/1696743032098-AdsOnStream.js index c86ee84883..43b9f83e66 100644 --- a/packages/backend/migration/1696743032098-AdsOnStream.js +++ b/packages/backend/migration/1696743032098-AdsOnStream.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1696807733453-userListUserId.js b/packages/backend/migration/1696807733453-userListUserId.js index ab2ba07fb5..8f0ae2cd87 100644 --- a/packages/backend/migration/1696807733453-userListUserId.js +++ b/packages/backend/migration/1696807733453-userListUserId.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1696808725134-userListUserId-2.js b/packages/backend/migration/1696808725134-userListUserId-2.js index 5bcb5aedc2..cc504e761c 100644 --- a/packages/backend/migration/1696808725134-userListUserId-2.js +++ b/packages/backend/migration/1696808725134-userListUserId-2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1697247230117-InstanceSilence.js b/packages/backend/migration/1697247230117-InstanceSilence.js index 5fdbca3b27..309d817087 100644 --- a/packages/backend/migration/1697247230117-InstanceSilence.js +++ b/packages/backend/migration/1697247230117-InstanceSilence.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1697420555911-deleteCreatedAt.js b/packages/backend/migration/1697420555911-deleteCreatedAt.js index 958d61a348..407a5f449a 100644 --- a/packages/backend/migration/1697420555911-deleteCreatedAt.js +++ b/packages/backend/migration/1697420555911-deleteCreatedAt.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1697436246389-antenna-localOnly.js b/packages/backend/migration/1697436246389-antenna-localOnly.js index 0228673291..d7c0ca6510 100644 --- a/packages/backend/migration/1697436246389-antenna-localOnly.js +++ b/packages/backend/migration/1697436246389-antenna-localOnly.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1697441463087-FollowRequestWithReplies.js b/packages/backend/migration/1697441463087-FollowRequestWithReplies.js index 214c6f6680..58b61aff63 100644 --- a/packages/backend/migration/1697441463087-FollowRequestWithReplies.js +++ b/packages/backend/migration/1697441463087-FollowRequestWithReplies.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1697673894459-note-reactionAndUserPairCache.js b/packages/backend/migration/1697673894459-note-reactionAndUserPairCache.js index fe0ea282d2..fab07fd3f4 100644 --- a/packages/backend/migration/1697673894459-note-reactionAndUserPairCache.js +++ b/packages/backend/migration/1697673894459-note-reactionAndUserPairCache.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1697847397844-avatar-decoration.js b/packages/backend/migration/1697847397844-avatar-decoration.js index 1f22139746..32ee47e968 100644 --- a/packages/backend/migration/1697847397844-avatar-decoration.js +++ b/packages/backend/migration/1697847397844-avatar-decoration.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1697941908548-avatar-decoration2.js b/packages/backend/migration/1697941908548-avatar-decoration2.js index 9d15c1c3d0..58344e2bb6 100644 --- a/packages/backend/migration/1697941908548-avatar-decoration2.js +++ b/packages/backend/migration/1697941908548-avatar-decoration2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1698041201306-enable-ftt.js b/packages/backend/migration/1698041201306-enable-ftt.js index 6769ed53b5..c67dda6f5f 100644 --- a/packages/backend/migration/1698041201306-enable-ftt.js +++ b/packages/backend/migration/1698041201306-enable-ftt.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1698840138000-add-allow-renote-to-external.js b/packages/backend/migration/1698840138000-add-allow-renote-to-external.js index 0edf298841..8ce35b0f69 100644 --- a/packages/backend/migration/1698840138000-add-allow-renote-to-external.js +++ b/packages/backend/migration/1698840138000-add-allow-renote-to-external.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1699141698112-announcement-silence.js b/packages/backend/migration/1699141698112-announcement-silence.js index eef9b076fc..f462d30b51 100644 --- a/packages/backend/migration/1699141698112-announcement-silence.js +++ b/packages/backend/migration/1699141698112-announcement-silence.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1700096812223-enableFanoutTimelineDbFallback.js b/packages/backend/migration/1700096812223-enableFanoutTimelineDbFallback.js index 94fa588985..2ab93624ce 100644 --- a/packages/backend/migration/1700096812223-enableFanoutTimelineDbFallback.js +++ b/packages/backend/migration/1700096812223-enableFanoutTimelineDbFallback.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1700303245007-supportVerifyMailApi.js b/packages/backend/migration/1700303245007-supportVerifyMailApi.js index 3ac59ec37a..58ff7a69c4 100644 --- a/packages/backend/migration/1700303245007-supportVerifyMailApi.js +++ b/packages/backend/migration/1700303245007-supportVerifyMailApi.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1700902349231-add-bday-index.js b/packages/backend/migration/1700902349231-add-bday-index.js index 251526fc26..c58165c70e 100644 --- a/packages/backend/migration/1700902349231-add-bday-index.js +++ b/packages/backend/migration/1700902349231-add-bday-index.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1702718871541-ffVisibility.js b/packages/backend/migration/1702718871541-ffVisibility.js index e9e820c897..164af00f25 100644 --- a/packages/backend/migration/1702718871541-ffVisibility.js +++ b/packages/backend/migration/1702718871541-ffVisibility.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1703209889304-bannedEmailDomains.js b/packages/backend/migration/1703209889304-bannedEmailDomains.js index 5dc99c138f..2fdd4e1183 100644 --- a/packages/backend/migration/1703209889304-bannedEmailDomains.js +++ b/packages/backend/migration/1703209889304-bannedEmailDomains.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1703658526000-supportTrueMailApi.js b/packages/backend/migration/1703658526000-supportTrueMailApi.js index 0054d54122..fb62653e40 100644 --- a/packages/backend/migration/1703658526000-supportTrueMailApi.js +++ b/packages/backend/migration/1703658526000-supportTrueMailApi.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1704373210054-support-mcaptcha.js b/packages/backend/migration/1704373210054-support-mcaptcha.js index ce42b90716..50b4801e14 100644 --- a/packages/backend/migration/1704373210054-support-mcaptcha.js +++ b/packages/backend/migration/1704373210054-support-mcaptcha.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1704959805077-bubble-game-record.js b/packages/backend/migration/1704959805077-bubble-game-record.js index cc45b09c82..6c4d7ab1a9 100644 --- a/packages/backend/migration/1704959805077-bubble-game-record.js +++ b/packages/backend/migration/1704959805077-bubble-game-record.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1705222772858-optimize-note-index-for-array-column.js b/packages/backend/migration/1705222772858-optimize-note-index-for-array-column.js index 571bd8e8f3..fe0a5a2bcf 100644 --- a/packages/backend/migration/1705222772858-optimize-note-index-for-array-column.js +++ b/packages/backend/migration/1705222772858-optimize-note-index-for-array-column.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1705475608437-reversi.js b/packages/backend/migration/1705475608437-reversi.js index c9d69e2c7c..9921728457 100644 --- a/packages/backend/migration/1705475608437-reversi.js +++ b/packages/backend/migration/1705475608437-reversi.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1705654039457-reversi-2.js b/packages/backend/migration/1705654039457-reversi-2.js index 33747ba9f7..6685dca73b 100644 --- a/packages/backend/migration/1705654039457-reversi-2.js +++ b/packages/backend/migration/1705654039457-reversi-2.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1705793785675-reversi-3.js b/packages/backend/migration/1705793785675-reversi-3.js index 2faf9ae6d5..94b1e4fac9 100644 --- a/packages/backend/migration/1705793785675-reversi-3.js +++ b/packages/backend/migration/1705793785675-reversi-3.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1705794768153-reversi-4.js b/packages/backend/migration/1705794768153-reversi-4.js index 5b7bacb21e..95119cabba 100644 --- a/packages/backend/migration/1705794768153-reversi-4.js +++ b/packages/backend/migration/1705794768153-reversi-4.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1705798904141-reversi-5.js b/packages/backend/migration/1705798904141-reversi-5.js index 7ca7221604..f1a1a42d46 100644 --- a/packages/backend/migration/1705798904141-reversi-5.js +++ b/packages/backend/migration/1705798904141-reversi-5.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1706081514499-reversi-6.js b/packages/backend/migration/1706081514499-reversi-6.js index de870be446..0d9e5cbbf2 100644 --- a/packages/backend/migration/1706081514499-reversi-6.js +++ b/packages/backend/migration/1706081514499-reversi-6.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/migration/1706791962000-fix-meta-disableRegistration.js b/packages/backend/migration/1706791962000-fix-meta-disableRegistration.js new file mode 100644 index 0000000000..1c45f3756d --- /dev/null +++ b/packages/backend/migration/1706791962000-fix-meta-disableRegistration.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class FixMetaDisableRegistration1706791962000 { + name = 'FixMetaDisableRegistration1706791962000' + + async up(queryRunner) { + await queryRunner.query(`alter table meta alter column "disableRegistration" set default true;`); + } + + async down(queryRunner) { + await queryRunner.query(`alter table meta alter column "disableRegistration" set default false;`); + } +} diff --git a/packages/backend/migration/1707429690000-prohibited-words.js b/packages/backend/migration/1707429690000-prohibited-words.js new file mode 100644 index 0000000000..44e96cb160 --- /dev/null +++ b/packages/backend/migration/1707429690000-prohibited-words.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class prohibitedWords1707429690000 { + name = 'prohibitedWords1707429690000' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "prohibitedWords" character varying(1024) array NOT NULL DEFAULT '{}'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "prohibitedWords"`); + } +} diff --git a/packages/backend/migration/1707808106310-MakeRepositoryUrlNullable.js b/packages/backend/migration/1707808106310-MakeRepositoryUrlNullable.js new file mode 100644 index 0000000000..335b14976c --- /dev/null +++ b/packages/backend/migration/1707808106310-MakeRepositoryUrlNullable.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class MakeRepositoryUrlNullable1707808106310 { + name = 'MakeRepositoryUrlNullable1707808106310' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" DROP NOT NULL`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET NOT NULL`); + } +} diff --git a/packages/backend/migration/1708266695091-repositoryUrl-from-syuilo-to-misskey-dev.js b/packages/backend/migration/1708266695091-repositoryUrl-from-syuilo-to-misskey-dev.js new file mode 100644 index 0000000000..e4dbaa16d0 --- /dev/null +++ b/packages/backend/migration/1708266695091-repositoryUrl-from-syuilo-to-misskey-dev.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class RepositoryUrlFromSyuiloToMisskeyDev1708266695091 { + name = 'RepositoryUrlFromSyuiloToMisskeyDev1708266695091' + + async up(queryRunner) { + await queryRunner.query(`UPDATE "meta" SET "repositoryUrl" = 'https://github.com/misskey-dev/misskey' WHERE "repositoryUrl" = 'https://github.com/syuilo/misskey'`); + } + + async down(queryRunner) { + // no valid down migration + } +} diff --git a/packages/backend/migration/1708399372194-per-instance-mod-note.js b/packages/backend/migration/1708399372194-per-instance-mod-note.js new file mode 100644 index 0000000000..339a4d7af9 --- /dev/null +++ b/packages/backend/migration/1708399372194-per-instance-mod-note.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class PerInstanceModNote1708399372194 { + name = 'PerInstanceModNote1708399372194' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" ADD "moderationNote" character varying(16384) NOT NULL DEFAULT ''`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "moderationNote"`); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index 9551991b34..8680610441 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -67,9 +67,9 @@ "dependencies": { "@aws-sdk/client-s3": "3.412.0", "@aws-sdk/lib-storage": "3.412.0", - "@bull-board/api": "5.10.2", - "@bull-board/fastify": "5.10.2", - "@bull-board/ui": "5.10.2", + "@bull-board/api": "5.14.2", + "@bull-board/fastify": "5.14.2", + "@bull-board/ui": "5.14.2", "@discordapp/twemoji": "15.0.2", "@fastify/accepts": "4.3.0", "@fastify/cookie": "9.3.1", @@ -79,17 +79,17 @@ "@fastify/multipart": "8.1.0", "@fastify/static": "6.12.0", "@fastify/view": "8.2.0", - "@misskey-dev/sharp-read-bmp": "^1.1.1", - "@misskey-dev/summaly": "^5.0.3", - "@nestjs/common": "10.2.10", - "@nestjs/core": "10.2.10", - "@nestjs/testing": "10.2.10", + "@misskey-dev/sharp-read-bmp": "1.2.0", + "@misskey-dev/summaly": "5.0.3", + "@nestjs/common": "10.3.3", + "@nestjs/core": "10.3.3", + "@nestjs/testing": "10.3.3", "@peertube/http-signature": "1.7.0", - "@simplewebauthn/server": "9.0.0", + "@simplewebauthn/server": "9.0.3", "@sinonjs/fake-timers": "11.2.2", "@smithy/node-http-handler": "2.1.10", "@swc/cli": "0.1.63", - "@swc/core": "1.3.105", + "@swc/core": "1.3.107", "@twemoji/parser": "15.0.0", "accepts": "1.3.8", "ajv": "8.12.0", @@ -98,12 +98,12 @@ "bcryptjs": "2.4.3", "blurhash": "2.0.5", "body-parser": "1.20.2", - "bullmq": "5.1.4", + "bullmq": "5.4.0", "cacheable-lookup": "7.0.0", - "cbor": "9.0.1", + "cbor": "9.0.2", "chalk": "5.3.0", "chalk-template": "1.1.0", - "chokidar": "3.5.3", + "chokidar": "3.6.0", "cli-highlight": "2.1.11", "color-convert": "2.0.1", "content-disposition": "0.5.4", @@ -115,10 +115,11 @@ "file-type": "19.0.0", "fluent-ffmpeg": "2.1.2", "form-data": "4.0.0", - "got": "14.0.0", + "got": "14.2.0", "happy-dom": "10.0.3", "hpagent": "1.2.0", - "http-link-header": "1.1.1", + "htmlescape": "1.1.1", + "http-link-header": "1.1.2", "ioredis": "5.3.2", "ip-cidr": "3.1.0", "ipaddr.js": "2.1.0", @@ -127,7 +128,7 @@ "jsdom": "23.2.0", "json5": "2.2.3", "jsonld": "8.3.2", - "jsrsasign": "11.0.0", + "jsrsasign": "11.1.0", "meilisearch": "0.37.0", "mfm-js": "0.24.0", "microformats-parser": "2.0.2", @@ -135,10 +136,10 @@ "misskey-js": "workspace:*", "misskey-reversi": "workspace:*", "ms": "3.0.0-canary.1", - "nanoid": "5.0.4", + "nanoid": "5.0.6", "nested-property": "4.0.0", "node-fetch": "3.3.2", - "nodemailer": "6.9.8", + "nodemailer": "6.9.10", "nsfwjs": "2.4.2", "oauth": "0.10.0", "oauth2orize": "1.12.0", @@ -147,7 +148,7 @@ "otpauth": "9.2.2", "parse5": "7.1.2", "pg": "8.11.3", - "pkce-challenge": "4.0.1", + "pkce-challenge": "4.1.0", "probe-image-size": "7.2.3", "promise-limit": "2.7.0", "pug": "3.0.2", @@ -158,22 +159,22 @@ "ratelimiter": "3.4.1", "re2": "1.20.9", "redis-lock": "0.1.4", - "reflect-metadata": "0.1.14", + "reflect-metadata": "0.2.1", "rename": "1.0.4", "rss-parser": "3.13.0", "rxjs": "7.8.1", - "sanitize-html": "2.11.0", + "sanitize-html": "2.12.1", "secure-json-parse": "2.7.0", - "sharp": "0.32.6", + "sharp": "0.33.2", "slacc": "0.0.10", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", - "systeminformation": "5.21.23", + "systeminformation": "5.22.0", "tinycolor2": "1.6.0", - "tmp": "0.2.1", + "tmp": "0.2.2", "tsc-alias": "1.8.8", "tsconfig-paths": "4.2.0", - "typeorm": "0.3.19", + "typeorm": "0.3.20", "typescript": "5.3.3", "ulid": "2.3.0", "vary": "1.1.2", @@ -184,17 +185,17 @@ "devDependencies": { "@jest/globals": "29.7.0", "@misskey-dev/eslint-plugin": "1.0.0", - "@nestjs/platform-express": "10.3.0", - "@simplewebauthn/typescript-types": "8.3.4", + "@nestjs/platform-express": "10.3.3", + "@simplewebauthn/types": "9.0.1", "@swc/jest": "0.2.31", "@types/accepts": "1.3.7", "@types/archiver": "6.0.2", "@types/bcryptjs": "2.4.6", "@types/body-parser": "1.19.5", - "@types/cbor": "6.0.0", "@types/color-convert": "2.0.3", "@types/content-disposition": "0.5.8", "@types/fluent-ffmpeg": "2.1.24", + "@types/htmlescape": "^1.1.3", "@types/http-link-header": "1.0.5", "@types/jest": "29.5.11", "@types/js-yaml": "4.0.9", @@ -203,22 +204,21 @@ "@types/jsrsasign": "10.5.12", "@types/mime-types": "2.1.4", "@types/ms": "0.7.34", - "@types/node": "20.11.5", + "@types/node": "20.11.22", "@types/node-fetch": "3.0.3", "@types/nodemailer": "6.4.14", "@types/oauth": "0.9.4", "@types/oauth2orize": "1.11.3", "@types/oauth2orize-pkce": "0.1.2", - "@types/pg": "8.10.9", + "@types/pg": "8.11.2", "@types/pug": "2.0.10", - "@types/punycode": "2.1.3", + "@types/punycode": "2.1.4", "@types/qrcode": "1.5.5", "@types/random-seed": "0.3.5", "@types/ratelimiter": "3.4.6", "@types/rename": "1.0.7", - "@types/sanitize-html": "2.9.5", - "@types/semver": "7.5.6", - "@types/sharp": "0.32.0", + "@types/sanitize-html": "2.11.0", + "@types/semver": "7.5.8", "@types/simple-oauth2": "5.0.7", "@types/sinonjs__fake-timers": "8.1.5", "@types/tinycolor2": "1.4.6", @@ -226,17 +226,17 @@ "@types/vary": "1.1.3", "@types/web-push": "3.6.3", "@types/ws": "8.5.10", - "@typescript-eslint/eslint-plugin": "6.18.1", - "@typescript-eslint/parser": "6.18.1", + "@typescript-eslint/eslint-plugin": "7.1.0", + "@typescript-eslint/parser": "7.1.0", "aws-sdk-client-mock": "3.0.1", "cross-env": "7.0.3", - "eslint": "8.56.0", + "eslint": "8.57.0", "eslint-plugin-import": "2.29.1", "execa": "8.0.1", "fkill": "^9.0.0", "jest": "29.7.0", "jest-mock": "29.7.0", - "nodemon": "3.0.3", + "nodemon": "3.1.0", "pid-port": "1.0.0", "simple-oauth2": "5.0.0" } diff --git a/packages/backend/src/@types/hcaptcha.d.ts b/packages/backend/src/@types/hcaptcha.d.ts index 43e67dd340..e11dda4662 100644 --- a/packages/backend/src/@types/hcaptcha.d.ts +++ b/packages/backend/src/@types/hcaptcha.d.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/@types/http-signature.d.ts b/packages/backend/src/@types/http-signature.d.ts index 1f3b48aa54..75b62e55f0 100644 --- a/packages/backend/src/@types/http-signature.d.ts +++ b/packages/backend/src/@types/http-signature.d.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/@types/os-utils.d.ts b/packages/backend/src/@types/os-utils.d.ts index 8c44232c14..8943edddd1 100644 --- a/packages/backend/src/@types/os-utils.d.ts +++ b/packages/backend/src/@types/os-utils.d.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/@types/package.json.d.ts b/packages/backend/src/@types/package.json.d.ts index 197b4b6bf0..52a2b356db 100644 --- a/packages/backend/src/@types/package.json.d.ts +++ b/packages/backend/src/@types/package.json.d.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/@types/probe-image-size.d.ts b/packages/backend/src/@types/probe-image-size.d.ts index 4d312cba34..538836475c 100644 --- a/packages/backend/src/@types/probe-image-size.d.ts +++ b/packages/backend/src/@types/probe-image-size.d.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/@types/redis-lock.d.ts b/packages/backend/src/@types/redis-lock.d.ts index c607d600d8..b037cde5ee 100644 --- a/packages/backend/src/@types/redis-lock.d.ts +++ b/packages/backend/src/@types/redis-lock.d.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/GlobalModule.ts b/packages/backend/src/GlobalModule.ts index c83845b94c..09971e8ca0 100644 --- a/packages/backend/src/GlobalModule.ts +++ b/packages/backend/src/GlobalModule.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/MainModule.ts b/packages/backend/src/MainModule.ts index 90aba0cc91..f86a0be93c 100644 --- a/packages/backend/src/MainModule.ts +++ b/packages/backend/src/MainModule.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/NestLogger.ts b/packages/backend/src/NestLogger.ts index e18e9e88a7..80f1f7a024 100644 --- a/packages/backend/src/NestLogger.ts +++ b/packages/backend/src/NestLogger.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/boot/common.ts b/packages/backend/src/boot/common.ts index df10ab1e3d..268c07582d 100644 --- a/packages/backend/src/boot/common.ts +++ b/packages/backend/src/boot/common.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/boot/entry.ts b/packages/backend/src/boot/entry.ts index fc8fc2ffb4..6b8e83d4f9 100644 --- a/packages/backend/src/boot/entry.ts +++ b/packages/backend/src/boot/entry.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index 623cc964ac..30f9477ccf 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/boot/worker.ts b/packages/backend/src/boot/worker.ts index 0399c9fe5c..d4a7cd56e5 100644 --- a/packages/backend/src/boot/worker.ts +++ b/packages/backend/src/boot/worker.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index b25554b229..0ca1fa55c1 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -57,6 +57,8 @@ type Source = { scope?: 'local' | 'global' | string[]; }; + publishTarballInsteadOfProvideRepositoryUrl?: boolean; + proxy?: string; proxySmtp?: string; proxyBypassHosts?: string[]; @@ -74,10 +76,10 @@ type Source = { deliverJobConcurrency?: number; inboxJobConcurrency?: number; - relashionshipJobConcurrency?: number; + relationshipJobConcurrency?: number; deliverJobPerSec?: number; inboxJobPerSec?: number; - relashionshipJobPerSec?: number; + relationshipJobPerSec?: number; deliverJobMaxAttempts?: number; inboxJobMaxAttempts?: number; @@ -135,16 +137,17 @@ export type Config = { outgoingAddressFamily: 'ipv4' | 'ipv6' | 'dual' | undefined; deliverJobConcurrency: number | undefined; inboxJobConcurrency: number | undefined; - relashionshipJobConcurrency: number | undefined; + relationshipJobConcurrency: number | undefined; deliverJobPerSec: number | undefined; inboxJobPerSec: number | undefined; - relashionshipJobPerSec: number | undefined; + relationshipJobPerSec: number | undefined; deliverJobMaxAttempts: number | undefined; inboxJobMaxAttempts: number | undefined; proxyRemoteFiles: boolean | undefined; signToActivityPubGet: boolean | undefined; version: string; + publishTarballInsteadOfProvideRepositoryUrl: boolean; host: string; hostname: string; scheme: string; @@ -209,6 +212,7 @@ export function loadConfig(): Config { return { version, + publishTarballInsteadOfProvideRepositoryUrl: !!config.publishTarballInsteadOfProvideRepositoryUrl, url: url.origin, port: config.port ?? parseInt(process.env.PORT ?? '', 10), socket: config.socket, @@ -241,10 +245,10 @@ export function loadConfig(): Config { outgoingAddressFamily: config.outgoingAddressFamily, deliverJobConcurrency: config.deliverJobConcurrency, inboxJobConcurrency: config.inboxJobConcurrency, - relashionshipJobConcurrency: config.relashionshipJobConcurrency, + relationshipJobConcurrency: config.relationshipJobConcurrency, deliverJobPerSec: config.deliverJobPerSec, inboxJobPerSec: config.inboxJobPerSec, - relashionshipJobPerSec: config.relashionshipJobPerSec, + relationshipJobPerSec: config.relationshipJobPerSec, deliverJobMaxAttempts: config.deliverJobMaxAttempts, inboxJobMaxAttempts: config.inboxJobMaxAttempts, proxyRemoteFiles: config.proxyRemoteFiles, diff --git a/packages/backend/src/const.ts b/packages/backend/src/const.ts index 716a8de382..a238f4973a 100644 --- a/packages/backend/src/const.ts +++ b/packages/backend/src/const.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/AccountMoveService.ts b/packages/backend/src/core/AccountMoveService.ts index 350aa6ba24..5bd885df40 100644 --- a/packages/backend/src/core/AccountMoveService.ts +++ b/packages/backend/src/core/AccountMoveService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -20,7 +20,6 @@ import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { CacheService } from '@/core/CacheService.js'; import { ProxyAccountService } from '@/core/ProxyAccountService.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; import { MetaService } from '@/core/MetaService.js'; @@ -60,7 +59,6 @@ export class AccountMoveService { private instanceChart: InstanceChart, private metaService: MetaService, private relayService: RelayService, - private cacheService: CacheService, private queueService: QueueService, ) { } @@ -84,7 +82,7 @@ export class AccountMoveService { Object.assign(src, update); // Update cache - this.cacheService.uriPersonCache.set(srcUri, src); + this.globalEventService.publishInternalEvent('localUserUpdated', src); const srcPerson = await this.apRendererService.renderPerson(src); const updateAct = this.apRendererService.addContext(this.apRendererService.renderUpdate(srcPerson, src)); @@ -96,7 +94,7 @@ export class AccountMoveService { await this.apDeliverManagerService.deliverToFollowers(src, moveAct); // Publish meUpdated event - const iObj = await this.userEntityService.pack(src.id, src, { detail: true, includeSecrets: true }); + const iObj = await this.userEntityService.pack(src.id, src, { schema: 'MeDetailed', includeSecrets: true }); this.globalEventService.publishMainStream(src.id, 'meUpdated', iObj); // Unfollow after 24 hours diff --git a/packages/backend/src/core/AccountUpdateService.ts b/packages/backend/src/core/AccountUpdateService.ts index 664700ea6b..69a57b4854 100644 --- a/packages/backend/src/core/AccountUpdateService.ts +++ b/packages/backend/src/core/AccountUpdateService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/AchievementService.ts b/packages/backend/src/core/AchievementService.ts index a28b68ee86..4fc1193f32 100644 --- a/packages/backend/src/core/AchievementService.ts +++ b/packages/backend/src/core/AchievementService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/AiService.ts b/packages/backend/src/core/AiService.ts index 4e876495a6..ad852fdd6e 100644 --- a/packages/backend/src/core/AiService.ts +++ b/packages/backend/src/core/AiService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts index 8c348e595d..b298a70929 100644 --- a/packages/backend/src/core/AnnouncementService.ts +++ b/packages/backend/src/core/AnnouncementService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index 2959153070..4f956a43ed 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/AppLockService.ts b/packages/backend/src/core/AppLockService.ts index 7a1293a6de..bd2749cb87 100644 --- a/packages/backend/src/core/AppLockService.ts +++ b/packages/backend/src/core/AppLockService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/AvatarDecorationService.ts b/packages/backend/src/core/AvatarDecorationService.ts index e97946f9dc..21e31d79a4 100644 --- a/packages/backend/src/core/AvatarDecorationService.ts +++ b/packages/backend/src/core/AvatarDecorationService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/CacheService.ts b/packages/backend/src/core/CacheService.ts index e1413342b1..d008e7ec52 100644 --- a/packages/backend/src/core/CacheService.ts +++ b/packages/backend/src/core/CacheService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -16,10 +16,10 @@ import type { OnApplicationShutdown } from '@nestjs/common'; @Injectable() export class CacheService implements OnApplicationShutdown { - public userByIdCache: MemoryKVCache; - public localUserByNativeTokenCache: MemoryKVCache; + public userByIdCache: MemoryKVCache; + public localUserByNativeTokenCache: MemoryKVCache; public localUserByIdCache: MemoryKVCache; - public uriPersonCache: MemoryKVCache; + public uriPersonCache: MemoryKVCache; public userProfileCache: RedisKVCache; public userMutingsCache: RedisKVCache>; public userBlockingCache: RedisKVCache>; @@ -56,41 +56,10 @@ export class CacheService implements OnApplicationShutdown { ) { //this.onMessage = this.onMessage.bind(this); - const localUserByIdCache = new MemoryKVCache(1000 * 60 * 60 * 6 /* 6h */); - this.localUserByIdCache = localUserByIdCache; - - // ローカルユーザーならlocalUserByIdCacheにデータを追加し、こちらにはid(文字列)だけを追加する - const userByIdCache = new MemoryKVCache(1000 * 60 * 60 * 6 /* 6h */, { - toMapConverter: user => { - if (user.host === null) { - localUserByIdCache.set(user.id, user as MiLocalUser); - return user.id; - } - - return user; - }, - fromMapConverter: userOrId => typeof userOrId === 'string' ? localUserByIdCache.get(userOrId) : userOrId, - }); - this.userByIdCache = userByIdCache; - - this.localUserByNativeTokenCache = new MemoryKVCache(Infinity, { - toMapConverter: user => { - if (user === null) return null; - - localUserByIdCache.set(user.id, user); - return user.id; - }, - fromMapConverter: id => id === null ? null : localUserByIdCache.get(id), - }); - this.uriPersonCache = new MemoryKVCache(Infinity, { - toMapConverter: user => { - if (user === null) return null; - - userByIdCache.set(user.id, user); - return user.id; - }, - fromMapConverter: id => id === null ? null : userByIdCache.get(id), - }); + this.userByIdCache = new MemoryKVCache(Infinity); + this.localUserByNativeTokenCache = new MemoryKVCache(Infinity); + this.localUserByIdCache = new MemoryKVCache(Infinity); + this.uriPersonCache = new MemoryKVCache(Infinity); this.userProfileCache = new RedisKVCache(this.redisClient, 'userProfile', { lifetime: 1000 * 60 * 30, // 30m @@ -159,17 +128,29 @@ export class CacheService implements OnApplicationShutdown { const { type, body } = obj.message as GlobalEvents['internal']['payload']; switch (type) { case 'userChangeSuspendedState': - case 'remoteUserUpdated': { - const user = await this.usersRepository.findOneByOrFail({ id: body.id }); - this.userByIdCache.set(user.id, user); - for (const [k, v] of this.uriPersonCache.cache.entries()) { - if (v.value === user.id) { - this.uriPersonCache.set(k, user); + case 'userChangeDeletedState': + case 'remoteUserUpdated': + case 'localUserUpdated': { + const user = await this.usersRepository.findOneBy({ id: body.id }); + if (user == null) { + this.userByIdCache.delete(body.id); + this.localUserByIdCache.delete(body.id); + for (const [k, v] of this.uriPersonCache.cache.entries()) { + if (v.value?.id === body.id) { + this.uriPersonCache.delete(k); + } + } + } else { + this.userByIdCache.set(user.id, user); + for (const [k, v] of this.uriPersonCache.cache.entries()) { + if (v.value?.id === user.id) { + this.uriPersonCache.set(k, user); + } + } + if (this.userEntityService.isLocalUser(user)) { + this.localUserByNativeTokenCache.set(user.token!, user); + this.localUserByIdCache.set(user.id, user); } - } - if (this.userEntityService.isLocalUser(user)) { - this.localUserByNativeTokenCache.set(user.token!, user); - this.localUserByIdCache.set(user.id, user); } break; } diff --git a/packages/backend/src/core/CaptchaService.ts b/packages/backend/src/core/CaptchaService.ts index 6c5ee4835d..f6b7955cd2 100644 --- a/packages/backend/src/core/CaptchaService.ts +++ b/packages/backend/src/core/CaptchaService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/ClipService.ts b/packages/backend/src/core/ClipService.ts index e94f1eb531..bb8be26ce6 100644 --- a/packages/backend/src/core/ClipService.ts +++ b/packages/backend/src/core/ClipService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts index c9e285346e..2c27d33c06 100644 --- a/packages/backend/src/core/CoreModule.ts +++ b/packages/backend/src/core/CoreModule.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -116,6 +116,7 @@ import { FlashEntityService } from './entities/FlashEntityService.js'; import { FlashLikeEntityService } from './entities/FlashLikeEntityService.js'; import { RoleEntityService } from './entities/RoleEntityService.js'; import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js'; +import { MetaEntityService } from './entities/MetaEntityService.js'; import { ApAudienceService } from './activitypub/ApAudienceService.js'; import { ApDbResolverService } from './activitypub/ApDbResolverService.js'; @@ -254,6 +255,7 @@ const $FlashEntityService: Provider = { provide: 'FlashEntityService', useExisti const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', useExisting: FlashLikeEntityService }; const $RoleEntityService: Provider = { provide: 'RoleEntityService', useExisting: RoleEntityService }; const $ReversiGameEntityService: Provider = { provide: 'ReversiGameEntityService', useExisting: ReversiGameEntityService }; +const $MetaEntityService: Provider = { provide: 'MetaEntityService', useExisting: MetaEntityService }; const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService }; const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService }; @@ -393,6 +395,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting FlashLikeEntityService, RoleEntityService, ReversiGameEntityService, + MetaEntityService, ApAudienceService, ApDbResolverService, @@ -528,6 +531,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $FlashLikeEntityService, $RoleEntityService, $ReversiGameEntityService, + $MetaEntityService, $ApAudienceService, $ApDbResolverService, @@ -663,6 +667,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting FlashLikeEntityService, RoleEntityService, ReversiGameEntityService, + MetaEntityService, ApAudienceService, ApDbResolverService, @@ -797,6 +802,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $FlashLikeEntityService, $RoleEntityService, $ReversiGameEntityService, + $MetaEntityService, $ApAudienceService, $ApDbResolverService, diff --git a/packages/backend/src/core/CreateSystemUserService.ts b/packages/backend/src/core/CreateSystemUserService.ts index 6b475316f0..6c5b0f6a36 100644 --- a/packages/backend/src/core/CreateSystemUserService.ts +++ b/packages/backend/src/core/CreateSystemUserService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts index 9a8267b466..edb9335b6e 100644 --- a/packages/backend/src/core/CustomEmojiService.ts +++ b/packages/backend/src/core/CustomEmojiService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -385,7 +385,7 @@ export class CustomEmojiService implements OnApplicationShutdown { */ @bindThis public checkDuplicate(name: string): Promise { - return this.emojisRepository.exist({ where: { name, host: IsNull() } }); + return this.emojisRepository.exists({ where: { name, host: IsNull() } }); } @bindThis @@ -393,6 +393,11 @@ export class CustomEmojiService implements OnApplicationShutdown { return this.emojisRepository.findOneBy({ id }); } + @bindThis + public getEmojiByName(name: string): Promise { + return this.emojisRepository.findOneBy({ name, host: IsNull() }); + } + @bindThis public dispose(): void { this.cache.dispose(); diff --git a/packages/backend/src/core/DeleteAccountService.ts b/packages/backend/src/core/DeleteAccountService.ts index 570bd440e4..79b614edba 100644 --- a/packages/backend/src/core/DeleteAccountService.ts +++ b/packages/backend/src/core/DeleteAccountService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -9,6 +9,7 @@ import { QueueService } from '@/core/QueueService.js'; import { UserSuspendService } from '@/core/UserSuspendService.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; @Injectable() export class DeleteAccountService { @@ -18,6 +19,7 @@ export class DeleteAccountService { private userSuspendService: UserSuspendService, private queueService: QueueService, + private globalEventService: GlobalEventService, ) { } @@ -39,5 +41,7 @@ export class DeleteAccountService { await this.usersRepository.update(user.id, { isDeleted: true, }); + + this.globalEventService.publishInternalEvent('userChangeDeletedState', { id: user.id, isDeleted: true }); } } diff --git a/packages/backend/src/core/DownloadService.ts b/packages/backend/src/core/DownloadService.ts index 5e196e83dd..21ae798f9f 100644 --- a/packages/backend/src/core/DownloadService.ts +++ b/packages/backend/src/core/DownloadService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts index 075bc9d7f7..1bc1df1dda 100644 --- a/packages/backend/src/core/DriveService.ts +++ b/packages/backend/src/core/DriveService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts index 8daee148eb..08f8f80a6e 100644 --- a/packages/backend/src/core/EmailService.ts +++ b/packages/backend/src/core/EmailService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -40,6 +40,8 @@ export class EmailService { public async sendEmail(to: string, subject: string, html: string, text: string) { const meta = await this.metaService.fetch(true); + if (!meta.enableEmail) return; + const iconUrl = `${this.config.url}/static-assets/mi-white.png`; const emailSettingUrl = `${this.config.url}/settings/email`; diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts index 11027960f1..9c239b4dfc 100644 --- a/packages/backend/src/core/FanoutTimelineEndpointService.ts +++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/FanoutTimelineService.ts b/packages/backend/src/core/FanoutTimelineService.ts index 9b2678fbcd..f6dabfadcd 100644 --- a/packages/backend/src/core/FanoutTimelineService.ts +++ b/packages/backend/src/core/FanoutTimelineService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/FeaturedService.ts b/packages/backend/src/core/FeaturedService.ts index 595383c82c..b3335e38da 100644 --- a/packages/backend/src/core/FeaturedService.ts +++ b/packages/backend/src/core/FeaturedService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts index e41f010e48..66db2067d9 100644 --- a/packages/backend/src/core/FederatedInstanceService.ts +++ b/packages/backend/src/core/FederatedInstanceService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/FetchInstanceMetadataService.ts b/packages/backend/src/core/FetchInstanceMetadataService.ts index 682acef15b..8d173855f3 100644 --- a/packages/backend/src/core/FetchInstanceMetadataService.ts +++ b/packages/backend/src/core/FetchInstanceMetadataService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -51,21 +51,35 @@ export class FetchInstanceMetadataService { } @bindThis - public async tryLock(host: string): Promise { - const mutex = await this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '1', 'GET'); - return mutex !== '1'; + // public for test + public async tryLock(host: string): Promise { + // TODO: マイグレーションなのであとで消す (2024.3.1) + this.redisClient.del(`fetchInstanceMetadata:mutex:${host}`); + + return await this.redisClient.set( + `fetchInstanceMetadata:mutex:v2:${host}`, '1', + 'EX', 30, // 30秒したら自動でロック解除 https://github.com/misskey-dev/misskey/issues/13506#issuecomment-1975375395 + 'GET' // 古い値を返す(なかったらnull) + ); } @bindThis - public unlock(host: string): Promise<'OK'> { - return this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '0'); + // public for test + public unlock(host: string): Promise { + return this.redisClient.del(`fetchInstanceMetadata:mutex:v2:${host}`); } @bindThis public async fetchInstanceMetadata(instance: MiInstance, force = false): Promise { const host = instance.host; - // Acquire mutex to ensure no parallel runs - if (!await this.tryLock(host)) return; + + // finallyでunlockされてしまうのでtry内でロックチェックをしない + // (returnであってもfinallyは実行される) + if (!force && await this.tryLock(host) === '1') { + // 1が返ってきていたらロックされているという意味なので、何もしない + return; + } + try { if (!force) { const _instance = await this.federatedInstanceService.fetch(host); diff --git a/packages/backend/src/core/FileInfoService.ts b/packages/backend/src/core/FileInfoService.ts index fdea59a8ad..b8babcb3a7 100644 --- a/packages/backend/src/core/FileInfoService.ts +++ b/packages/backend/src/core/FileInfoService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -15,6 +15,7 @@ import isSvg from 'is-svg'; import probeImageSize from 'probe-image-size'; import { type predictionType } from 'nsfwjs'; import sharp from 'sharp'; +import { sharpBmp } from '@misskey-dev/sharp-read-bmp'; import { encode } from 'blurhash'; import { createTempDir } from '@/misc/create-temp.js'; import { AiService } from '@/core/AiService.js'; @@ -122,7 +123,7 @@ export class FileInfoService { 'image/avif', 'image/svg+xml', ].includes(type.mime)) { - blurhash = await this.getBlurhash(path).catch(e => { + blurhash = await this.getBlurhash(path, type.mime).catch(e => { warnings.push(`getBlurhash failed: ${e}`); return undefined; }); @@ -407,9 +408,9 @@ export class FileInfoService { * Calculate average color of image */ @bindThis - private getBlurhash(path: string): Promise { - return new Promise((resolve, reject) => { - sharp(path) + private getBlurhash(path: string, type: string): Promise { + return new Promise(async (resolve, reject) => { + (await sharpBmp(path, type)) .raw() .ensureAlpha() .resize(64, 64, { fit: 'inside' }) diff --git a/packages/backend/src/core/GlobalEventService.ts b/packages/backend/src/core/GlobalEventService.ts index 5b4c8cb44f..90efd63f3a 100644 --- a/packages/backend/src/core/GlobalEventService.ts +++ b/packages/backend/src/core/GlobalEventService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -54,21 +54,22 @@ export interface MainEventTypes { reply: Packed<'Note'>; renote: Packed<'Note'>; follow: Packed<'UserDetailedNotMe'>; - followed: Packed<'User'>; - unfollow: Packed<'User'>; - meUpdated: Packed<'User'>; + followed: Packed<'UserLite'>; + unfollow: Packed<'UserDetailedNotMe'>; + meUpdated: Packed<'MeDetailed'>; pageEvent: { pageId: MiPage['id']; event: string; var: any; userId: MiUser['id']; - user: Packed<'User'>; + user: Packed<'UserDetailed'>; }; urlUploadFinished: { marker?: string | null; file: Packed<'DriveFile'>; }; readAllNotifications: undefined; + notificationFlushed: undefined; unreadNotification: Packed<'Notification'>; unreadMention: MiNote['id']; readAllUnreadMentions: undefined; @@ -92,7 +93,7 @@ export interface MainEventTypes { }; driveFileCreated: Packed<'DriveFile'>; readAntenna: MiAntenna; - receiveFollowRequest: Packed<'User'>; + receiveFollowRequest: Packed<'UserLite'>; announcementCreated: { announcement: Packed<'Announcement'>; }; @@ -140,8 +141,8 @@ type NoteStreamEventTypes = { }; export interface UserListEventTypes { - userAdded: Packed<'User'>; - userRemoved: Packed<'User'>; + userAdded: Packed<'UserLite'>; + userRemoved: Packed<'UserLite'>; } export interface AntennaEventTypes { @@ -209,8 +210,10 @@ type SerializedAll = { export interface InternalEventTypes { userChangeSuspendedState: { id: MiUser['id']; isSuspended: MiUser['isSuspended']; }; + userChangeDeletedState: { id: MiUser['id']; isDeleted: MiUser['isDeleted']; }; userTokenRegenerated: { id: MiUser['id']; oldToken: string; newToken: string; }; remoteUserUpdated: { id: MiUser['id']; }; + localUserUpdated: { id: MiUser['id']; }; follow: { followerId: MiUser['id']; followeeId: MiUser['id']; }; unfollow: { followerId: MiUser['id']; followeeId: MiUser['id']; }; blockingCreated: { blockerId: MiUser['id']; blockeeId: MiUser['id']; }; diff --git a/packages/backend/src/core/HashtagService.ts b/packages/backend/src/core/HashtagService.ts index 5a2417c9cd..eb192ee6da 100644 --- a/packages/backend/src/core/HashtagService.ts +++ b/packages/backend/src/core/HashtagService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -163,7 +163,7 @@ export class HashtagService { const instance = await this.metaService.fetch(); const hiddenTags = instance.hiddenTags.map(t => normalizeForSearch(t)); if (hiddenTags.includes(hashtag)) return; - if (this.utilityService.isSensitiveWordIncluded(hashtag, instance.sensitiveWords)) return; + if (this.utilityService.isKeyWordIncluded(hashtag, instance.sensitiveWords)) return; // YYYYMMDDHHmm (10分間隔) const now = new Date(); diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts index 73bb3dc7e9..7f3cac7c58 100644 --- a/packages/backend/src/core/HttpRequestService.ts +++ b/packages/backend/src/core/HttpRequestService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -14,9 +14,16 @@ import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { StatusError } from '@/misc/status-error.js'; import { bindThis } from '@/decorators.js'; +import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js'; +import type { IObject } from '@/core/activitypub/type.js'; import type { Response } from 'node-fetch'; import type { URL } from 'node:url'; +export type HttpRequestSendOptions = { + throwErrorWhenResponseNotOk: boolean; + validators?: ((res: Response) => void)[]; +}; + @Injectable() export class HttpRequestService { /** @@ -104,6 +111,23 @@ export class HttpRequestService { } } + @bindThis + public async getActivityJson(url: string): Promise { + const res = await this.send(url, { + method: 'GET', + headers: { + Accept: 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', + }, + timeout: 5000, + size: 1024 * 256, + }, { + throwErrorWhenResponseNotOk: true, + validators: [validateContentTypeSetAsActivityPub], + }); + + return await res.json() as IObject; + } + @bindThis public async getJson(url: string, accept = 'application/json, */*', headers?: Record): Promise { const res = await this.send(url, { @@ -132,17 +156,20 @@ export class HttpRequestService { } @bindThis - public async send(url: string, args: { - method?: string, - body?: string, - headers?: Record, - timeout?: number, - size?: number, - } = {}, extra: { - throwErrorWhenResponseNotOk: boolean; - } = { - throwErrorWhenResponseNotOk: true, - }): Promise { + public async send( + url: string, + args: { + method?: string, + body?: string, + headers?: Record, + timeout?: number, + size?: number, + } = {}, + extra: HttpRequestSendOptions = { + throwErrorWhenResponseNotOk: true, + validators: [], + }, + ): Promise { const timeout = args.timeout ?? 5000; const controller = new AbortController(); @@ -166,6 +193,12 @@ export class HttpRequestService { throw new StatusError(`${res.status} ${res.statusText}`, res.status, res.statusText); } + if (res.ok) { + for (const validator of (extra.validators ?? [])) { + validator(res); + } + } + return res; } } diff --git a/packages/backend/src/core/IdService.ts b/packages/backend/src/core/IdService.ts index 43e72d2d7b..10df6ef266 100644 --- a/packages/backend/src/core/IdService.ts +++ b/packages/backend/src/core/IdService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/ImageProcessingService.ts b/packages/backend/src/core/ImageProcessingService.ts index 8e800eb8f5..6f978b34c8 100644 --- a/packages/backend/src/core/ImageProcessingService.ts +++ b/packages/backend/src/core/ImageProcessingService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/InstanceActorService.ts b/packages/backend/src/core/InstanceActorService.ts index b40fd46291..22c47297a3 100644 --- a/packages/backend/src/core/InstanceActorService.ts +++ b/packages/backend/src/core/InstanceActorService.ts @@ -1,10 +1,10 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ import { Inject, Injectable } from '@nestjs/common'; -import { IsNull } from 'typeorm'; +import { IsNull, Not } from 'typeorm'; import type { MiLocalUser } from '@/models/User.js'; import type { UsersRepository } from '@/models/_.js'; import { MemorySingleCache } from '@/misc/cache.js'; @@ -27,6 +27,14 @@ export class InstanceActorService { this.cache = new MemorySingleCache(Infinity); } + @bindThis + public async realLocalUsersPresent(): Promise { + return await this.usersRepository.existsBy({ + host: IsNull(), + username: Not(ACTOR_USERNAME), + }); + } + @bindThis public async getInstanceActor(): Promise { const cached = this.cache.get(); diff --git a/packages/backend/src/core/InternalStorageService.ts b/packages/backend/src/core/InternalStorageService.ts index 22129bb348..4fb8a93e49 100644 --- a/packages/backend/src/core/InternalStorageService.ts +++ b/packages/backend/src/core/InternalStorageService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/LoggerService.ts b/packages/backend/src/core/LoggerService.ts index 46b000ee63..96d9b09992 100644 --- a/packages/backend/src/core/LoggerService.ts +++ b/packages/backend/src/core/LoggerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/MetaService.ts b/packages/backend/src/core/MetaService.ts index 8e945e3d89..ec630f804e 100644 --- a/packages/backend/src/core/MetaService.ts +++ b/packages/backend/src/core/MetaService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts index e74c62e1a8..c62ee5a642 100644 --- a/packages/backend/src/core/MfmService.ts +++ b/packages/backend/src/core/MfmService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -419,6 +419,10 @@ export class MfmService { }, text: (node) => { + if (!node.props.text.match(/[\r\n]/)) { + return doc.createTextNode(node.props.text); + } + const el = doc.createElement('span'); const nodes = node.props.text.split(/\r\n|\r|\n/).map(x => doc.createTextNode(x)); diff --git a/packages/backend/src/core/ModerationLogService.ts b/packages/backend/src/core/ModerationLogService.ts index 8b78d02047..6c155c9a62 100644 --- a/packages/backend/src/core/ModerationLogService.ts +++ b/packages/backend/src/core/ModerationLogService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 30f6d07118..81ae2908d3 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -59,6 +59,8 @@ import { UtilityService } from '@/core/UtilityService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js'; import { isReply } from '@/misc/is-reply.js'; import { trackPromise } from '@/misc/promise-tracker.js'; +import { isNotNull } from '@/misc/is-not-null.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; type NotificationType = 'reply' | 'renote' | 'quote' | 'mention'; @@ -254,13 +256,23 @@ export class NoteCreateService implements OnApplicationShutdown { if (data.visibility === 'public' && data.channel == null) { const sensitiveWords = meta.sensitiveWords; - if (this.utilityService.isSensitiveWordIncluded(data.cw ?? data.text ?? '', sensitiveWords)) { + if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', sensitiveWords)) { data.visibility = 'home'; } else if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) { data.visibility = 'home'; } } + const hasProhibitedWords = await this.checkProhibitedWordsContain({ + cw: data.cw, + text: data.text, + pollChoices: data.poll?.choices, + }, meta.prohibitedWords); + + if (hasProhibitedWords) { + throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Note contains prohibited words'); + } + const inSilencedInstance = this.utilityService.isSilencedHost(meta.silencedHosts, user.host); if (data.visibility === 'public' && inSilencedInstance && user.host !== null) { @@ -373,6 +385,10 @@ export class NoteCreateService implements OnApplicationShutdown { } } + if (mentionedUsers.length > 0 && mentionedUsers.length > (await this.roleService.getUserPolicies(user.id)).mentionLimit) { + throw new IdentifiableError('9f466dab-c856-48cd-9e65-ff90ff750580', 'Note contains too many mentions'); + } + const note = await this.insertNote(user, data, tags, emojis, mentionedUsers); setImmediate('post created', { signal: this.#shutdownController.signal }).then( @@ -603,7 +619,7 @@ export class NoteCreateService implements OnApplicationShutdown { if (data.reply) { // 通知 if (data.reply.userHost === null) { - const isThreadMuted = await this.noteThreadMutingsRepository.exist({ + const isThreadMuted = await this.noteThreadMutingsRepository.exists({ where: { userId: data.reply.userId, threadId: data.reply.threadId ?? data.reply.id, @@ -741,7 +757,7 @@ export class NoteCreateService implements OnApplicationShutdown { @bindThis private async createMentionedEvents(mentionedUsers: MinimumUser[], note: MiNote, nm: NotificationManager) { for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) { - const isThreadMuted = await this.noteThreadMutingsRepository.exist({ + const isThreadMuted = await this.noteThreadMutingsRepository.exists({ where: { userId: u.id, threadId: note.threadId ?? note.id, @@ -811,7 +827,7 @@ export class NoteCreateService implements OnApplicationShutdown { const mentions = extractMentions(tokens); let mentionedUsers = (await Promise.all(mentions.map(m => this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null), - ))).filter(x => x != null) as MiUser[]; + ))).filter(isNotNull); // Drop duplicate users mentionedUsers = mentionedUsers.filter((u, i, self) => @@ -985,6 +1001,23 @@ export class NoteCreateService implements OnApplicationShutdown { } } + public async checkProhibitedWordsContain(content: Parameters[0], prohibitedWords?: string[]) { + if (prohibitedWords == null) { + prohibitedWords = (await this.metaService.fetch()).prohibitedWords; + } + + if ( + this.utilityService.isKeyWordIncluded( + this.utilityService.concatNoteContentsForKeyWordCheck(content), + prohibitedWords, + ) + ) { + return true; + } + + return false; + } + @bindThis public dispose(): void { this.#shutdownController.abort(); diff --git a/packages/backend/src/core/NoteDeleteService.ts b/packages/backend/src/core/NoteDeleteService.ts index 632daf991a..fdf843c3e8 100644 --- a/packages/backend/src/core/NoteDeleteService.ts +++ b/packages/backend/src/core/NoteDeleteService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/NotePiningService.ts b/packages/backend/src/core/NotePiningService.ts index 74e53c5c46..d38b48b65d 100644 --- a/packages/backend/src/core/NotePiningService.ts +++ b/packages/backend/src/core/NotePiningService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/NoteReadService.ts b/packages/backend/src/core/NoteReadService.ts index c73cf76592..181c9f7649 100644 --- a/packages/backend/src/core/NoteReadService.ts +++ b/packages/backend/src/core/NoteReadService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -49,7 +49,7 @@ export class NoteReadService implements OnApplicationShutdown { //#endregion // スレッドミュート - const isThreadMuted = await this.noteThreadMutingsRepository.exist({ + const isThreadMuted = await this.noteThreadMutingsRepository.exists({ where: { userId: userId, threadId: note.threadId ?? note.id, @@ -70,7 +70,7 @@ export class NoteReadService implements OnApplicationShutdown { // 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する setTimeout(2000, 'unread note', { signal: this.#shutdownController.signal }).then(async () => { - const exist = await this.noteUnreadsRepository.exist({ where: { id: unread.id } }); + const exist = await this.noteUnreadsRepository.exists({ where: { id: unread.id } }); if (!exist) return; @@ -88,46 +88,47 @@ export class NoteReadService implements OnApplicationShutdown { userId: MiUser['id'], notes: (MiNote | Packed<'Note'>)[], ): Promise { - const readMentions: (MiNote | Packed<'Note'>)[] = []; - const readSpecifiedNotes: (MiNote | Packed<'Note'>)[] = []; + if (notes.length === 0) return; + + const noteIds = new Set(); for (const note of notes) { if (note.mentions && note.mentions.includes(userId)) { - readMentions.push(note); + noteIds.add(note.id); } else if (note.visibleUserIds && note.visibleUserIds.includes(userId)) { - readSpecifiedNotes.push(note); + noteIds.add(note.id); } } - if ((readMentions.length > 0) || (readSpecifiedNotes.length > 0)) { - // Remove the record - await this.noteUnreadsRepository.delete({ - userId: userId, - noteId: In([...readMentions.map(n => n.id), ...readSpecifiedNotes.map(n => n.id)]), - }); + if (noteIds.size === 0) return; - // TODO: ↓まとめてクエリしたい + // Remove the record + await this.noteUnreadsRepository.delete({ + userId: userId, + noteId: In(Array.from(noteIds)), + }); - trackPromise(this.noteUnreadsRepository.countBy({ - userId: userId, - isMentioned: true, - }).then(mentionsCount => { - if (mentionsCount === 0) { - // 全て既読になったイベントを発行 - this.globalEventService.publishMainStream(userId, 'readAllUnreadMentions'); - } - })); + // TODO: ↓まとめてクエリしたい - trackPromise(this.noteUnreadsRepository.countBy({ - userId: userId, - isSpecified: true, - }).then(specifiedCount => { - if (specifiedCount === 0) { - // 全て既読になったイベントを発行 - this.globalEventService.publishMainStream(userId, 'readAllUnreadSpecifiedNotes'); - } - })); - } + trackPromise(this.noteUnreadsRepository.countBy({ + userId: userId, + isMentioned: true, + }).then(mentionsCount => { + if (mentionsCount === 0) { + // 全て既読になったイベントを発行 + this.globalEventService.publishMainStream(userId, 'readAllUnreadMentions'); + } + })); + + trackPromise(this.noteUnreadsRepository.countBy({ + userId: userId, + isSpecified: true, + }).then(specifiedCount => { + if (specifiedCount === 0) { + // 全て既読になったイベントを発行 + this.globalEventService.publishMainStream(userId, 'readAllUnreadSpecifiedNotes'); + } + })); } @bindThis diff --git a/packages/backend/src/core/NotificationService.ts b/packages/backend/src/core/NotificationService.ts index 765fcae063..68ad92f396 100644 --- a/packages/backend/src/core/NotificationService.ts +++ b/packages/backend/src/core/NotificationService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -122,6 +122,14 @@ export class NotificationService implements OnApplicationShutdown { return null; } } else if (recieveConfig?.type === 'mutualFollow') { + const [isFollowing, isFollower] = await Promise.all([ + this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => Object.hasOwn(followings, notifierId)), + this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => Object.hasOwn(followings, notifieeId)), + ]); + if (!(isFollowing && isFollower)) { + return null; + } + } else if (recieveConfig?.type === 'followingOrFollower') { const [isFollowing, isFollower] = await Promise.all([ this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => Object.hasOwn(followings, notifierId)), this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => Object.hasOwn(followings, notifieeId)), @@ -155,6 +163,8 @@ export class NotificationService implements OnApplicationShutdown { const packed = await this.notificationEntityService.pack(notification, notifieeId, {}); + if (packed == null) return null; + // Publish notification event this.globalEventService.publishMainStream(notifieeId, 'notification', packed); @@ -204,6 +214,15 @@ export class NotificationService implements OnApplicationShutdown { */ } + @bindThis + public async flushAllNotifications(userId: MiUser['id']) { + await Promise.all([ + this.redisClient.del(`notificationTimeline:${userId}`), + this.redisClient.del(`latestReadNotification:${userId}`), + ]); + this.globalEventService.publishMainStream(userId, 'notificationFlushed'); + } + @bindThis public dispose(): void { this.#shutdownController.abort(); diff --git a/packages/backend/src/core/PollService.ts b/packages/backend/src/core/PollService.ts index 9e1b5ca78a..6c96ab16cf 100644 --- a/packages/backend/src/core/PollService.ts +++ b/packages/backend/src/core/PollService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/ProxyAccountService.ts b/packages/backend/src/core/ProxyAccountService.ts index b1bc60701b..71d663bf90 100644 --- a/packages/backend/src/core/ProxyAccountService.ts +++ b/packages/backend/src/core/ProxyAccountService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts index 40d1deceeb..3b706d9854 100644 --- a/packages/backend/src/core/PushNotificationService.ts +++ b/packages/backend/src/core/PushNotificationService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -115,12 +115,19 @@ export class PushNotificationService implements OnApplicationShutdown { endpoint: subscription.endpoint, auth: subscription.auth, publickey: subscription.publickey, + }).then(() => { + this.refreshCache(userId); }); } }); } } + @bindThis + public refreshCache(userId: string): void { + this.subscriptionsCache.refresh(userId); + } + @bindThis public dispose(): void { this.subscriptionsCache.dispose(); diff --git a/packages/backend/src/core/QueryService.ts b/packages/backend/src/core/QueryService.ts index 13d8a67597..c4feeaf971 100644 --- a/packages/backend/src/core/QueryService.ts +++ b/packages/backend/src/core/QueryService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/QueueModule.ts b/packages/backend/src/core/QueueModule.ts index 20a53ff282..216734e9e5 100644 --- a/packages/backend/src/core/QueueModule.ts +++ b/packages/backend/src/core/QueueModule.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index dc3f248da4..c258a22927 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 2e8f76fa8a..cb0b079df0 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -30,12 +30,12 @@ import { RoleService } from '@/core/RoleService.js'; import { FeaturedService } from '@/core/FeaturedService.js'; import { trackPromise } from '@/misc/promise-tracker.js'; -const FALLBACK = '❤'; +const FALLBACK = '\u2764'; const PER_NOTE_REACTION_USER_PAIR_CACHE_MAX = 16; const legacies: Record = { 'like': '👍', - 'love': '❤', // ここに記述する場合は異体字セレクタを入れない + 'love': '\u2764', // ハート、異体字セレクタを入れない 'laugh': '😆', 'hmm': '🤔', 'surprise': '😮', @@ -120,7 +120,7 @@ export class ReactionService { let reaction = _reaction ?? FALLBACK; if (note.reactionAcceptance === 'likeOnly' || ((note.reactionAcceptance === 'likeOnlyForRemote' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && (user.host != null))) { - reaction = '❤️'; + reaction = '\u2764'; } else if (_reaction) { const custom = reaction.match(isCustomEmojiRegexp); if (custom) { @@ -322,35 +322,36 @@ export class ReactionService { //#endregion } + /** + * 文字列タイプのレガシーな形式のリアクションを現在の形式に変換しつつ、 + * データベース上には存在する「0個のリアクションがついている」という情報を削除する。 + */ @bindThis - public convertLegacyReactions(reactions: Record) { - const _reactions = {} as Record; + public convertLegacyReactions(reactions: MiNote['reactions']): MiNote['reactions'] { + return Object.entries(reactions) + .filter(([, count]) => { + // `ReactionService.prototype.delete`ではリアクション削除時に、 + // `MiNote['reactions']`のエントリの値をデクリメントしているが、 + // デクリメントしているだけなのでエントリ自体は0を値として持つ形で残り続ける。 + // そのため、この処理がなければ、「0個のリアクションがついている」ということになってしまう。 + return count > 0; + }) + .map(([reaction, count]) => { + // unchecked indexed access + const convertedReaction = legacies[reaction] as string | undefined; - for (const reaction of Object.keys(reactions)) { - if (reactions[reaction] <= 0) continue; + const key = this.decodeReaction(convertedReaction ?? reaction).reaction; - if (Object.keys(legacies).includes(reaction)) { - if (_reactions[legacies[reaction]]) { - _reactions[legacies[reaction]] += reactions[reaction]; - } else { - _reactions[legacies[reaction]] = reactions[reaction]; - } - } else { - if (_reactions[reaction]) { - _reactions[reaction] += reactions[reaction]; - } else { - _reactions[reaction] = reactions[reaction]; - } - } - } + return [key, count] as const; + }) + .reduce((acc, [key, count]) => { + // unchecked indexed access + const prevCount = acc[key] as number | undefined; - const _reactions2 = {} as Record; + acc[key] = (prevCount ?? 0) + count; - for (const reaction of Object.keys(_reactions)) { - _reactions2[this.decodeReaction(reaction).reaction] = _reactions[reaction]; - } - - return _reactions2; + return acc; + }, {}); } @bindThis diff --git a/packages/backend/src/core/RegistryApiService.ts b/packages/backend/src/core/RegistryApiService.ts index d340c5e480..2c8877d8a8 100644 --- a/packages/backend/src/core/RegistryApiService.ts +++ b/packages/backend/src/core/RegistryApiService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts index d40cd080c7..e9dc9b57af 100644 --- a/packages/backend/src/core/RelayService.ts +++ b/packages/backend/src/core/RelayService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/RemoteLoggerService.ts b/packages/backend/src/core/RemoteLoggerService.ts index 5d13988ed7..413b03bb56 100644 --- a/packages/backend/src/core/RemoteLoggerService.ts +++ b/packages/backend/src/core/RemoteLoggerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/RemoteUserResolveService.ts b/packages/backend/src/core/RemoteUserResolveService.ts index 75c5f14aa4..f5a55eb8bc 100644 --- a/packages/backend/src/core/RemoteUserResolveService.ts +++ b/packages/backend/src/core/RemoteUserResolveService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/ReversiService.ts b/packages/backend/src/core/ReversiService.ts index 186ec6d7b1..439bc08845 100644 --- a/packages/backend/src/core/ReversiService.ts +++ b/packages/backend/src/core/ReversiService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index a3558ea9ed..09f3097114 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -35,6 +35,7 @@ export type RolePolicies = { gtlAvailable: boolean; ltlAvailable: boolean; canPublicNote: boolean; + mentionLimit: number; canInvite: boolean; inviteLimit: number; inviteLimitCycle: number; @@ -62,6 +63,7 @@ export const DEFAULT_POLICIES: RolePolicies = { gtlAvailable: true, ltlAvailable: true, canPublicNote: true, + mentionLimit: 20, canInvite: false, inviteLimit: 0, inviteLimitCycle: 60 * 24 * 7, @@ -200,17 +202,20 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { } @bindThis - private evalCond(user: MiUser, value: RoleCondFormulaValue): boolean { + private evalCond(user: MiUser, roles: MiRole[], value: RoleCondFormulaValue): boolean { try { switch (value.type) { case 'and': { - return value.values.every(v => this.evalCond(user, v)); + return value.values.every(v => this.evalCond(user, roles, v)); } case 'or': { - return value.values.some(v => this.evalCond(user, v)); + return value.values.some(v => this.evalCond(user, roles, v)); } case 'not': { - return !this.evalCond(user, value.value); + return !this.evalCond(user, roles, value.value); + } + case 'roleAssignedTo': { + return roles.some(r => r.id === value.roleId); } case 'isLocal': { return this.userEntityService.isLocalUser(user); @@ -272,7 +277,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { const assigns = await this.getUserAssigns(userId); const assignedRoles = roles.filter(r => assigns.map(x => x.roleId).includes(r.id)); const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null; - const matchedCondRoles = roles.filter(r => r.target === 'conditional' && this.evalCond(user!, r.condFormula)); + const matchedCondRoles = roles.filter(r => r.target === 'conditional' && this.evalCond(user!, assignedRoles, r.condFormula)); return [...assignedRoles, ...matchedCondRoles]; } @@ -285,13 +290,13 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId })); // 期限切れのロールを除外 assigns = assigns.filter(a => a.expiresAt == null || (a.expiresAt.getTime() > now)); - const assignedRoleIds = assigns.map(x => x.roleId); const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({})); - const assignedBadgeRoles = roles.filter(r => r.asBadge && assignedRoleIds.includes(r.id)); + const assignedRoles = roles.filter(r => assigns.map(x => x.roleId).includes(r.id)); + const assignedBadgeRoles = assignedRoles.filter(r => r.asBadge); const badgeCondRoles = roles.filter(r => r.asBadge && (r.target === 'conditional')); if (badgeCondRoles.length > 0) { const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null; - const matchedBadgeCondRoles = badgeCondRoles.filter(r => this.evalCond(user!, r.condFormula)); + const matchedBadgeCondRoles = badgeCondRoles.filter(r => this.evalCond(user!, assignedRoles, r.condFormula)); return [...assignedBadgeRoles, ...matchedBadgeCondRoles]; } else { return assignedBadgeRoles; @@ -325,6 +330,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { gtlAvailable: calc('gtlAvailable', vs => vs.some(v => v === true)), ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)), canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)), + mentionLimit: calc('mentionLimit', vs => Math.max(...vs)), canInvite: calc('canInvite', vs => vs.some(v => v === true)), inviteLimit: calc('inviteLimit', vs => Math.max(...vs)), inviteLimitCycle: calc('inviteLimitCycle', vs => Math.max(...vs)), diff --git a/packages/backend/src/core/S3Service.ts b/packages/backend/src/core/S3Service.ts index df0991539d..bb2a463354 100644 --- a/packages/backend/src/core/S3Service.ts +++ b/packages/backend/src/core/S3Service.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/SearchService.ts b/packages/backend/src/core/SearchService.ts index a46d68fd84..edfc470375 100644 --- a/packages/backend/src/core/SearchService.ts +++ b/packages/backend/src/core/SearchService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/SignupService.ts b/packages/backend/src/core/SignupService.ts index b9e3ded46f..5522ecd6cc 100644 --- a/packages/backend/src/core/SignupService.ts +++ b/packages/backend/src/core/SignupService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -16,6 +16,7 @@ import { MiUserKeypair } from '@/models/UserKeypair.js'; import { MiUsedUsername } from '@/models/UsedUsername.js'; import generateUserToken from '@/misc/generate-native-user-token.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { InstanceActorService } from '@/core/InstanceActorService.js'; import { bindThis } from '@/decorators.js'; import UsersChart from '@/core/chart/charts/users.js'; import { UtilityService } from '@/core/UtilityService.js'; @@ -37,6 +38,7 @@ export class SignupService { private userEntityService: UserEntityService, private idService: IdService, private metaService: MetaService, + private instanceActorService: InstanceActorService, private usersChart: UsersChart, ) { } @@ -72,16 +74,16 @@ export class SignupService { const secret = generateUserToken(); // Check username duplication - if (await this.usersRepository.exist({ where: { usernameLower: username.toLowerCase(), host: IsNull() } })) { + if (await this.usersRepository.exists({ where: { usernameLower: username.toLowerCase(), host: IsNull() } })) { throw new Error('DUPLICATED_USERNAME'); } // Check deleted username duplication - if (await this.usedUsernamesRepository.exist({ where: { username: username.toLowerCase() } })) { + if (await this.usedUsernamesRepository.exists({ where: { username: username.toLowerCase() } })) { throw new Error('USED_USERNAME'); } - const isTheFirstUser = (await this.usersRepository.countBy({ host: IsNull() })) === 0; + const isTheFirstUser = !await this.instanceActorService.realLocalUsersPresent(); if (!opts.ignorePreservedUsernames && !isTheFirstUser) { const instance = await this.metaService.fetch(true); diff --git a/packages/backend/src/core/UserAuthService.ts b/packages/backend/src/core/UserAuthService.ts index ccf4dfc6bd..bdc27cbe8e 100644 --- a/packages/backend/src/core/UserAuthService.ts +++ b/packages/backend/src/core/UserAuthService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/UserBlockingService.ts b/packages/backend/src/core/UserBlockingService.ts index 39b19325c3..96f389b54c 100644 --- a/packages/backend/src/core/UserBlockingService.ts +++ b/packages/backend/src/core/UserBlockingService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -109,13 +109,13 @@ export class UserBlockingService implements OnModuleInit { if (this.userEntityService.isLocalUser(followee)) { this.userEntityService.pack(followee, followee, { - detail: true, + schema: 'MeDetailed', }).then(packed => this.globalEventService.publishMainStream(followee.id, 'meUpdated', packed)); } if (this.userEntityService.isLocalUser(follower) && !silent) { this.userEntityService.pack(followee, follower, { - detail: true, + schema: 'UserDetailedNotMe', }).then(async packed => { this.globalEventService.publishMainStream(follower.id, 'unfollow', packed); diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index d600ffb9d9..0a492c06e4 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -30,6 +30,7 @@ import type { Config } from '@/config.js'; import { AccountMoveService } from '@/core/AccountMoveService.js'; import { UtilityService } from '@/core/UtilityService.js'; import { FanoutTimelineService } from '@/core/FanoutTimelineService.js'; +import type { ThinUser } from '@/queue/types.js'; import Logger from '../logger.js'; const logger = new Logger('following/create'); @@ -94,21 +95,35 @@ export class UserFollowingService implements OnModuleInit { this.userBlockingService = this.moduleRef.get('UserBlockingService'); } + @bindThis + public async deliverAccept(follower: MiRemoteUser, followee: MiPartialLocalUser, requestId?: string) { + const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee)); + this.queueService.deliver(followee, content, follower.inbox, false); + } + @bindThis public async follow( - _follower: { id: MiUser['id'] }, - _followee: { id: MiUser['id'] }, + _follower: ThinUser, + _followee: ThinUser, { requestId, silent = false, withReplies }: { requestId?: string, silent?: boolean, withReplies?: boolean, } = {}, ): Promise { + /** + * 必ず最新のユーザー情報を取得する + */ const [follower, followee] = await Promise.all([ this.usersRepository.findOneByOrFail({ id: _follower.id }), this.usersRepository.findOneByOrFail({ id: _followee.id }), ]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser]; + if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isRemoteUser(followee)) { + // What? + throw new Error('Remote user cannot follow remote user.'); + } + // check blocking const [blocking, blocked] = await Promise.all([ this.userBlockingService.checkBlocked(follower.id, followee.id), @@ -129,6 +144,24 @@ export class UserFollowingService implements OnModuleInit { if (blocked) throw new IdentifiableError('3338392a-f764-498d-8855-db939dcf8c48', 'blocked'); } + if (await this.followingsRepository.exists({ + where: { + followerId: follower.id, + followeeId: followee.id, + }, + })) { + // すでにフォロー関係が存在している場合 + if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { + // リモート → ローカル: acceptを送り返しておしまい + this.deliverAccept(follower, followee, requestId); + return; + } + if (this.userEntityService.isLocalUser(follower)) { + // ローカル → リモート/ローカル: 例外 + throw new IdentifiableError('ec3f65c0-a9d1-47d9-8791-b2e7b9dcdced', 'already following'); + } + } + const followeeProfile = await this.userProfilesRepository.findOneByOrFail({ userId: followee.id }); // フォロー対象が鍵アカウントである or // フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or @@ -144,7 +177,7 @@ export class UserFollowingService implements OnModuleInit { let autoAccept = false; // 鍵アカウントであっても、既にフォローされていた場合はスルー - const isFollowing = await this.followingsRepository.exist({ + const isFollowing = await this.followingsRepository.exists({ where: { followerId: follower.id, followeeId: followee.id, @@ -156,7 +189,7 @@ export class UserFollowingService implements OnModuleInit { // フォローしているユーザーは自動承認オプション if (!autoAccept && (this.userEntityService.isLocalUser(followee) && followeeProfile.autoAcceptFollowed)) { - const isFollowed = await this.followingsRepository.exist({ + const isFollowed = await this.followingsRepository.exists({ where: { followerId: followee.id, followeeId: follower.id, @@ -170,7 +203,7 @@ export class UserFollowingService implements OnModuleInit { if (followee.isLocked && !autoAccept) { autoAccept = !!(await this.accountMoveService.validateAlsoKnownAs( follower, - (oldSrc, newSrc) => this.followingsRepository.exist({ + (oldSrc, newSrc) => this.followingsRepository.exists({ where: { followeeId: followee.id, followerId: newSrc.id, @@ -189,8 +222,7 @@ export class UserFollowingService implements OnModuleInit { await this.insertFollowingDoc(followee, follower, silent, withReplies); if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { - const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee)); - this.queueService.deliver(followee, content, follower.inbox, false); + this.deliverAccept(follower, followee, requestId); } } @@ -233,7 +265,7 @@ export class UserFollowingService implements OnModuleInit { this.cacheService.userFollowingsCache.refresh(follower.id); - const requestExist = await this.followRequestsRepository.exist({ + const requestExist = await this.followRequestsRepository.exists({ where: { followeeId: followee.id, followerId: follower.id, @@ -293,9 +325,9 @@ export class UserFollowingService implements OnModuleInit { if (this.userEntityService.isLocalUser(follower) && !silent) { // Publish follow event this.userEntityService.pack(followee.id, follower, { - detail: true, + schema: 'UserDetailedNotMe', }).then(async packed => { - this.globalEventService.publishMainStream(follower.id, 'follow', packed as Packed<'UserDetailedNotMe'>); + this.globalEventService.publishMainStream(follower.id, 'follow', packed); const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('follow')); for (const webhook of webhooks) { @@ -360,7 +392,7 @@ export class UserFollowingService implements OnModuleInit { if (!silent && this.userEntityService.isLocalUser(follower)) { // Publish unfollow event this.userEntityService.pack(followee.id, follower, { - detail: true, + schema: 'UserDetailedNotMe', }).then(async packed => { this.globalEventService.publishMainStream(follower.id, 'unfollow', packed); @@ -500,7 +532,7 @@ export class UserFollowingService implements OnModuleInit { this.userEntityService.pack(follower.id, followee).then(packed => this.globalEventService.publishMainStream(followee.id, 'receiveFollowRequest', packed)); this.userEntityService.pack(followee.id, followee, { - detail: true, + schema: 'MeDetailed', }).then(packed => this.globalEventService.publishMainStream(followee.id, 'meUpdated', packed)); // 通知を作成 @@ -531,7 +563,7 @@ export class UserFollowingService implements OnModuleInit { } } - const requestExist = await this.followRequestsRepository.exist({ + const requestExist = await this.followRequestsRepository.exists({ where: { followeeId: followee.id, followerId: follower.id, @@ -548,7 +580,7 @@ export class UserFollowingService implements OnModuleInit { }); this.userEntityService.pack(followee.id, followee, { - detail: true, + schema: 'MeDetailed', }).then(packed => this.globalEventService.publishMainStream(followee.id, 'meUpdated', packed)); } @@ -571,12 +603,11 @@ export class UserFollowingService implements OnModuleInit { await this.insertFollowingDoc(followee, follower, false, request.withReplies); if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { - const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee as MiPartialLocalUser, request.requestId!), followee)); - this.queueService.deliver(followee, content, follower.inbox, false); + this.deliverAccept(follower, followee as MiPartialLocalUser, request.requestId ?? undefined); } this.userEntityService.pack(followee.id, followee, { - detail: true, + schema: 'MeDetailed', }).then(packed => this.globalEventService.publishMainStream(followee.id, 'meUpdated', packed)); } @@ -696,7 +727,7 @@ export class UserFollowingService implements OnModuleInit { @bindThis private async publishUnfollow(followee: Both, follower: Local): Promise { const packedFollowee = await this.userEntityService.pack(followee.id, follower, { - detail: true, + schema: 'UserDetailedNotMe', }); this.globalEventService.publishMainStream(follower.id, 'unfollow', packedFollowee); diff --git a/packages/backend/src/core/UserKeypairService.ts b/packages/backend/src/core/UserKeypairService.ts index 425a97f3f1..51ac99179a 100644 --- a/packages/backend/src/core/UserKeypairService.ts +++ b/packages/backend/src/core/UserKeypairService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/UserListService.ts b/packages/backend/src/core/UserListService.ts index b6e4e1e884..bbdcfed738 100644 --- a/packages/backend/src/core/UserListService.ts +++ b/packages/backend/src/core/UserListService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/UserMutingService.ts b/packages/backend/src/core/UserMutingService.ts index 397e6bdd5d..06643be5fb 100644 --- a/packages/backend/src/core/UserMutingService.ts +++ b/packages/backend/src/core/UserMutingService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/UserService.ts b/packages/backend/src/core/UserService.ts index d16e1be615..72fa4d928d 100644 --- a/packages/backend/src/core/UserService.ts +++ b/packages/backend/src/core/UserService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts index 8940a142d1..d594a223f4 100644 --- a/packages/backend/src/core/UserSuspendService.ts +++ b/packages/backend/src/core/UserSuspendService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/UtilityService.ts b/packages/backend/src/core/UtilityService.ts index 5dec36c89e..652e8f7449 100644 --- a/packages/backend/src/core/UtilityService.ts +++ b/packages/backend/src/core/UtilityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -43,13 +43,27 @@ export class UtilityService { } @bindThis - public isSensitiveWordIncluded(text: string, sensitiveWords: string[]): boolean { - if (sensitiveWords.length === 0) return false; + public concatNoteContentsForKeyWordCheck(content: { + cw?: string | null; + text?: string | null; + pollChoices?: string[] | null; + others?: string[] | null; + }): string { + /** + * ノートの内容を結合してキーワードチェック用の文字列を生成する + * cwとtextは内容が繋がっているかもしれないので間に何も入れずにチェックする + */ + return `${content.cw ?? ''}${content.text ?? ''}\n${(content.pollChoices ?? []).join('\n')}\n${(content.others ?? []).join('\n')}`; + } + + @bindThis + public isKeyWordIncluded(text: string, keyWords: string[]): boolean { + if (keyWords.length === 0) return false; if (text === '') return false; const regexpregexp = /^\/(.+)\/(.*)$/; - const matched = sensitiveWords.some(filter => { + const matched = keyWords.some(filter => { // represents RegExp const regexp = filter.match(regexpregexp); // This should never happen due to input sanitisation. diff --git a/packages/backend/src/core/VideoProcessingService.ts b/packages/backend/src/core/VideoProcessingService.ts index ffb7573358..747fe4fc7e 100644 --- a/packages/backend/src/core/VideoProcessingService.ts +++ b/packages/backend/src/core/VideoProcessingService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/WebAuthnService.ts b/packages/backend/src/core/WebAuthnService.ts index 5945dc2919..42fbed2110 100644 --- a/packages/backend/src/core/WebAuthnService.ts +++ b/packages/backend/src/core/WebAuthnService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -26,7 +26,7 @@ import type { PublicKeyCredentialDescriptorFuture, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON, -} from '@simplewebauthn/typescript-types'; +} from '@simplewebauthn/types'; @Injectable() export class WebAuthnService { @@ -191,7 +191,7 @@ export class WebAuthnService { if (cert[0] === 0x04) { // 前の実装ではいつも 0x04 で始まっていた const halfLength = (cert.length - 1) / 2; - const cborMap = new Map(); + const cborMap = new Map(); cborMap.set(1, 2); // kty, EC2 cborMap.set(3, -7); // alg, ES256 cborMap.set(-1, 1); // crv, P256 diff --git a/packages/backend/src/core/WebfingerService.ts b/packages/backend/src/core/WebfingerService.ts index 3d5747aebd..374536a741 100644 --- a/packages/backend/src/core/WebfingerService.ts +++ b/packages/backend/src/core/WebfingerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/WebhookService.ts b/packages/backend/src/core/WebhookService.ts index 5937bf89b1..6be34977b0 100644 --- a/packages/backend/src/core/WebhookService.ts +++ b/packages/backend/src/core/WebhookService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/activitypub/ApAudienceService.ts b/packages/backend/src/core/activitypub/ApAudienceService.ts index 11fc82e8bc..0fccc7b950 100644 --- a/packages/backend/src/core/activitypub/ApAudienceService.ts +++ b/packages/backend/src/core/activitypub/ApAudienceService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -8,6 +8,7 @@ import promiseLimit from 'promise-limit'; import type { MiRemoteUser, MiUser } from '@/models/User.js'; import { concat, unique } from '@/misc/prelude/array.js'; import { bindThis } from '@/decorators.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { getApIds } from './type.js'; import { ApPersonService } from './models/ApPersonService.js'; import type { ApObject } from './type.js'; @@ -40,7 +41,7 @@ export class ApAudienceService { const limit = promiseLimit(2); const mentionedUsers = (await Promise.all( others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))), - )).filter((x): x is MiUser => x != null); + )).filter(isNotNull); if (toGroups.public.length > 0) { return { diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index 995c5dcd5f..f6b70ead44 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -106,12 +106,12 @@ export class ApDbResolverService implements OnApplicationShutdown { return await this.cacheService.userByIdCache.fetchMaybe( parsed.id, - () => this.usersRepository.findOneBy({ id: parsed.id }).then(x => x ?? undefined), + () => this.usersRepository.findOneBy({ id: parsed.id, isDeleted: false }).then(x => x ?? undefined), ) as MiLocalUser | undefined ?? null; } else { return await this.cacheService.uriPersonCache.fetch( parsed.uri, - () => this.usersRepository.findOneBy({ uri: parsed.uri }), + () => this.usersRepository.findOneBy({ uri: parsed.uri, isDeleted: false }), ) as MiRemoteUser | null; } } @@ -136,8 +136,12 @@ export class ApDbResolverService implements OnApplicationShutdown { if (key == null) return null; + const user = await this.cacheService.findUserById(key.userId).catch(() => null) as MiRemoteUser | null; + if (user == null) return null; + if (user.isDeleted) return null; + return { - user: await this.cacheService.findUserById(key.userId) as MiRemoteUser, + user, key, }; } @@ -151,6 +155,7 @@ export class ApDbResolverService implements OnApplicationShutdown { key: MiUserPublickey | null; } | null> { const user = await this.apPersonService.resolvePerson(uri) as MiRemoteUser; + if (user.isDeleted) return null; const key = await this.publicKeyByUserIdCache.fetch( user.id, diff --git a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts index d7414e9c99..5d07cd8e8f 100644 --- a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts +++ b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index a0c63bdbf7..1621c41bcc 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -27,6 +27,7 @@ import { QueueService } from '@/core/QueueService.js'; import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; import type { MiRemoteUser } from '@/models/User.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js'; import { ApNoteService } from './models/ApNoteService.js'; import { ApLoggerService } from './ApLoggerService.js'; @@ -35,6 +36,7 @@ import { ApResolverService } from './ApResolverService.js'; import { ApAudienceService } from './ApAudienceService.js'; import { ApPersonService } from './models/ApPersonService.js'; import { ApQuestionService } from './models/ApQuestionService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; import type { Resolver } from './ApResolverService.js'; import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IReject, IRemove, IUndo, IUpdate, IMove } from './type.js'; @@ -82,6 +84,7 @@ export class ApInboxService { private apPersonService: ApPersonService, private apQuestionService: ApQuestionService, private queueService: QueueService, + private globalEventService: GlobalEventService, ) { this.logger = this.apLoggerService.logger; } @@ -479,6 +482,8 @@ export class ApInboxService { isDeleted: true, }); + this.globalEventService.publishInternalEvent('remoteUserUpdated', { id: actor.id }); + return `ok: queued ${job.name} ${job.id}`; } @@ -515,7 +520,7 @@ export class ApInboxService { const userIds = uris .filter(uri => uri.startsWith(this.config.url + '/users/')) .map(uri => uri.split('/').at(-1)) - .filter((userId): userId is string => userId !== undefined); + .filter(isNotNull); const users = await this.usersRepository.findBy({ id: In(userIds), }); @@ -629,7 +634,7 @@ export class ApInboxService { return 'skip: follower not found'; } - const isFollowing = await this.followingsRepository.exist({ + const isFollowing = await this.followingsRepository.exists({ where: { followerId: follower.id, followeeId: actor.id, @@ -686,14 +691,14 @@ export class ApInboxService { return 'skip: フォロー解除しようとしているユーザーはローカルユーザーではありません'; } - const requestExist = await this.followRequestsRepository.exist({ + const requestExist = await this.followRequestsRepository.exists({ where: { followerId: actor.id, followeeId: followee.id, }, }); - const isFollowing = await this.followingsRepository.exist({ + const isFollowing = await this.followingsRepository.exists({ where: { followerId: actor.id, followeeId: followee.id, diff --git a/packages/backend/src/core/activitypub/ApLoggerService.ts b/packages/backend/src/core/activitypub/ApLoggerService.ts index cd9597e423..428d8061ce 100644 --- a/packages/backend/src/core/activitypub/ApLoggerService.ts +++ b/packages/backend/src/core/activitypub/ApLoggerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/activitypub/ApMfmService.ts b/packages/backend/src/core/activitypub/ApMfmService.ts index 60868627a2..ab75b9abbd 100644 --- a/packages/backend/src/core/activitypub/ApMfmService.ts +++ b/packages/backend/src/core/activitypub/ApMfmService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -25,8 +25,21 @@ export class ApMfmService { } @bindThis - public getNoteHtml(note: MiNote): string | null { - if (!note.text) return ''; - return this.mfmService.toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers)); + public getNoteHtml(note: MiNote, apAppend?: string) { + let noMisskeyContent = false; + const srcMfm = (note.text ?? '') + (apAppend ?? ''); + + const parsed = mfm.parse(srcMfm); + + if (!apAppend && parsed?.every(n => ['text', 'unicodeEmoji', 'emojiCode', 'mention', 'hashtag', 'url'].includes(n.type))) { + noMisskeyContent = true; + } + + const content = this.mfmService.toHtml(parsed, JSON.parse(note.mentionedRemoteUsers)); + + return { + content, + noMisskeyContent, + }; } } diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 1891c341e4..d7fb977a99 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -315,7 +315,7 @@ export class ApRendererService { const getPromisedFiles = async (ids: string[]): Promise => { if (ids.length === 0) return []; const items = await this.driveFilesRepository.findBy({ id: In(ids) }); - return ids.map(id => items.find(item => item.id === id)).filter((item): item is MiDriveFile => item != null); + return ids.map(id => items.find(item => item.id === id)).filter(isNotNull); }; let inReplyTo; @@ -325,7 +325,7 @@ export class ApRendererService { inReplyToNote = await this.notesRepository.findOneBy({ id: note.replyId }); if (inReplyToNote != null) { - const inReplyToUserExist = await this.usersRepository.exist({ where: { id: inReplyToNote.userId } }); + const inReplyToUserExist = await this.usersRepository.exists({ where: { id: inReplyToNote.userId } }); if (inReplyToUserExist) { if (inReplyToNote.uri) { @@ -389,17 +389,15 @@ export class ApRendererService { poll = await this.pollsRepository.findOneBy({ noteId: note.id }); } - let apText = text; + let apAppend = ''; if (quote) { - apText += `\n\nRE: ${quote}`; + apAppend += `\n\nRE: ${quote}`; } const summary = note.cw === '' ? String.fromCharCode(0x200B) : note.cw; - const content = this.apMfmService.getNoteHtml(Object.assign({}, note, { - text: apText, - })); + const { content, noMisskeyContent } = this.apMfmService.getNoteHtml(note, apAppend); const emojis = await this.getEmojis(note.emojis); const apemojis = emojis.filter(emoji => !emoji.localOnly).map(emoji => this.renderEmoji(emoji)); @@ -412,9 +410,6 @@ export class ApRendererService { const asPoll = poll ? { type: 'Question', - content: this.apMfmService.getNoteHtml(Object.assign({}, note, { - text: text, - })), [poll.expiresAt && poll.expiresAt < new Date() ? 'closed' : 'endTime']: poll.expiresAt, [poll.multiple ? 'anyOf' : 'oneOf']: poll.choices.map((text, i) => ({ type: 'Note', @@ -432,11 +427,13 @@ export class ApRendererService { attributedTo, summary: summary ?? undefined, content: content ?? undefined, - _misskey_content: text, - source: { - content: text, - mediaType: 'text/x.misskeymarkdown', - }, + ...(noMisskeyContent ? {} : { + _misskey_content: text, + source: { + content: text, + mediaType: 'text/x.misskeymarkdown', + }, + }), _misskey_quote: quote, quoteUrl: quote, published: this.idService.parse(note.id).date.toISOString(), @@ -625,6 +622,7 @@ export class ApRendererService { 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1', { + Key: 'sec:Key', // as non-standards manuallyApprovesFollowers: 'as:manuallyApprovesFollowers', sensitive: 'as:sensitive', diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts index e165c5e960..93ac8ce9a7 100644 --- a/packages/backend/src/core/activitypub/ApRequestService.ts +++ b/packages/backend/src/core/activitypub/ApRequestService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -14,6 +14,7 @@ import { HttpRequestService } from '@/core/HttpRequestService.js'; import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; import type Logger from '@/logger.js'; +import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js'; type Request = { url: string; @@ -70,7 +71,7 @@ export class ApRequestCreator { url: u.href, method: 'GET', headers: this.#objectAssignWithLcKey({ - 'Accept': 'application/activity+json, application/ld+json', + 'Accept': 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', 'Date': new Date().toUTCString(), 'Host': new URL(args.url).host, }, args.additionalHeaders), @@ -195,6 +196,9 @@ export class ApRequestService { const res = await this.httpRequestService.send(url, { method: req.request.method, headers: req.request.headers, + }, { + throwErrorWhenResponseNotOk: true, + validators: [validateContentTypeSetAsActivityPub], }); return await res.json(); diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts index 9ca63c9ec5..bb3c40f093 100644 --- a/packages/backend/src/core/activitypub/ApResolverService.ts +++ b/packages/backend/src/core/activitypub/ApResolverService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -105,7 +105,7 @@ export class Resolver { const object = (this.user ? await this.apRequestService.signedGet(value, this.user) as IObject - : await this.httpRequestService.getJson(value, 'application/activity+json, application/ld+json')) as IObject; + : await this.httpRequestService.getActivityJson(value)) as IObject; if ( Array.isArray(object['@context']) ? diff --git a/packages/backend/src/core/activitypub/LdSignatureService.ts b/packages/backend/src/core/activitypub/LdSignatureService.ts index 39b5ff8abc..9de184336f 100644 --- a/packages/backend/src/core/activitypub/LdSignatureService.ts +++ b/packages/backend/src/core/activitypub/LdSignatureService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -8,6 +8,7 @@ import { Injectable } from '@nestjs/common'; import { HttpRequestService } from '@/core/HttpRequestService.js'; import { bindThis } from '@/decorators.js'; import { CONTEXTS } from './misc/contexts.js'; +import { validateContentTypeSetAsJsonLD } from './misc/validator.js'; import type { JsonLdDocument } from 'jsonld'; import type { JsonLd, RemoteDocument } from 'jsonld/jsonld-spec.js'; @@ -133,7 +134,10 @@ class LdSignature { }, timeout: this.loderTimeout, }, - { throwErrorWhenResponseNotOk: false }, + { + throwErrorWhenResponseNotOk: false, + validators: [validateContentTypeSetAsJsonLD], + }, ).then(res => { if (!res.ok) { throw new Error(`${res.status} ${res.statusText}`); diff --git a/packages/backend/src/core/activitypub/misc/contexts.ts b/packages/backend/src/core/activitypub/misc/contexts.ts index 71c440e5cc..88afdefcd3 100644 --- a/packages/backend/src/core/activitypub/misc/contexts.ts +++ b/packages/backend/src/core/activitypub/misc/contexts.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/activitypub/misc/validator.ts b/packages/backend/src/core/activitypub/misc/validator.ts new file mode 100644 index 0000000000..690beeffef --- /dev/null +++ b/packages/backend/src/core/activitypub/misc/validator.ts @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import type { Response } from 'node-fetch'; + +export function validateContentTypeSetAsActivityPub(response: Response): void { + const contentType = (response.headers.get('content-type') ?? '').toLowerCase(); + + if (contentType === '') { + throw new Error('Validate content type of AP response: No content-type header'); + } + if ( + contentType.startsWith('application/activity+json') || + (contentType.startsWith('application/ld+json;') && contentType.includes('https://www.w3.org/ns/activitystreams')) + ) { + return; + } + throw new Error('Validate content type of AP response: Content type is not application/activity+json or application/ld+json'); +} + +const plusJsonSuffixRegex = /^\s*(application|text)\/[a-zA-Z0-9\.\-\+]+\+json\s*(;|$)/; + +export function validateContentTypeSetAsJsonLD(response: Response): void { + const contentType = (response.headers.get('content-type') ?? '').toLowerCase(); + + if (contentType === '') { + throw new Error('Validate content type of JSON LD: No content-type header'); + } + if ( + contentType.startsWith('application/ld+json') || + contentType.startsWith('application/json') || + plusJsonSuffixRegex.test(contentType) + ) { + return; + } + throw new Error('Validate content type of JSON LD: Content type is not application/ld+json or application/json'); +} diff --git a/packages/backend/src/core/activitypub/models/ApImageService.ts b/packages/backend/src/core/activitypub/models/ApImageService.ts index a4cd533892..89b6ef23d0 100644 --- a/packages/backend/src/core/activitypub/models/ApImageService.ts +++ b/packages/backend/src/core/activitypub/models/ApImageService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/activitypub/models/ApMentionService.ts b/packages/backend/src/core/activitypub/models/ApMentionService.ts index 9aa8ba5ede..0ced7e88af 100644 --- a/packages/backend/src/core/activitypub/models/ApMentionService.ts +++ b/packages/backend/src/core/activitypub/models/ApMentionService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -8,6 +8,7 @@ import promiseLimit from 'promise-limit'; import type { MiUser } from '@/models/_.js'; import { toArray, unique } from '@/misc/prelude/array.js'; import { bindThis } from '@/decorators.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { isMention } from '../type.js'; import { Resolver } from '../ApResolverService.js'; import { ApPersonService } from './ApPersonService.js'; @@ -27,7 +28,7 @@ export class ApMentionService { const limit = promiseLimit(2); const mentionedUsers = (await Promise.all( hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))), - )).filter((x): x is MiUser => x != null); + )).filter(isNotNull); return mentionedUsers; } diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index e3eccd5405..b2fd435f93 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -24,6 +24,8 @@ import { StatusError } from '@/misc/status-error.js'; import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; import { checkHttps } from '@/misc/check-https.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js'; import { ApLoggerService } from '../ApLoggerService.js'; import { ApMfmService } from '../ApMfmService.js'; @@ -151,11 +153,47 @@ export class ApNoteService { throw new Error('invalid note.attributedTo: ' + note.attributedTo); } - const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo), resolver) as MiRemoteUser; + const uri = getOneApId(note.attributedTo); - // 投稿者が凍結されていたらスキップ + // ローカルで投稿者を検索し、もし凍結されていたらスキップ + const cachedActor = await this.apPersonService.fetchPerson(uri) as MiRemoteUser; + if (cachedActor && cachedActor.isSuspended) { + throw new IdentifiableError('85ab9bd7-3a41-4530-959d-f07073900109', 'actor has been suspended'); + } + + const apMentions = await this.apMentionService.extractApMentions(note.tag, resolver); + const apHashtags = extractApHashtags(note.tag); + + const cw = note.summary === '' ? null : note.summary; + + // テキストのパース + let text: string | null = null; + if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source.content === 'string') { + text = note.source.content; + } else if (typeof note._misskey_content !== 'undefined') { + text = note._misskey_content; + } else if (typeof note.content === 'string') { + text = this.apMfmService.htmlToMfm(note.content, note.tag); + } + + const poll = await this.apQuestionService.extractPollFromQuestion(note, resolver).catch(() => undefined); + + //#region Contents Check + // 添付ファイルとユーザーをこのサーバーで登録する前に内容をチェックする + /** + * 禁止ワードチェック + */ + const hasProhibitedWords = await this.noteCreateService.checkProhibitedWordsContain({ cw, text, pollChoices: poll?.choices }); + if (hasProhibitedWords) { + throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Note contains prohibited words'); + } + //#endregion + + const actor = cachedActor ?? await this.apPersonService.resolvePerson(uri, resolver) as MiRemoteUser; + + // 解決した投稿者が凍結されていたらスキップ if (actor.isSuspended) { - throw new Error('actor has been suspended'); + throw new IdentifiableError('85ab9bd7-3a41-4530-959d-f07073900109', 'actor has been suspended'); } const noteAudience = await this.apAudienceService.parseAudience(actor, note.to, note.cc, resolver); @@ -170,9 +208,6 @@ export class ApNoteService { } } - const apMentions = await this.apMentionService.extractApMentions(note.tag, resolver); - const apHashtags = extractApHashtags(note.tag); - // 添付ファイル // TODO: attachmentは必ずしもImageではない // TODO: attachmentは必ずしも配列ではない @@ -221,7 +256,7 @@ export class ApNoteService { } }; - const uris = unique([note._misskey_quote, note.quoteUrl].filter((x): x is string => typeof x === 'string')); + const uris = unique([note._misskey_quote, note.quoteUrl].filter(isNotNull)); const results = await Promise.all(uris.map(tryResolveNote)); quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0); @@ -232,18 +267,6 @@ export class ApNoteService { } } - const cw = note.summary === '' ? null : note.summary; - - // テキストのパース - let text: string | null = null; - if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source.content === 'string') { - text = note.source.content; - } else if (typeof note._misskey_content !== 'undefined') { - text = note._misskey_content; - } else if (typeof note.content === 'string') { - text = this.apMfmService.htmlToMfm(note.content, note.tag); - } - // vote if (reply && reply.hasPoll) { const poll = await this.pollsRepository.findOneByOrFail({ noteId: reply.id }); @@ -273,8 +296,6 @@ export class ApNoteService { const apEmojis = emojis.map(emoji => emoji.name); - const poll = await this.apQuestionService.extractPollFromQuestion(note, resolver).catch(() => undefined); - try { return await this.noteCreateService.create(actor, { createdAt: note.published ? new Date(note.published) : null, diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index bf38d5fd60..744b1ea683 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -38,6 +38,7 @@ import { MetaService } from '@/core/MetaService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import type { AccountMoveService } from '@/core/AccountMoveService.js'; import { checkHttps } from '@/misc/check-https.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js'; import { extractApHashtags } from './tag.js'; import type { OnModuleInit } from '@nestjs/common'; @@ -225,20 +226,37 @@ export class ApPersonService implements OnModuleInit { return null; } - private async resolveAvatarAndBanner(user: MiRemoteUser, icon: any, image: any): Promise> { + private async resolveAvatarAndBanner(user: MiRemoteUser, icon: any, image: any): Promise>> { + if (user == null) throw new Error('failed to create user: user is null'); + const [avatar, banner] = await Promise.all([icon, image].map(img => { - if (img == null) return null; - if (user == null) throw new Error('failed to create user: user is null'); + // if we have an explicitly missing image, return an + // explicitly-null set of values + if ((img == null) || (typeof img === 'object' && img.url == null)) { + return { id: null, url: null, blurhash: null }; + } + return this.apImageService.resolveImage(user, img).catch(() => null); })); + /* + we don't want to return nulls on errors! if the database fields + are already null, nothing changes; if the database has old + values, we should keep those. The exception is if the remote has + actually removed the images: in that case, the block above + returns the special {id:null}&c value, and we return those + */ return { - avatarId: avatar?.id ?? null, - bannerId: banner?.id ?? null, - avatarUrl: avatar ? this.driveFileEntityService.getPublicUrl(avatar, 'avatar') : null, - bannerUrl: banner ? this.driveFileEntityService.getPublicUrl(banner) : null, - avatarBlurhash: avatar?.blurhash ?? null, - bannerBlurhash: banner?.blurhash ?? null, + ...( avatar ? { + avatarId: avatar.id, + avatarUrl: avatar.url ? this.driveFileEntityService.getPublicUrl(avatar, 'avatar') : null, + avatarBlurhash: avatar.blurhash, + } : {}), + ...( banner ? { + bannerId: banner.id, + bannerUrl: banner.url ? this.driveFileEntityService.getPublicUrl(banner) : null, + bannerBlurhash: banner.blurhash, + } : {}), }; } @@ -619,7 +637,7 @@ export class ApPersonService implements OnModuleInit { // とりあえずidを別の時間で生成して順番を維持 let td = 0; - for (const note of featuredNotes.filter((note): note is MiNote => note != null)) { + for (const note of featuredNotes.filter(isNotNull)) { td -= 1000; transactionalEntityManager.insert(MiUserNotePining, { id: this.idService.gen(Date.now() + td), diff --git a/packages/backend/src/core/activitypub/models/ApQuestionService.ts b/packages/backend/src/core/activitypub/models/ApQuestionService.ts index 27bd62268b..d1936cfe1d 100644 --- a/packages/backend/src/core/activitypub/models/ApQuestionService.ts +++ b/packages/backend/src/core/activitypub/models/ApQuestionService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -10,6 +10,7 @@ import type { Config } from '@/config.js'; import type { IPoll } from '@/models/Poll.js'; import type Logger from '@/logger.js'; import { bindThis } from '@/decorators.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { isQuestion } from '../type.js'; import { ApLoggerService } from '../ApLoggerService.js'; import { ApResolverService } from '../ApResolverService.js'; @@ -51,7 +52,7 @@ export class ApQuestionService { const choices = question[multiple ? 'anyOf' : 'oneOf'] ?.map((x) => x.name) - .filter((x): x is string => typeof x === 'string') + .filter(isNotNull) ?? []; const votes = question[multiple ? 'anyOf' : 'oneOf']?.map((x) => x.replies?.totalItems ?? x._misskey_votes ?? 0); diff --git a/packages/backend/src/core/activitypub/models/icon.ts b/packages/backend/src/core/activitypub/models/icon.ts index 9fed78020d..5722507a3b 100644 --- a/packages/backend/src/core/activitypub/models/icon.ts +++ b/packages/backend/src/core/activitypub/models/icon.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/activitypub/models/identifier.ts b/packages/backend/src/core/activitypub/models/identifier.ts index 22a7b0a76e..dce4f410b4 100644 --- a/packages/backend/src/core/activitypub/models/identifier.ts +++ b/packages/backend/src/core/activitypub/models/identifier.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/activitypub/models/tag.ts b/packages/backend/src/core/activitypub/models/tag.ts index 772ea11864..e7ceec3262 100644 --- a/packages/backend/src/core/activitypub/models/tag.ts +++ b/packages/backend/src/core/activitypub/models/tag.ts @@ -1,9 +1,10 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ import { toArray } from '@/misc/prelude/array.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { isHashtag } from '../type.js'; import type { IObject, IApHashtag } from '../type.js'; @@ -15,7 +16,7 @@ export function extractApHashtags(tags: IObject | IObject[] | null | undefined): return hashtags.map(tag => { const m = tag.name.match(/^#(.+)/); return m ? m[1] : null; - }).filter((x): x is string => x != null); + }).filter(isNotNull); } export function extractApHashtagObjects(tags: IObject | IObject[] | null | undefined): IApHashtag[] { diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index d9fcc99066..b43dddad61 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/ChartLoggerService.ts b/packages/backend/src/core/chart/ChartLoggerService.ts index bd90efec64..afc728d564 100644 --- a/packages/backend/src/core/chart/ChartLoggerService.ts +++ b/packages/backend/src/core/chart/ChartLoggerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/ChartManagementService.ts b/packages/backend/src/core/chart/ChartManagementService.ts index f751a68cb4..79681370a1 100644 --- a/packages/backend/src/core/chart/ChartManagementService.ts +++ b/packages/backend/src/core/chart/ChartManagementService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/active-users.ts b/packages/backend/src/core/chart/charts/active-users.ts index f0918e059c..05905f3782 100644 --- a/packages/backend/src/core/chart/charts/active-users.ts +++ b/packages/backend/src/core/chart/charts/active-users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/ap-request.ts b/packages/backend/src/core/chart/charts/ap-request.ts index 03c9b42be1..04e771a95b 100644 --- a/packages/backend/src/core/chart/charts/ap-request.ts +++ b/packages/backend/src/core/chart/charts/ap-request.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/drive.ts b/packages/backend/src/core/chart/charts/drive.ts index bbcbf1a955..613e074a9f 100644 --- a/packages/backend/src/core/chart/charts/drive.ts +++ b/packages/backend/src/core/chart/charts/drive.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/active-users.ts b/packages/backend/src/core/chart/charts/entities/active-users.ts index e68022ef29..fc2b88a2bb 100644 --- a/packages/backend/src/core/chart/charts/entities/active-users.ts +++ b/packages/backend/src/core/chart/charts/entities/active-users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/ap-request.ts b/packages/backend/src/core/chart/charts/entities/ap-request.ts index a824515255..93e47e081b 100644 --- a/packages/backend/src/core/chart/charts/entities/ap-request.ts +++ b/packages/backend/src/core/chart/charts/entities/ap-request.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/drive.ts b/packages/backend/src/core/chart/charts/entities/drive.ts index 4a56bd45c5..4ea16da38c 100644 --- a/packages/backend/src/core/chart/charts/entities/drive.ts +++ b/packages/backend/src/core/chart/charts/entities/drive.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/federation.ts b/packages/backend/src/core/chart/charts/entities/federation.ts index e067c71a7f..5ed7804343 100644 --- a/packages/backend/src/core/chart/charts/entities/federation.ts +++ b/packages/backend/src/core/chart/charts/entities/federation.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/instance.ts b/packages/backend/src/core/chart/charts/entities/instance.ts index 4ea10d56d1..d0cac3e73f 100644 --- a/packages/backend/src/core/chart/charts/entities/instance.ts +++ b/packages/backend/src/core/chart/charts/entities/instance.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/notes.ts b/packages/backend/src/core/chart/charts/entities/notes.ts index 26e2529b17..325236ab35 100644 --- a/packages/backend/src/core/chart/charts/entities/notes.ts +++ b/packages/backend/src/core/chart/charts/entities/notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/per-user-drive.ts b/packages/backend/src/core/chart/charts/entities/per-user-drive.ts index aec3dd5140..25d4619dde 100644 --- a/packages/backend/src/core/chart/charts/entities/per-user-drive.ts +++ b/packages/backend/src/core/chart/charts/entities/per-user-drive.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/per-user-following.ts b/packages/backend/src/core/chart/charts/entities/per-user-following.ts index afb5813058..1618bd22f3 100644 --- a/packages/backend/src/core/chart/charts/entities/per-user-following.ts +++ b/packages/backend/src/core/chart/charts/entities/per-user-following.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/per-user-notes.ts b/packages/backend/src/core/chart/charts/entities/per-user-notes.ts index 60a0b01c8e..30404b2e48 100644 --- a/packages/backend/src/core/chart/charts/entities/per-user-notes.ts +++ b/packages/backend/src/core/chart/charts/entities/per-user-notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/per-user-pv.ts b/packages/backend/src/core/chart/charts/entities/per-user-pv.ts index 78d4464d7e..7a903afad4 100644 --- a/packages/backend/src/core/chart/charts/entities/per-user-pv.ts +++ b/packages/backend/src/core/chart/charts/entities/per-user-pv.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/per-user-reactions.ts b/packages/backend/src/core/chart/charts/entities/per-user-reactions.ts index 761101d479..bb62bb2386 100644 --- a/packages/backend/src/core/chart/charts/entities/per-user-reactions.ts +++ b/packages/backend/src/core/chart/charts/entities/per-user-reactions.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/test-grouped.ts b/packages/backend/src/core/chart/charts/entities/test-grouped.ts index 15eb1fd1f8..599c1dc136 100644 --- a/packages/backend/src/core/chart/charts/entities/test-grouped.ts +++ b/packages/backend/src/core/chart/charts/entities/test-grouped.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/test-intersection.ts b/packages/backend/src/core/chart/charts/entities/test-intersection.ts index 2ef63977a5..d29b39716c 100644 --- a/packages/backend/src/core/chart/charts/entities/test-intersection.ts +++ b/packages/backend/src/core/chart/charts/entities/test-intersection.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/test-unique.ts b/packages/backend/src/core/chart/charts/entities/test-unique.ts index 56233585db..bdaa1716ed 100644 --- a/packages/backend/src/core/chart/charts/entities/test-unique.ts +++ b/packages/backend/src/core/chart/charts/entities/test-unique.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/test.ts b/packages/backend/src/core/chart/charts/entities/test.ts index 163db4e79f..c80ff55c99 100644 --- a/packages/backend/src/core/chart/charts/entities/test.ts +++ b/packages/backend/src/core/chart/charts/entities/test.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/entities/users.ts b/packages/backend/src/core/chart/charts/entities/users.ts index c7bffd3fd4..f94a5029d7 100644 --- a/packages/backend/src/core/chart/charts/entities/users.ts +++ b/packages/backend/src/core/chart/charts/entities/users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/federation.ts b/packages/backend/src/core/chart/charts/federation.ts index fc474b002b..5e4555ee96 100644 --- a/packages/backend/src/core/chart/charts/federation.ts +++ b/packages/backend/src/core/chart/charts/federation.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/instance.ts b/packages/backend/src/core/chart/charts/instance.ts index 9df0afb02e..97f3bc6f2b 100644 --- a/packages/backend/src/core/chart/charts/instance.ts +++ b/packages/backend/src/core/chart/charts/instance.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/notes.ts b/packages/backend/src/core/chart/charts/notes.ts index df3295dbac..f763b5fffa 100644 --- a/packages/backend/src/core/chart/charts/notes.ts +++ b/packages/backend/src/core/chart/charts/notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/per-user-drive.ts b/packages/backend/src/core/chart/charts/per-user-drive.ts index 18354359c8..404964d8b7 100644 --- a/packages/backend/src/core/chart/charts/per-user-drive.ts +++ b/packages/backend/src/core/chart/charts/per-user-drive.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/per-user-following.ts b/packages/backend/src/core/chart/charts/per-user-following.ts index 79bff2cb66..588ac638de 100644 --- a/packages/backend/src/core/chart/charts/per-user-following.ts +++ b/packages/backend/src/core/chart/charts/per-user-following.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/per-user-notes.ts b/packages/backend/src/core/chart/charts/per-user-notes.ts index 0db0e6f07f..e4900772bb 100644 --- a/packages/backend/src/core/chart/charts/per-user-notes.ts +++ b/packages/backend/src/core/chart/charts/per-user-notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/per-user-pv.ts b/packages/backend/src/core/chart/charts/per-user-pv.ts index cf1b4c71f6..31708fefa8 100644 --- a/packages/backend/src/core/chart/charts/per-user-pv.ts +++ b/packages/backend/src/core/chart/charts/per-user-pv.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/per-user-reactions.ts b/packages/backend/src/core/chart/charts/per-user-reactions.ts index 9f4f6e9651..c29c4d2870 100644 --- a/packages/backend/src/core/chart/charts/per-user-reactions.ts +++ b/packages/backend/src/core/chart/charts/per-user-reactions.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/test-grouped.ts b/packages/backend/src/core/chart/charts/test-grouped.ts index 00fb872237..7a2844f4ed 100644 --- a/packages/backend/src/core/chart/charts/test-grouped.ts +++ b/packages/backend/src/core/chart/charts/test-grouped.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/test-intersection.ts b/packages/backend/src/core/chart/charts/test-intersection.ts index 45a7e805c5..b8d0556c9f 100644 --- a/packages/backend/src/core/chart/charts/test-intersection.ts +++ b/packages/backend/src/core/chart/charts/test-intersection.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/test-unique.ts b/packages/backend/src/core/chart/charts/test-unique.ts index e9d38eaf13..f94e008059 100644 --- a/packages/backend/src/core/chart/charts/test-unique.ts +++ b/packages/backend/src/core/chart/charts/test-unique.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/test.ts b/packages/backend/src/core/chart/charts/test.ts index 4dd6063b5b..a90dc8f99b 100644 --- a/packages/backend/src/core/chart/charts/test.ts +++ b/packages/backend/src/core/chart/charts/test.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/charts/users.ts b/packages/backend/src/core/chart/charts/users.ts index c2026c2aea..d148fc629b 100644 --- a/packages/backend/src/core/chart/charts/users.ts +++ b/packages/backend/src/core/chart/charts/users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/chart/core.ts b/packages/backend/src/core/chart/core.ts index 8d0a89f2d6..aa0cb9dc2b 100644 --- a/packages/backend/src/core/chart/core.ts +++ b/packages/backend/src/core/chart/core.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -94,6 +94,29 @@ type ToJsonSchema = { }; export function getJsonSchema(schema: S): ToJsonSchema>> { + const unflatten = (str: string, parent: Record) => { + const keys = str.split('.'); + const key = keys.shift(); + const nextKey = keys[0]; + + if (key == null) return; + + if (parent.properties[key] == null) { + parent.properties[key] = nextKey ? { + type: 'object', + properties: {}, + required: [], + } : { + type: 'array', + items: { + type: 'number', + }, + }; + } + + if (nextKey) unflatten(keys.join('.'), parent.properties[key] as Record); + }; + const jsonSchema = { type: 'object', properties: {} as Record, @@ -101,10 +124,7 @@ export function getJsonSchema(schema: S): ToJsonSchema>>; diff --git a/packages/backend/src/core/chart/entities.ts b/packages/backend/src/core/chart/entities.ts index b6a1299a2f..e424f2c8c5 100644 --- a/packages/backend/src/core/chart/entities.ts +++ b/packages/backend/src/core/chart/entities.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/AbuseUserReportEntityService.ts b/packages/backend/src/core/entities/AbuseUserReportEntityService.ts index 97de891ece..49f256d870 100644 --- a/packages/backend/src/core/entities/AbuseUserReportEntityService.ts +++ b/packages/backend/src/core/entities/AbuseUserReportEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -38,13 +38,13 @@ export class AbuseUserReportEntityService { targetUserId: report.targetUserId, assigneeId: report.assigneeId, reporter: this.userEntityService.pack(report.reporter ?? report.reporterId, null, { - detail: true, + schema: 'UserDetailedNotMe', }), targetUser: this.userEntityService.pack(report.targetUser ?? report.targetUserId, null, { - detail: true, + schema: 'UserDetailedNotMe', }), assignee: report.assigneeId ? this.userEntityService.pack(report.assignee ?? report.assigneeId, null, { - detail: true, + schema: 'UserDetailedNotMe', }) : null, forwarded: report.forwarded, }); diff --git a/packages/backend/src/core/entities/AntennaEntityService.ts b/packages/backend/src/core/entities/AntennaEntityService.ts index 265a61e8ad..64d6a3c978 100644 --- a/packages/backend/src/core/entities/AntennaEntityService.ts +++ b/packages/backend/src/core/entities/AntennaEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/AppEntityService.ts b/packages/backend/src/core/entities/AppEntityService.ts index 14a93cda5b..785b84689a 100644 --- a/packages/backend/src/core/entities/AppEntityService.ts +++ b/packages/backend/src/core/entities/AppEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/AuthSessionEntityService.ts b/packages/backend/src/core/entities/AuthSessionEntityService.ts index fd356cc89d..72873680c9 100644 --- a/packages/backend/src/core/entities/AuthSessionEntityService.ts +++ b/packages/backend/src/core/entities/AuthSessionEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/BlockingEntityService.ts b/packages/backend/src/core/entities/BlockingEntityService.ts index b4760346b7..c8c1520ceb 100644 --- a/packages/backend/src/core/entities/BlockingEntityService.ts +++ b/packages/backend/src/core/entities/BlockingEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -37,7 +37,7 @@ export class BlockingEntityService { createdAt: this.idService.parse(blocking.id).date.toISOString(), blockeeId: blocking.blockeeId, blockee: this.userEntityService.pack(blocking.blockeeId, me, { - detail: true, + schema: 'UserDetailedNotMe', }), }); } diff --git a/packages/backend/src/core/entities/ChannelEntityService.ts b/packages/backend/src/core/entities/ChannelEntityService.ts index 305946b8a6..1ba7ca8e57 100644 --- a/packages/backend/src/core/entities/ChannelEntityService.ts +++ b/packages/backend/src/core/entities/ChannelEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -51,14 +51,14 @@ export class ChannelEntityService { const banner = channel.bannerId ? await this.driveFilesRepository.findOneBy({ id: channel.bannerId }) : null; - const isFollowing = meId ? await this.channelFollowingsRepository.exist({ + const isFollowing = meId ? await this.channelFollowingsRepository.exists({ where: { followerId: meId, followeeId: channel.id, }, }) : false; - const isFavorited = meId ? await this.channelFavoritesRepository.exist({ + const isFavorited = meId ? await this.channelFavoritesRepository.exists({ where: { userId: meId, channelId: channel.id, diff --git a/packages/backend/src/core/entities/ClipEntityService.ts b/packages/backend/src/core/entities/ClipEntityService.ts index 96422894fd..26fcd6714d 100644 --- a/packages/backend/src/core/entities/ClipEntityService.ts +++ b/packages/backend/src/core/entities/ClipEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -46,7 +46,7 @@ export class ClipEntityService { description: clip.description, isPublic: clip.isPublic, favoritedCount: await this.clipFavoritesRepository.countBy({ clipId: clip.id }), - isFavorited: meId ? await this.clipFavoritesRepository.exist({ where: { clipId: clip.id, userId: meId } }) : undefined, + isFavorited: meId ? await this.clipFavoritesRepository.exists({ where: { clipId: clip.id, userId: meId } }) : undefined, }); } diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts index 14be000367..8affe2b3bf 100644 --- a/packages/backend/src/core/entities/DriveFileEntityService.ts +++ b/packages/backend/src/core/entities/DriveFileEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -259,7 +259,7 @@ export class DriveFileEntityService { options?: PackOptions, ): Promise[]> { const items = await Promise.all(files.map(f => this.packNullable(f, options))); - return items.filter((x): x is Packed<'DriveFile'> => x != null); + return items.filter(isNotNull); } @bindThis diff --git a/packages/backend/src/core/entities/DriveFolderEntityService.ts b/packages/backend/src/core/entities/DriveFolderEntityService.ts index 8fa78154b9..299f23ad38 100644 --- a/packages/backend/src/core/entities/DriveFolderEntityService.ts +++ b/packages/backend/src/core/entities/DriveFolderEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/EmojiEntityService.ts b/packages/backend/src/core/entities/EmojiEntityService.ts index 5b97cfad5e..841bd731c0 100644 --- a/packages/backend/src/core/entities/EmojiEntityService.ts +++ b/packages/backend/src/core/entities/EmojiEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -31,6 +31,7 @@ export class EmojiEntityService { category: emoji.category, // || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ) url: emoji.publicUrl || emoji.originalUrl, + localOnly: emoji.localOnly ? true : undefined, isSensitive: emoji.isSensitive ? true : undefined, roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length > 0 ? emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : undefined, }; diff --git a/packages/backend/src/core/entities/FlashEntityService.ts b/packages/backend/src/core/entities/FlashEntityService.ts index dc335d9975..db4cf6d360 100644 --- a/packages/backend/src/core/entities/FlashEntityService.ts +++ b/packages/backend/src/core/entities/FlashEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -42,12 +42,12 @@ export class FlashEntityService { createdAt: this.idService.parse(flash.id).date.toISOString(), updatedAt: flash.updatedAt.toISOString(), userId: flash.userId, - user: this.userEntityService.pack(flash.user ?? flash.userId, me), // { detail: true } すると無限ループするので注意 + user: this.userEntityService.pack(flash.user ?? flash.userId, me), // { schema: 'UserDetailed' } すると無限ループするので注意 title: flash.title, summary: flash.summary, script: flash.script, likedCount: flash.likedCount, - isLiked: meId ? await this.flashLikesRepository.exist({ where: { flashId: flash.id, userId: meId } }) : undefined, + isLiked: meId ? await this.flashLikesRepository.exists({ where: { flashId: flash.id, userId: meId } }) : undefined, }); } diff --git a/packages/backend/src/core/entities/FlashLikeEntityService.ts b/packages/backend/src/core/entities/FlashLikeEntityService.ts index 2eff86217a..6e0b9d6e11 100644 --- a/packages/backend/src/core/entities/FlashLikeEntityService.ts +++ b/packages/backend/src/core/entities/FlashLikeEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/FollowRequestEntityService.ts b/packages/backend/src/core/entities/FollowRequestEntityService.ts index 0e0fec9f46..763b75101f 100644 --- a/packages/backend/src/core/entities/FollowRequestEntityService.ts +++ b/packages/backend/src/core/entities/FollowRequestEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/FollowingEntityService.ts b/packages/backend/src/core/entities/FollowingEntityService.ts index 52aa979677..24cd33e3f7 100644 --- a/packages/backend/src/core/entities/FollowingEntityService.ts +++ b/packages/backend/src/core/entities/FollowingEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -89,10 +89,10 @@ export class FollowingEntityService { followeeId: following.followeeId, followerId: following.followerId, followee: opts.populateFollowee ? this.userEntityService.pack(following.followee ?? following.followeeId, me, { - detail: true, + schema: 'UserDetailedNotMe', }) : undefined, follower: opts.populateFollower ? this.userEntityService.pack(following.follower ?? following.followerId, me, { - detail: true, + schema: 'UserDetailedNotMe', }) : undefined, }); } diff --git a/packages/backend/src/core/entities/GalleryLikeEntityService.ts b/packages/backend/src/core/entities/GalleryLikeEntityService.ts index e740701888..f199a81b4d 100644 --- a/packages/backend/src/core/entities/GalleryLikeEntityService.ts +++ b/packages/backend/src/core/entities/GalleryLikeEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/GalleryPostEntityService.ts b/packages/backend/src/core/entities/GalleryPostEntityService.ts index d7b960e0d9..101182a9e5 100644 --- a/packages/backend/src/core/entities/GalleryPostEntityService.ts +++ b/packages/backend/src/core/entities/GalleryPostEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -53,7 +53,7 @@ export class GalleryPostEntityService { tags: post.tags.length > 0 ? post.tags : undefined, isSensitive: post.isSensitive, likedCount: post.likedCount, - isLiked: meId ? await this.galleryLikesRepository.exist({ where: { postId: post.id, userId: meId } }) : undefined, + isLiked: meId ? await this.galleryLikesRepository.exists({ where: { postId: post.id, userId: meId } }) : undefined, }); } diff --git a/packages/backend/src/core/entities/HashtagEntityService.ts b/packages/backend/src/core/entities/HashtagEntityService.ts index 006e267b12..d798b15807 100644 --- a/packages/backend/src/core/entities/HashtagEntityService.ts +++ b/packages/backend/src/core/entities/HashtagEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/InstanceEntityService.ts b/packages/backend/src/core/entities/InstanceEntityService.ts index 7d16a7a80e..e46bd8b963 100644 --- a/packages/backend/src/core/entities/InstanceEntityService.ts +++ b/packages/backend/src/core/entities/InstanceEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -8,12 +8,15 @@ import type { Packed } from '@/misc/json-schema.js'; import type { MiInstance } from '@/models/Instance.js'; import { MetaService } from '@/core/MetaService.js'; import { bindThis } from '@/decorators.js'; -import { UtilityService } from '../UtilityService.js'; +import { UtilityService } from '@/core/UtilityService.js'; +import { RoleService } from '@/core/RoleService.js'; +import { MiUser } from '@/models/User.js'; @Injectable() export class InstanceEntityService { constructor( private metaService: MetaService, + private roleService: RoleService, private utilityService: UtilityService, ) { @@ -22,8 +25,11 @@ export class InstanceEntityService { @bindThis public async pack( instance: MiInstance, + me?: { id: MiUser['id']; } | null | undefined, ): Promise> { const meta = await this.metaService.fetch(); + const iAmModerator = me ? await this.roleService.isModerator(me as MiUser) : false; + return { id: instance.id, firstRetrievedAt: instance.firstRetrievedAt.toISOString(), @@ -48,6 +54,7 @@ export class InstanceEntityService { themeColor: instance.themeColor, infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null, latestRequestReceivedAt: instance.latestRequestReceivedAt ? instance.latestRequestReceivedAt.toISOString() : null, + moderationNote: iAmModerator ? instance.moderationNote : null, }; } diff --git a/packages/backend/src/core/entities/InviteCodeEntityService.ts b/packages/backend/src/core/entities/InviteCodeEntityService.ts index 0f15fb5ab2..891543bc0f 100644 --- a/packages/backend/src/core/entities/InviteCodeEntityService.ts +++ b/packages/backend/src/core/entities/InviteCodeEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts new file mode 100644 index 0000000000..b50d76288f --- /dev/null +++ b/packages/backend/src/core/entities/MetaEntityService.ts @@ -0,0 +1,154 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Brackets } from 'typeorm'; +import { Inject, Injectable } from '@nestjs/common'; +import JSON5 from 'json5'; +import type { Packed } from '@/misc/json-schema.js'; +import type { MiMeta } from '@/models/Meta.js'; +import type { AdsRepository } from '@/models/_.js'; +import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; +import { MetaService } from '@/core/MetaService.js'; +import { bindThis } from '@/decorators.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { InstanceActorService } from '@/core/InstanceActorService.js'; +import type { Config } from '@/config.js'; +import { DI } from '@/di-symbols.js'; +import { DEFAULT_POLICIES } from '@/core/RoleService.js'; + +@Injectable() +export class MetaEntityService { + constructor( + @Inject(DI.config) + private config: Config, + + @Inject(DI.adsRepository) + private adsRepository: AdsRepository, + + private userEntityService: UserEntityService, + private metaService: MetaService, + private instanceActorService: InstanceActorService, + ) { } + + @bindThis + public async pack(meta?: MiMeta): Promise> { + let instance = meta; + + if (!instance) { + instance = await this.metaService.fetch(); + } + + const ads = await this.adsRepository.createQueryBuilder('ads') + .where('ads.expiresAt > :now', { now: new Date() }) + .andWhere('ads.startsAt <= :now', { now: new Date() }) + .andWhere(new Brackets(qb => { + // 曜日のビットフラグを確認する + qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << new Date().getDay() }) + .orWhere('ads.dayOfWeek = 0'); + })) + .getMany(); + + const packed: Packed<'MetaLite'> = { + maintainerName: instance.maintainerName, + maintainerEmail: instance.maintainerEmail, + + version: this.config.version, + providesTarball: this.config.publishTarballInsteadOfProvideRepositoryUrl, + + name: instance.name, + shortName: instance.shortName, + uri: this.config.url, + description: instance.description, + langs: instance.langs, + tosUrl: instance.termsOfServiceUrl, + repositoryUrl: instance.repositoryUrl, + feedbackUrl: instance.feedbackUrl, + impressumUrl: instance.impressumUrl, + privacyPolicyUrl: instance.privacyPolicyUrl, + disableRegistration: instance.disableRegistration, + emailRequiredForSignup: instance.emailRequiredForSignup, + enableHcaptcha: instance.enableHcaptcha, + hcaptchaSiteKey: instance.hcaptchaSiteKey, + enableMcaptcha: instance.enableMcaptcha, + mcaptchaSiteKey: instance.mcaptchaSitekey, + mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl, + enableRecaptcha: instance.enableRecaptcha, + recaptchaSiteKey: instance.recaptchaSiteKey, + enableTurnstile: instance.enableTurnstile, + turnstileSiteKey: instance.turnstileSiteKey, + swPublickey: instance.swPublicKey, + themeColor: instance.themeColor, + mascotImageUrl: instance.mascotImageUrl ?? '/assets/ai.png', + bannerUrl: instance.bannerUrl, + infoImageUrl: instance.infoImageUrl, + serverErrorImageUrl: instance.serverErrorImageUrl, + notFoundImageUrl: instance.notFoundImageUrl, + iconUrl: instance.iconUrl, + backgroundImageUrl: instance.backgroundImageUrl, + logoImageUrl: instance.logoImageUrl, + maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, + // クライアントの手間を減らすためあらかじめJSONに変換しておく + defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null, + defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null, + ads: ads.map(ad => ({ + id: ad.id, + url: ad.url, + place: ad.place, + ratio: ad.ratio, + imageUrl: ad.imageUrl, + dayOfWeek: ad.dayOfWeek, + })), + notesPerOneAd: instance.notesPerOneAd, + enableEmail: instance.enableEmail, + enableServiceWorker: instance.enableServiceWorker, + + translatorAvailable: instance.deeplAuthKey != null, + + serverRules: instance.serverRules, + + policies: { ...DEFAULT_POLICIES, ...instance.policies }, + + mediaProxy: this.config.mediaProxy, + }; + + return packed; + } + + @bindThis + public async packDetailed(meta?: MiMeta): Promise> { + let instance = meta; + + if (!instance) { + instance = await this.metaService.fetch(); + } + + const packed = await this.pack(instance); + + const proxyAccount = instance.proxyAccountId ? await this.userEntityService.pack(instance.proxyAccountId).catch(() => null) : null; + + const packDetailed: Packed<'MetaDetailed'> = { + ...packed, + cacheRemoteFiles: instance.cacheRemoteFiles, + cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles, + requireSetup: !await this.instanceActorService.realLocalUsersPresent(), + proxyAccountName: proxyAccount ? proxyAccount.username : null, + features: { + localTimeline: instance.policies.ltlAvailable, + globalTimeline: instance.policies.gtlAvailable, + registration: !instance.disableRegistration, + emailRequiredForSignup: instance.emailRequiredForSignup, + hcaptcha: instance.enableHcaptcha, + recaptcha: instance.enableRecaptcha, + turnstile: instance.enableTurnstile, + objectStorage: instance.useObjectStorage, + serviceWorker: instance.enableServiceWorker, + miauth: true, + }, + }; + + return packDetailed; + } +} + diff --git a/packages/backend/src/core/entities/ModerationLogEntityService.ts b/packages/backend/src/core/entities/ModerationLogEntityService.ts index 6729ca2671..205e147bd1 100644 --- a/packages/backend/src/core/entities/ModerationLogEntityService.ts +++ b/packages/backend/src/core/entities/ModerationLogEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -37,7 +37,7 @@ export class ModerationLogEntityService { info: log.info, userId: log.userId, user: this.userEntityService.pack(log.user ?? log.userId, null, { - detail: true, + schema: 'UserDetailedNotMe', }), }); } diff --git a/packages/backend/src/core/entities/MutingEntityService.ts b/packages/backend/src/core/entities/MutingEntityService.ts index 9d672169ba..0a52f429a2 100644 --- a/packages/backend/src/core/entities/MutingEntityService.ts +++ b/packages/backend/src/core/entities/MutingEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -39,7 +39,7 @@ export class MutingEntityService { expiresAt: muting.expiresAt ? muting.expiresAt.toISOString() : null, muteeId: muting.muteeId, mutee: this.userEntityService.pack(muting.muteeId, me, { - detail: true, + schema: 'UserDetailedNotMe', }), }); } diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 1777e2cf54..5b6affc6a5 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -108,7 +108,7 @@ export class NoteEntityService implements OnModuleInit { hide = false; } else { // フォロワーかどうか - const isFollowing = await this.followingsRepository.exist({ + const isFollowing = await this.followingsRepository.exists({ where: { followeeId: packedNote.userId, followerId: meId, @@ -164,7 +164,7 @@ export class NoteEntityService implements OnModuleInit { return { multiple: poll.multiple, - expiresAt: poll.expiresAt, + expiresAt: poll.expiresAt?.toISOString() ?? null, choices, }; } @@ -324,9 +324,7 @@ export class NoteEntityService implements OnModuleInit { id: note.id, createdAt: this.idService.parse(note.id).date.toISOString(), userId: note.userId, - user: this.userEntityService.pack(note.user ?? note.userId, me, { - detail: false, - }), + user: this.userEntityService.pack(note.user ?? note.userId, me), text: text, cw: note.cw, visibility: note.visibility, diff --git a/packages/backend/src/core/entities/NoteFavoriteEntityService.ts b/packages/backend/src/core/entities/NoteFavoriteEntityService.ts index 1c9aed413f..3cdafe48ad 100644 --- a/packages/backend/src/core/entities/NoteFavoriteEntityService.ts +++ b/packages/backend/src/core/entities/NoteFavoriteEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/NoteReactionEntityService.ts b/packages/backend/src/core/entities/NoteReactionEntityService.ts index f4aba3e543..3f4fa3cf96 100644 --- a/packages/backend/src/core/entities/NoteReactionEntityService.ts +++ b/packages/backend/src/core/entities/NoteReactionEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -69,4 +69,19 @@ export class NoteReactionEntityService implements OnModuleInit { } : {}), }; } + + @bindThis + public async packMany( + reactions: MiNoteReaction[], + me?: { id: MiUser['id'] } | null | undefined, + options?: { + withNote: boolean; + }, + ): Promise[]> { + const opts = Object.assign({ + withNote: false, + }, options); + + return Promise.all(reactions.map(reaction => this.pack(reaction, me, opts))); + } } diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index 704081ed00..94d56c883b 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -14,14 +14,14 @@ import type { MiNote } from '@/models/Note.js'; import type { Packed } from '@/misc/json-schema.js'; import { bindThis } from '@/decorators.js'; import { isNotNull } from '@/misc/is-not-null.js'; -import { FilterUnionByProperty, notificationTypes } from '@/types.js'; +import { FilterUnionByProperty, groupedNotificationTypes } from '@/types.js'; +import { CacheService } from '@/core/CacheService.js'; import { RoleEntityService } from './RoleEntityService.js'; import type { OnModuleInit } from '@nestjs/common'; import type { UserEntityService } from './UserEntityService.js'; import type { NoteEntityService } from './NoteEntityService.js'; -const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded'] as (typeof notificationTypes[number])[]); -const NOTE_REQUIRED_GROUPED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'renote:grouped', 'quote', 'reaction', 'reaction:grouped', 'pollEnded']); +const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'renote:grouped', 'quote', 'reaction', 'reaction:grouped', 'pollEnded'] as (typeof groupedNotificationTypes[number])[]); @Injectable() export class NotificationEntityService implements OnModuleInit { @@ -41,6 +41,8 @@ export class NotificationEntityService implements OnModuleInit { @Inject(DI.followRequestsRepository) private followRequestsRepository: FollowRequestsRepository, + private cacheService: CacheService, + //private userEntityService: UserEntityService, //private noteEntityService: NoteEntityService, ) { @@ -52,146 +54,61 @@ export class NotificationEntityService implements OnModuleInit { this.roleEntityService = this.moduleRef.get('RoleEntityService'); } - @bindThis - public async pack( - src: MiNotification, + /** + * 通知をパックする共通処理 + */ + async #packInternal ( + src: T, meId: MiUser['id'], // eslint-disable-next-line @typescript-eslint/ban-types options: { - + checkValidNotifier?: boolean; }, hint?: { packedNotes: Map>; - packedUsers: Map>; + packedUsers: Map>; }, - ): Promise> { + ): Promise | null> { const notification = src; - const noteIfNeed = NOTE_REQUIRED_NOTIFICATION_TYPES.has(notification.type) && 'noteId' in notification ? ( + + if (options.checkValidNotifier !== false && !(await this.#isValidNotifier(notification, meId))) return null; + + const needsNote = NOTE_REQUIRED_NOTIFICATION_TYPES.has(notification.type) && 'noteId' in notification; + const noteIfNeed = needsNote ? ( hint?.packedNotes != null ? hint.packedNotes.get(notification.noteId) : this.noteEntityService.pack(notification.noteId, { id: meId }, { detail: true, }) ) : undefined; - const userIfNeed = 'notifierId' in notification ? ( + // if the note has been deleted, don't show this notification + if (needsNote && !noteIfNeed) return null; + + const needsUser = 'notifierId' in notification; + const userIfNeed = needsUser ? ( hint?.packedUsers != null ? hint.packedUsers.get(notification.notifierId) - : this.userEntityService.pack(notification.notifierId, { id: meId }, { - detail: false, - }) - ) : undefined; - const role = notification.type === 'roleAssigned' ? await this.roleEntityService.pack(notification.roleId) : undefined; - - return await awaitAll({ - id: notification.id, - createdAt: new Date(notification.createdAt).toISOString(), - type: notification.type, - userId: 'notifierId' in notification ? notification.notifierId : undefined, - ...(userIfNeed != null ? { user: userIfNeed } : {}), - ...(noteIfNeed != null ? { note: noteIfNeed } : {}), - ...(notification.type === 'reaction' ? { - reaction: notification.reaction, - } : {}), - ...(notification.type === 'roleAssigned' ? { - role: role, - } : {}), - ...(notification.type === 'achievementEarned' ? { - achievement: notification.achievement, - } : {}), - ...(notification.type === 'app' ? { - body: notification.customBody, - header: notification.customHeader, - icon: notification.customIcon, - } : {}), - }); - } - - @bindThis - public async packMany( - notifications: MiNotification[], - meId: MiUser['id'], - ) { - if (notifications.length === 0) return []; - - let validNotifications = notifications; - - const noteIds = validNotifications.map(x => 'noteId' in x ? x.noteId : null).filter(isNotNull); - const notes = noteIds.length > 0 ? await this.notesRepository.find({ - where: { id: In(noteIds) }, - relations: ['user', 'reply', 'reply.user', 'renote', 'renote.user'], - }) : []; - const packedNotesArray = await this.noteEntityService.packMany(notes, { id: meId }, { - detail: true, - }); - const packedNotes = new Map(packedNotesArray.map(p => [p.id, p])); - - validNotifications = validNotifications.filter(x => !('noteId' in x) || packedNotes.has(x.noteId)); - - const userIds = validNotifications.map(x => 'notifierId' in x ? x.notifierId : null).filter(isNotNull); - const users = userIds.length > 0 ? await this.usersRepository.find({ - where: { id: In(userIds) }, - }) : []; - const packedUsersArray = await this.userEntityService.packMany(users, { id: meId }, { - detail: false, - }); - const packedUsers = new Map(packedUsersArray.map(p => [p.id, p])); - - // 既に解決されたフォローリクエストの通知を除外 - const followRequestNotifications = validNotifications.filter((x): x is FilterUnionByProperty => x.type === 'receiveFollowRequest'); - if (followRequestNotifications.length > 0) { - const reqs = await this.followRequestsRepository.find({ - where: { followerId: In(followRequestNotifications.map(x => x.notifierId)) }, - }); - validNotifications = validNotifications.filter(x => (x.type !== 'receiveFollowRequest') || reqs.some(r => r.followerId === x.notifierId)); - } - - return await Promise.all(validNotifications.map(x => this.pack(x, meId, {}, { - packedNotes, - packedUsers, - }))); - } - - @bindThis - public async packGrouped( - src: MiGroupedNotification, - meId: MiUser['id'], - // eslint-disable-next-line @typescript-eslint/ban-types - options: { - - }, - hint?: { - packedNotes: Map>; - packedUsers: Map>; - }, - ): Promise> { - const notification = src; - const noteIfNeed = NOTE_REQUIRED_GROUPED_NOTIFICATION_TYPES.has(notification.type) && 'noteId' in notification ? ( - hint?.packedNotes != null - ? hint.packedNotes.get(notification.noteId) - : this.noteEntityService.pack(notification.noteId, { id: meId }, { - detail: true, - }) - ) : undefined; - const userIfNeed = 'notifierId' in notification ? ( - hint?.packedUsers != null - ? hint.packedUsers.get(notification.notifierId) - : this.userEntityService.pack(notification.notifierId, { id: meId }, { - detail: false, - }) + : this.userEntityService.pack(notification.notifierId, { id: meId }) ) : undefined; + // if the user has been deleted, don't show this notification + if (needsUser && !userIfNeed) return null; + // #region Grouped notifications if (notification.type === 'reaction:grouped') { - const reactions = await Promise.all(notification.reactions.map(async reaction => { + const reactions = (await Promise.all(notification.reactions.map(async reaction => { const user = hint?.packedUsers != null ? hint.packedUsers.get(reaction.userId)! - : await this.userEntityService.pack(reaction.userId, { id: meId }, { - detail: false, - }); + : await this.userEntityService.pack(reaction.userId, { id: meId }); return { user, reaction: reaction.reaction, }; - })); + }))).filter(r => isNotNull(r.user)); + // if all users have been deleted, don't show this notification + if (reactions.length === 0) { + return null; + } + return await awaitAll({ id: notification.id, createdAt: new Date(notification.createdAt).toISOString(), @@ -200,16 +117,19 @@ export class NotificationEntityService implements OnModuleInit { reactions, }); } else if (notification.type === 'renote:grouped') { - const users = await Promise.all(notification.userIds.map(userId => { + const users = (await Promise.all(notification.userIds.map(userId => { const packedUser = hint?.packedUsers != null ? hint.packedUsers.get(userId) : null; if (packedUser) { return packedUser; } - return this.userEntityService.pack(userId, { id: meId }, { - detail: false, - }); - })); + return this.userEntityService.pack(userId, { id: meId }); + }))).filter(isNotNull); + // if all users have been deleted, don't show this notification + if (users.length === 0) { + return null; + } + return await awaitAll({ id: notification.id, createdAt: new Date(notification.createdAt).toISOString(), @@ -218,8 +138,14 @@ export class NotificationEntityService implements OnModuleInit { users, }); } + // #endregion - const role = notification.type === 'roleAssigned' ? await this.roleEntityService.pack(notification.roleId) : undefined; + const needsRole = notification.type === 'roleAssigned'; + const role = needsRole ? await this.roleEntityService.pack(notification.roleId) : undefined; + // if the role has been deleted, don't show this notification + if (needsRole && !role) { + return null; + } return await awaitAll({ id: notification.id, @@ -245,15 +171,16 @@ export class NotificationEntityService implements OnModuleInit { }); } - @bindThis - public async packGroupedMany( - notifications: MiGroupedNotification[], + async #packManyInternal ( + notifications: T[], meId: MiUser['id'], - ) { + ): Promise { if (notifications.length === 0) return []; let validNotifications = notifications; + validNotifications = await this.#filterValidNotifier(validNotifications, meId); + const noteIds = validNotifications.map(x => 'noteId' in x ? x.noteId : null).filter(isNotNull); const notes = noteIds.length > 0 ? await this.notesRepository.find({ where: { id: In(noteIds) }, @@ -275,13 +202,11 @@ export class NotificationEntityService implements OnModuleInit { const users = userIds.length > 0 ? await this.usersRepository.find({ where: { id: In(userIds) }, }) : []; - const packedUsersArray = await this.userEntityService.packMany(users, { id: meId }, { - detail: false, - }); + const packedUsersArray = await this.userEntityService.packMany(users, { id: meId }); const packedUsers = new Map(packedUsersArray.map(p => [p.id, p])); // 既に解決されたフォローリクエストの通知を除外 - const followRequestNotifications = validNotifications.filter((x): x is FilterUnionByProperty => x.type === 'receiveFollowRequest'); + const followRequestNotifications = validNotifications.filter((x): x is FilterUnionByProperty => x.type === 'receiveFollowRequest'); if (followRequestNotifications.length > 0) { const reqs = await this.followRequestsRepository.find({ where: { followerId: In(followRequestNotifications.map(x => x.notifierId)) }, @@ -289,9 +214,107 @@ export class NotificationEntityService implements OnModuleInit { validNotifications = validNotifications.filter(x => (x.type !== 'receiveFollowRequest') || reqs.some(r => r.followerId === x.notifierId)); } - return await Promise.all(validNotifications.map(x => this.packGrouped(x, meId, {}, { - packedNotes, - packedUsers, - }))); + const packPromises = validNotifications.map(x => { + return this.pack( + x, + meId, + { checkValidNotifier: false }, + { packedNotes, packedUsers }, + ); + }); + + return (await Promise.all(packPromises)).filter(isNotNull); + } + + @bindThis + public async pack( + src: MiNotification | MiGroupedNotification, + meId: MiUser['id'], + // eslint-disable-next-line @typescript-eslint/ban-types + options: { + checkValidNotifier?: boolean; + }, + hint?: { + packedNotes: Map>; + packedUsers: Map>; + }, + ): Promise | null> { + return await this.#packInternal(src, meId, options, hint); + } + + @bindThis + public async packMany( + notifications: MiNotification[], + meId: MiUser['id'], + ): Promise { + return await this.#packManyInternal(notifications, meId); + } + + @bindThis + public async packGroupedMany( + notifications: MiGroupedNotification[], + meId: MiUser['id'], + ): Promise { + return await this.#packManyInternal(notifications, meId); + } + + /** + * notifierが存在するか、ミュートされていないか、サスペンドされていないかを確認するvalidator + */ + #validateNotifier ( + notification: T, + userIdsWhoMeMuting: Set, + userMutedInstances: Set, + notifiers: MiUser[], + ): boolean { + if (!('notifierId' in notification)) return true; + if (userIdsWhoMeMuting.has(notification.notifierId)) return false; + + const notifier = notifiers.find(x => x.id === notification.notifierId) ?? null; + + if (notifier == null) return false; + if (notifier.host && userMutedInstances.has(notifier.host)) return false; + + if (notifier.isSuspended) return false; + + return true; + } + + /** + * notifierが存在するか、ミュートされていないか、サスペンドされていないかを実際に確認する + */ + async #isValidNotifier( + notification: MiNotification | MiGroupedNotification, + meId: MiUser['id'], + ): Promise { + return (await this.#filterValidNotifier([notification], meId)).length === 1; + } + + /** + * notifierが存在するか、ミュートされていないか、サスペンドされていないかを実際に複数確認する + */ + async #filterValidNotifier ( + notifications: T[], + meId: MiUser['id'], + ): Promise { + const [ + userIdsWhoMeMuting, + userMutedInstances, + ] = await Promise.all([ + this.cacheService.userMutingsCache.fetch(meId), + this.cacheService.userProfileCache.fetch(meId).then(p => new Set(p.mutedInstances)), + ]); + + const notifierIds = notifications.map(notification => 'notifierId' in notification ? notification.notifierId : null).filter(isNotNull); + const notifiers = notifierIds.length > 0 ? await this.usersRepository.find({ + where: { id: In(notifierIds) }, + }) : []; + + const filteredNotifications = ((await Promise.all(notifications.map(async (notification) => { + const isValid = this.#validateNotifier(notification, userIdsWhoMeMuting, userMutedInstances, notifiers); + return isValid ? notification : null; + }))) as [T | null] ).filter(isNotNull); + + return filteredNotifications; } } diff --git a/packages/backend/src/core/entities/PageEntityService.ts b/packages/backend/src/core/entities/PageEntityService.ts index f39ef949db..65c69a49a7 100644 --- a/packages/backend/src/core/entities/PageEntityService.ts +++ b/packages/backend/src/core/entities/PageEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -14,6 +14,7 @@ import type { MiPage } from '@/models/Page.js'; import type { MiDriveFile } from '@/models/DriveFile.js'; import { bindThis } from '@/decorators.js'; import { IdService } from '@/core/IdService.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import { UserEntityService } from './UserEntityService.js'; import { DriveFileEntityService } from './DriveFileEntityService.js'; @@ -90,7 +91,7 @@ export class PageEntityService { createdAt: this.idService.parse(page.id).date.toISOString(), updatedAt: page.updatedAt.toISOString(), userId: page.userId, - user: this.userEntityService.pack(page.user ?? page.userId, me), // { detail: true } すると無限ループするので注意 + user: this.userEntityService.pack(page.user ?? page.userId, me), // { schema: 'UserDetailed' } すると無限ループするので注意 content: page.content, variables: page.variables, title: page.title, @@ -102,9 +103,9 @@ export class PageEntityService { script: page.script, eyeCatchingImageId: page.eyeCatchingImageId, eyeCatchingImage: page.eyeCatchingImageId ? await this.driveFileEntityService.pack(page.eyeCatchingImageId) : null, - attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter((x): x is MiDriveFile => x != null)), + attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter(isNotNull)), likedCount: page.likedCount, - isLiked: meId ? await this.pageLikesRepository.exist({ where: { pageId: page.id, userId: meId } }) : undefined, + isLiked: meId ? await this.pageLikesRepository.exists({ where: { pageId: page.id, userId: meId } }) : undefined, }); } diff --git a/packages/backend/src/core/entities/PageLikeEntityService.ts b/packages/backend/src/core/entities/PageLikeEntityService.ts index 4dc691ab93..cfccbcb660 100644 --- a/packages/backend/src/core/entities/PageLikeEntityService.ts +++ b/packages/backend/src/core/entities/PageLikeEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/RenoteMutingEntityService.ts b/packages/backend/src/core/entities/RenoteMutingEntityService.ts index 3f9dc9180a..0b05a5db80 100644 --- a/packages/backend/src/core/entities/RenoteMutingEntityService.ts +++ b/packages/backend/src/core/entities/RenoteMutingEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -38,7 +38,7 @@ export class RenoteMutingEntityService { createdAt: this.idService.parse(muting.id).date.toISOString(), muteeId: muting.muteeId, mutee: this.userEntityService.pack(muting.muteeId, me, { - detail: true, + schema: 'UserDetailedNotMe', }), }); } diff --git a/packages/backend/src/core/entities/ReversiGameEntityService.ts b/packages/backend/src/core/entities/ReversiGameEntityService.ts index 1a689a7b53..32cbe631e4 100644 --- a/packages/backend/src/core/entities/ReversiGameEntityService.ts +++ b/packages/backend/src/core/entities/ReversiGameEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/RoleEntityService.ts b/packages/backend/src/core/entities/RoleEntityService.ts index 5563f9a1ac..2a7dc37bce 100644 --- a/packages/backend/src/core/entities/RoleEntityService.ts +++ b/packages/backend/src/core/entities/RoleEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/SigninEntityService.ts b/packages/backend/src/core/entities/SigninEntityService.ts index 6bde3e589a..00b124d594 100644 --- a/packages/backend/src/core/entities/SigninEntityService.ts +++ b/packages/backend/src/core/entities/SigninEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index ef815a388a..14761357a5 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -25,19 +25,12 @@ import { IdService } from '@/core/IdService.js'; import type { AnnouncementService } from '@/core/AnnouncementService.js'; import type { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { AvatarDecorationService } from '@/core/AvatarDecorationService.js'; +import { isNotNull } from '@/misc/is-not-null.js'; import type { OnModuleInit } from '@nestjs/common'; import type { NoteEntityService } from './NoteEntityService.js'; import type { DriveFileEntityService } from './DriveFileEntityService.js'; import type { PageEntityService } from './PageEntityService.js'; -type IsUserDetailed = Detailed extends true ? Packed<'UserDetailed'> : Packed<'UserLite'>; -type IsMeAndIsUserDetailed = - Detailed extends true ? - ExpectsMe extends true ? Packed<'MeDetailed'> : - ExpectsMe extends false ? Packed<'UserDetailedNotMe'> : - Packed<'UserDetailed'> : - Packed<'UserLite'>; - const Ajv = _Ajv.default; const ajv = new Ajv(); @@ -160,43 +153,43 @@ export class UserEntityService implements OnModuleInit { followerId: me, followeeId: target, }), - this.followingsRepository.exist({ + this.followingsRepository.exists({ where: { followerId: target, followeeId: me, }, }), - this.followRequestsRepository.exist({ + this.followRequestsRepository.exists({ where: { followerId: me, followeeId: target, }, }), - this.followRequestsRepository.exist({ + this.followRequestsRepository.exists({ where: { followerId: target, followeeId: me, }, }), - this.blockingsRepository.exist({ + this.blockingsRepository.exists({ where: { blockerId: me, blockeeId: target, }, }), - this.blockingsRepository.exist({ + this.blockingsRepository.exists({ where: { blockerId: target, blockeeId: me, }, }), - this.mutingsRepository.exist({ + this.mutingsRepository.exists({ where: { muterId: me, muteeId: target, }, }), - this.renoteMutingsRepository.exist({ + this.renoteMutingsRepository.exists({ where: { muterId: me, muteeId: target, @@ -223,7 +216,7 @@ export class UserEntityService implements OnModuleInit { /* const myAntennas = (await this.antennaService.getAntennas()).filter(a => a.userId === userId); - const isUnread = (myAntennas.length > 0 ? await this.antennaNotesRepository.exist({ + const isUnread = (myAntennas.length > 0 ? await this.antennaNotesRepository.exists({ where: { antennaId: In(myAntennas.map(x => x.id)), read: false, @@ -303,33 +296,34 @@ export class UserEntityService implements OnModuleInit { return `${this.config.url}/users/${userId}`; } - public async pack( + public async pack( src: MiUser['id'] | MiUser, me?: { id: MiUser['id']; } | null | undefined, options?: { - detail?: D, + schema?: S, includeSecrets?: boolean, userProfile?: MiUserProfile, }, - ): Promise> { + ): Promise> { const opts = Object.assign({ - detail: false, + schema: 'UserLite', includeSecrets: false, }, options); const user = typeof src === 'object' ? src : await this.usersRepository.findOneByOrFail({ id: src }); + const isDetailed = opts.schema !== 'UserLite'; const meId = me ? me.id : null; const isMe = meId === user.id; const iAmModerator = me ? await this.roleService.isModerator(me as MiUser) : false; - const relation = meId && !isMe && opts.detail ? await this.getRelation(meId, user.id) : null; - const pins = opts.detail ? await this.userNotePiningsRepository.createQueryBuilder('pin') + const relation = meId && !isMe && isDetailed ? await this.getRelation(meId, user.id) : null; + const pins = isDetailed ? await this.userNotePiningsRepository.createQueryBuilder('pin') .where('pin.userId = :userId', { userId: user.id }) .innerJoinAndSelect('pin.note', 'note') .orderBy('pin.id', 'DESC') .getMany() : []; - const profile = opts.detail ? (opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id })) : null; + const profile = isDetailed ? (opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id })) : null; const followingCount = profile == null ? null : (profile.followingVisibility === 'public') || isMe ? user.followingCount : @@ -341,15 +335,15 @@ export class UserEntityService implements OnModuleInit { (profile.followersVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount : null; - const isModerator = isMe && opts.detail ? this.roleService.isModerator(user) : null; - const isAdmin = isMe && opts.detail ? this.roleService.isAdministrator(user) : null; - const unreadAnnouncements = isMe && opts.detail ? + const isModerator = isMe && isDetailed ? this.roleService.isModerator(user) : null; + const isAdmin = isMe && isDetailed ? this.roleService.isAdministrator(user) : null; + const unreadAnnouncements = isMe && isDetailed ? (await this.announcementService.getUnreadAnnouncements(user)).map((announcement) => ({ createdAt: this.idService.parse(announcement.id).date.toISOString(), ...announcement, })) : null; - const notificationsInfo = isMe && opts.detail ? await this.getNotificationsInfo(user.id) : null; + const notificationsInfo = isMe && isDetailed ? await this.getNotificationsInfo(user.id) : null; const packed = { id: user.id, @@ -385,13 +379,13 @@ export class UserEntityService implements OnModuleInit { displayOrder: r.displayOrder, }))) : undefined, - ...(opts.detail ? { + ...(isDetailed ? { url: profile!.url, uri: user.uri, movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null, alsoKnownAs: user.alsoKnownAs ? Promise.all(user.alsoKnownAs.map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null))) - .then(xs => xs.length === 0 ? null : xs.filter(x => x != null) as string[]) + .then(xs => xs.length === 0 ? null : xs.filter(isNotNull)) : null, createdAt: this.idService.parse(user.id).date.toISOString(), updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, @@ -416,7 +410,7 @@ export class UserEntityService implements OnModuleInit { }), pinnedPageId: profile!.pinnedPageId, pinnedPage: profile!.pinnedPageId ? this.pageEntityService.pack(profile!.pinnedPageId, me) : null, - publicReactions: profile!.publicReactions, + publicReactions: this.isLocalUser(user) ? profile!.publicReactions : false, // https://github.com/misskey-dev/misskey/issues/12964 followersVisibility: profile!.followersVisibility, followingVisibility: profile!.followingVisibility, twoFactorEnabled: profile!.twoFactorEnabled, @@ -443,7 +437,7 @@ export class UserEntityService implements OnModuleInit { moderationNote: iAmModerator ? (profile!.moderationNote ?? '') : undefined, } : {}), - ...(opts.detail && isMe ? { + ...(isDetailed && isMe ? { avatarId: user.avatarId, bannerId: user.bannerId, isModerator: isModerator, @@ -515,19 +509,19 @@ export class UserEntityService implements OnModuleInit { notify: relation.following?.notify ?? 'none', withReplies: relation.following?.withReplies ?? false, } : {}), - } as Promiseable> as Promiseable>; + } as Promiseable>; return await awaitAll(packed); } - public packMany( + public packMany( users: (MiUser['id'] | MiUser)[], me?: { id: MiUser['id'] } | null | undefined, options?: { - detail?: D, + schema?: S, includeSecrets?: boolean, }, - ): Promise[]> { + ): Promise[]> { return Promise.all(users.map(u => this.pack(u, me, options))); } } diff --git a/packages/backend/src/core/entities/UserListEntityService.ts b/packages/backend/src/core/entities/UserListEntityService.ts index 31ab7293da..09cab24521 100644 --- a/packages/backend/src/core/entities/UserListEntityService.ts +++ b/packages/backend/src/core/entities/UserListEntityService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/daemons/DaemonModule.ts b/packages/backend/src/daemons/DaemonModule.ts index 236985076c..a67907e6dd 100644 --- a/packages/backend/src/daemons/DaemonModule.ts +++ b/packages/backend/src/daemons/DaemonModule.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/daemons/QueueStatsService.ts b/packages/backend/src/daemons/QueueStatsService.ts index 5edc0f45ab..ede104b9fe 100644 --- a/packages/backend/src/daemons/QueueStatsService.ts +++ b/packages/backend/src/daemons/QueueStatsService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/daemons/ServerStatsService.ts b/packages/backend/src/daemons/ServerStatsService.ts index 4c55acea5a..2c70344c94 100644 --- a/packages/backend/src/daemons/ServerStatsService.ts +++ b/packages/backend/src/daemons/ServerStatsService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/decorators.ts b/packages/backend/src/decorators.ts index 6b439978db..21777657d1 100644 --- a/packages/backend/src/decorators.ts +++ b/packages/backend/src/decorators.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/di-symbols.ts b/packages/backend/src/di-symbols.ts index 73de01f33a..919f4794a3 100644 --- a/packages/backend/src/di-symbols.ts +++ b/packages/backend/src/di-symbols.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/env.ts b/packages/backend/src/env.ts index af1c3bdd3c..ba44cfa2e6 100644 --- a/packages/backend/src/env.ts +++ b/packages/backend/src/env.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/global.d.ts b/packages/backend/src/global.d.ts index a9e6243cc4..2f19e85525 100644 --- a/packages/backend/src/global.d.ts +++ b/packages/backend/src/global.d.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/logger.ts b/packages/backend/src/logger.ts index 0a19036c97..d4705af601 100644 --- a/packages/backend/src/logger.ts +++ b/packages/backend/src/logger.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/FileWriterStream.ts b/packages/backend/src/misc/FileWriterStream.ts new file mode 100644 index 0000000000..367a8eb560 --- /dev/null +++ b/packages/backend/src/misc/FileWriterStream.ts @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import * as fs from 'node:fs/promises'; +import type { PathLike } from 'node:fs'; + +/** + * `fs.createWriteStream()`相当のことを行う`WritableStream` (Web標準) + */ +export class FileWriterStream extends WritableStream { + constructor(path: PathLike) { + let file: fs.FileHandle | null = null; + + super({ + start: async () => { + file = await fs.open(path, 'a'); + }, + write: async (chunk, controller) => { + if (file === null) { + controller.error(); + throw new Error(); + } + + await file.write(chunk); + }, + close: async () => { + await file?.close(); + }, + abort: async () => { + await file?.close(); + }, + }); + } +} diff --git a/packages/backend/src/misc/JsonArrayStream.ts b/packages/backend/src/misc/JsonArrayStream.ts new file mode 100644 index 0000000000..754938989d --- /dev/null +++ b/packages/backend/src/misc/JsonArrayStream.ts @@ -0,0 +1,35 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { TransformStream } from 'node:stream/web'; + +/** + * ストリームに流れてきた各データについて`JSON.stringify()`した上で、それらを一つの配列にまとめる + */ +export class JsonArrayStream extends TransformStream { + constructor() { + /** 最初の要素かどうかを変数に記録 */ + let isFirst = true; + + super({ + start(controller) { + controller.enqueue('['); + }, + flush(controller) { + controller.enqueue(']'); + }, + transform(chunk, controller) { + if (isFirst) { + isFirst = false; + } else { + // 妥当なJSON配列にするためには最初以外の要素の前に`,`を挿入しなければならない + controller.enqueue(',\n'); + } + + controller.enqueue(JSON.stringify(chunk)); + }, + }); + } +} diff --git a/packages/backend/src/misc/acct.ts b/packages/backend/src/misc/acct.ts index 5db72746c0..3d729b1151 100644 --- a/packages/backend/src/misc/acct.ts +++ b/packages/backend/src/misc/acct.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index c235871931..bba64a06ef 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -186,28 +186,18 @@ export class RedisSingleCache { // TODO: メモリ節約のためあまり参照されないキーを定期的に削除できるようにする? -function nothingToDo(value: T): V { - return value as unknown as V; -} - -export class MemoryKVCache { - public cache: Map; +export class MemoryKVCache { + /** + * データを持つマップ + * @deprecated これを直接操作するべきではない + */ + public cache: Map; private lifetime: number; private gcIntervalHandle: NodeJS.Timeout; - private toMapConverter: (value: T) => V; - private fromMapConverter: (cached: V) => T | undefined; - constructor(lifetime: MemoryKVCache['lifetime'], options: { - toMapConverter: (value: T) => V; - fromMapConverter: (cached: V) => T | undefined; - } = { - toMapConverter: nothingToDo, - fromMapConverter: nothingToDo, - }) { + constructor(lifetime: MemoryKVCache['lifetime']) { this.cache = new Map(); this.lifetime = lifetime; - this.toMapConverter = options.toMapConverter; - this.fromMapConverter = options.fromMapConverter; this.gcIntervalHandle = setInterval(() => { this.gc(); @@ -215,10 +205,14 @@ export class MemoryKVCache { } @bindThis + /** + * Mapにキャッシュをセットします + * @deprecated これを直接呼び出すべきではない。InternalEventなどで変更を全てのプロセス/マシンに通知するべき + */ public set(key: string, value: T): void { this.cache.set(key, { date: Date.now(), - value: this.toMapConverter(value), + value, }); } @@ -230,7 +224,7 @@ export class MemoryKVCache { this.cache.delete(key); return undefined; } - return this.fromMapConverter(cached.value); + return cached.value; } @bindThis @@ -241,10 +235,9 @@ export class MemoryKVCache { /** * キャッシュがあればそれを返し、無ければfetcherを呼び出して結果をキャッシュ&返します * optional: キャッシュが存在してもvalidatorでfalseを返すとキャッシュ無効扱いにします - * fetcherの引数はcacheに保存されている値があれば渡されます */ @bindThis - public async fetch(key: string, fetcher: (value: V | undefined) => Promise, validator?: (cachedValue: T) => boolean): Promise { + public async fetch(key: string, fetcher: () => Promise, validator?: (cachedValue: T) => boolean): Promise { const cachedValue = this.get(key); if (cachedValue !== undefined) { if (validator) { @@ -259,7 +252,7 @@ export class MemoryKVCache { } // Cache MISS - const value = await fetcher(this.cache.get(key)?.value); + const value = await fetcher(); this.set(key, value); return value; } @@ -267,10 +260,9 @@ export class MemoryKVCache { /** * キャッシュがあればそれを返し、無ければfetcherを呼び出して結果をキャッシュ&返します * optional: キャッシュが存在してもvalidatorでfalseを返すとキャッシュ無効扱いにします - * fetcherの引数はcacheに保存されている値があれば渡されます */ @bindThis - public async fetchMaybe(key: string, fetcher: (value: V | undefined) => Promise, validator?: (cachedValue: T) => boolean): Promise { + public async fetchMaybe(key: string, fetcher: () => Promise, validator?: (cachedValue: T) => boolean): Promise { const cachedValue = this.get(key); if (cachedValue !== undefined) { if (validator) { @@ -285,7 +277,7 @@ export class MemoryKVCache { } // Cache MISS - const value = await fetcher(this.cache.get(key)?.value); + const value = await fetcher(); if (value !== undefined) { this.set(key, value); } diff --git a/packages/backend/src/misc/check-https.ts b/packages/backend/src/misc/check-https.ts index 0b13ccabdd..15a54f6ce7 100644 --- a/packages/backend/src/misc/check-https.ts +++ b/packages/backend/src/misc/check-https.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/check-word-mute.ts b/packages/backend/src/misc/check-word-mute.ts index cef5595451..c50f2b723c 100644 --- a/packages/backend/src/misc/check-word-mute.ts +++ b/packages/backend/src/misc/check-word-mute.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/clone.ts b/packages/backend/src/misc/clone.ts index 9d20deac3b..ed05485649 100644 --- a/packages/backend/src/misc/clone.ts +++ b/packages/backend/src/misc/clone.ts @@ -1,12 +1,12 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ // structredCloneが遅いため // SEE: http://var.blog.jp/archives/86038606.html -type Cloneable = string | number | boolean | null | { [key: string]: Cloneable } | Cloneable[]; +type Cloneable = string | number | boolean | null | undefined | { [key: string]: Cloneable } | Cloneable[]; export function deepClone(x: T): T { if (typeof x === 'object') { @@ -14,7 +14,7 @@ export function deepClone(x: T): T { if (Array.isArray(x)) return x.map(deepClone) as T; const obj = {} as Record; for (const [k, v] of Object.entries(x)) { - obj[k] = deepClone(v); + obj[k] = v === undefined ? undefined : deepClone(v); } return obj as T; } else { diff --git a/packages/backend/src/misc/content-disposition.ts b/packages/backend/src/misc/content-disposition.ts index 1ac8c88d21..467b5057d6 100644 --- a/packages/backend/src/misc/content-disposition.ts +++ b/packages/backend/src/misc/content-disposition.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/correct-filename.ts b/packages/backend/src/misc/correct-filename.ts index 9130af44c3..f7ee02781d 100644 --- a/packages/backend/src/misc/correct-filename.ts +++ b/packages/backend/src/misc/correct-filename.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -21,7 +21,7 @@ const extRegExp = /\.[0-9a-zA-Z]+$/i; /** * 与えられた拡張子とファイル名が一致しているかどうかを確認し、 * 一致していない場合は拡張子を付与して返す - * + * * extはfile-typeのextを想定 */ export function correctFilename(filename: string, ext: string | null) { diff --git a/packages/backend/src/misc/create-temp.ts b/packages/backend/src/misc/create-temp.ts index 2bb0e88489..9aaecf8263 100644 --- a/packages/backend/src/misc/create-temp.ts +++ b/packages/backend/src/misc/create-temp.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/dev-null.ts b/packages/backend/src/misc/dev-null.ts index f510177c0b..4d9806fbe8 100644 --- a/packages/backend/src/misc/dev-null.ts +++ b/packages/backend/src/misc/dev-null.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/emoji-regex.ts b/packages/backend/src/misc/emoji-regex.ts index 37ecde6eb1..6d03b433ba 100644 --- a/packages/backend/src/misc/emoji-regex.ts +++ b/packages/backend/src/misc/emoji-regex.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts b/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts index 0b898d47e8..73ae9abb54 100644 --- a/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts +++ b/packages/backend/src/misc/extract-custom-emojis-from-mfm.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/extract-hashtags.ts b/packages/backend/src/misc/extract-hashtags.ts index 3bd56e98eb..d3d245d414 100644 --- a/packages/backend/src/misc/extract-hashtags.ts +++ b/packages/backend/src/misc/extract-hashtags.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/extract-mentions.ts b/packages/backend/src/misc/extract-mentions.ts index 272eb92192..2ec9349718 100644 --- a/packages/backend/src/misc/extract-mentions.ts +++ b/packages/backend/src/misc/extract-mentions.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/fastify-hook-handlers.ts b/packages/backend/src/misc/fastify-hook-handlers.ts new file mode 100644 index 0000000000..49a48f6a6b --- /dev/null +++ b/packages/backend/src/misc/fastify-hook-handlers.ts @@ -0,0 +1,9 @@ +import type { onRequestHookHandler } from 'fastify'; + +export const handleRequestRedirectToOmitSearch: onRequestHookHandler = (request, reply, done) => { + const index = request.url.indexOf('?'); + if (~index) { + reply.redirect(301, request.url.slice(0, index)); + } + done(); +}; diff --git a/packages/backend/src/misc/fastify-reply-error.ts b/packages/backend/src/misc/fastify-reply-error.ts index 7c889bab7a..e6c4e78d2f 100644 --- a/packages/backend/src/misc/fastify-reply-error.ts +++ b/packages/backend/src/misc/fastify-reply-error.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/gen-identicon.ts b/packages/backend/src/misc/gen-identicon.ts index c36b00af63..62a8ab8ace 100644 --- a/packages/backend/src/misc/gen-identicon.ts +++ b/packages/backend/src/misc/gen-identicon.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/gen-key-pair.ts b/packages/backend/src/misc/gen-key-pair.ts index c0815613e7..02a303dc0a 100644 --- a/packages/backend/src/misc/gen-key-pair.ts +++ b/packages/backend/src/misc/gen-key-pair.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/generate-invite-code.ts b/packages/backend/src/misc/generate-invite-code.ts index 7c88561179..006920cf0e 100644 --- a/packages/backend/src/misc/generate-invite-code.ts +++ b/packages/backend/src/misc/generate-invite-code.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/generate-native-user-token.ts b/packages/backend/src/misc/generate-native-user-token.ts index 094c625120..85fb383ba2 100644 --- a/packages/backend/src/misc/generate-native-user-token.ts +++ b/packages/backend/src/misc/generate-native-user-token.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/get-ip-hash.ts b/packages/backend/src/misc/get-ip-hash.ts index 3a01e4f578..e132fa8f31 100644 --- a/packages/backend/src/misc/get-ip-hash.ts +++ b/packages/backend/src/misc/get-ip-hash.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/get-note-summary.ts b/packages/backend/src/misc/get-note-summary.ts index 1bda5cdcf7..1a07139a50 100644 --- a/packages/backend/src/misc/get-note-summary.ts +++ b/packages/backend/src/misc/get-note-summary.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/get-reaction-emoji.ts b/packages/backend/src/misc/get-reaction-emoji.ts index 80ef7ff7bc..3f975853ed 100644 --- a/packages/backend/src/misc/get-reaction-emoji.ts +++ b/packages/backend/src/misc/get-reaction-emoji.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/i18n.ts b/packages/backend/src/misc/i18n.ts index 4c9d1a08e3..6cbbdef74c 100644 --- a/packages/backend/src/misc/i18n.ts +++ b/packages/backend/src/misc/i18n.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/id/aid.ts b/packages/backend/src/misc/id/aid.ts index de03f6793f..60ba788e44 100644 --- a/packages/backend/src/misc/id/aid.ts +++ b/packages/backend/src/misc/id/aid.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/id/aidx.ts b/packages/backend/src/misc/id/aidx.ts index 9f457f6f0a..1b087e70af 100644 --- a/packages/backend/src/misc/id/aidx.ts +++ b/packages/backend/src/misc/id/aidx.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/id/meid.ts b/packages/backend/src/misc/id/meid.ts index 7646282edb..dfab48a369 100644 --- a/packages/backend/src/misc/id/meid.ts +++ b/packages/backend/src/misc/id/meid.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/id/meidg.ts b/packages/backend/src/misc/id/meidg.ts index f2a55443ef..b9c0cc3dda 100644 --- a/packages/backend/src/misc/id/meidg.ts +++ b/packages/backend/src/misc/id/meidg.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/id/object-id.ts b/packages/backend/src/misc/id/object-id.ts index f5c3619fdb..243f92bbac 100644 --- a/packages/backend/src/misc/id/object-id.ts +++ b/packages/backend/src/misc/id/object-id.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/id/ulid.ts b/packages/backend/src/misc/id/ulid.ts index 00dd67dafe..fc3654d6d2 100644 --- a/packages/backend/src/misc/id/ulid.ts +++ b/packages/backend/src/misc/id/ulid.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/identifiable-error.ts b/packages/backend/src/misc/identifiable-error.ts index 71a4773fac..13c41f1e3b 100644 --- a/packages/backend/src/misc/identifiable-error.ts +++ b/packages/backend/src/misc/identifiable-error.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/is-duplicate-key-value-error.ts b/packages/backend/src/misc/is-duplicate-key-value-error.ts index 91e0a6b93d..8da0280f60 100644 --- a/packages/backend/src/misc/is-duplicate-key-value-error.ts +++ b/packages/backend/src/misc/is-duplicate-key-value-error.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/is-instance-muted.ts b/packages/backend/src/misc/is-instance-muted.ts index 35fe11849d..096a8b39c7 100644 --- a/packages/backend/src/misc/is-instance-muted.ts +++ b/packages/backend/src/misc/is-instance-muted.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/is-mime-image.ts b/packages/backend/src/misc/is-mime-image.ts index 1a5a8cf0f4..8ffbc99230 100644 --- a/packages/backend/src/misc/is-mime-image.ts +++ b/packages/backend/src/misc/is-mime-image.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/is-native-token.ts b/packages/backend/src/misc/is-native-token.ts index 618e60b7d8..300c4c05b3 100644 --- a/packages/backend/src/misc/is-native-token.ts +++ b/packages/backend/src/misc/is-native-token.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/is-not-null.ts b/packages/backend/src/misc/is-not-null.ts index 153a9e51ef..8d9dc8bb39 100644 --- a/packages/backend/src/misc/is-not-null.ts +++ b/packages/backend/src/misc/is-not-null.ts @@ -1,10 +1,8 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -// we are using {} as "any non-nullish value" as expected -// eslint-disable-next-line @typescript-eslint/ban-types -export function isNotNull(input: T | undefined | null): input is T { +export function isNotNull>(input: T | undefined | null): input is T { return input != null; } diff --git a/packages/backend/src/misc/is-quote.ts b/packages/backend/src/misc/is-quote.ts index db72d1d57a..75b29f63f4 100644 --- a/packages/backend/src/misc/is-quote.ts +++ b/packages/backend/src/misc/is-quote.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/is-reply.ts b/packages/backend/src/misc/is-reply.ts index 964c2aa153..980eae11c9 100644 --- a/packages/backend/src/misc/is-reply.ts +++ b/packages/backend/src/misc/is-reply.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/is-user-related.ts b/packages/backend/src/misc/is-user-related.ts index 6efb1194d3..93c9b2b814 100644 --- a/packages/backend/src/misc/is-user-related.ts +++ b/packages/backend/src/misc/is-user-related.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index b4f0541712..46b0bb2fab 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -25,7 +25,7 @@ import { packedBlockingSchema } from '@/models/json-schema/blocking.js'; import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js'; import { packedHashtagSchema } from '@/models/json-schema/hashtag.js'; import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js'; -import { packedPageSchema } from '@/models/json-schema/page.js'; +import { packedPageSchema, packedPageBlockSchema } from '@/models/json-schema/page.js'; import { packedNoteFavoriteSchema } from '@/models/json-schema/note-favorite.js'; import { packedChannelSchema } from '@/models/json-schema/channel.js'; import { packedAntennaSchema } from '@/models/json-schema/antenna.js'; @@ -37,9 +37,25 @@ import { packedEmojiDetailedSchema, packedEmojiSimpleSchema } from '@/models/jso import { packedFlashSchema } from '@/models/json-schema/flash.js'; import { packedAnnouncementSchema } from '@/models/json-schema/announcement.js'; import { packedSigninSchema } from '@/models/json-schema/signin.js'; -import { packedRoleLiteSchema, packedRoleSchema } from '@/models/json-schema/role.js'; +import { + packedRoleLiteSchema, + packedRoleSchema, + packedRolePoliciesSchema, + packedRoleCondFormulaLogicsSchema, + packedRoleCondFormulaValueNot, + packedRoleCondFormulaValueIsLocalOrRemoteSchema, + packedRoleCondFormulaValueAssignedRoleSchema, + packedRoleCondFormulaValueCreatedSchema, + packedRoleCondFormulaFollowersOrFollowingOrNotesSchema, + packedRoleCondFormulaValueSchema, +} from '@/models/json-schema/role.js'; import { packedAdSchema } from '@/models/json-schema/ad.js'; import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js'; +import { + packedMetaLiteSchema, + packedMetaDetailedOnlySchema, + packedMetaDetailedSchema, +} from '@/models/json-schema/meta.js'; export const refs = { UserLite: packedUserLiteSchema, @@ -67,6 +83,7 @@ export const refs = { Hashtag: packedHashtagSchema, InviteCode: packedInviteCodeSchema, Page: packedPageSchema, + PageBlock: packedPageBlockSchema, Channel: packedChannelSchema, QueueCount: packedQueueCountSchema, Antenna: packedAntennaSchema, @@ -77,14 +94,28 @@ export const refs = { EmojiDetailed: packedEmojiDetailedSchema, Flash: packedFlashSchema, Signin: packedSigninSchema, + RoleCondFormulaLogics: packedRoleCondFormulaLogicsSchema, + RoleCondFormulaValueNot: packedRoleCondFormulaValueNot, + RoleCondFormulaValueIsLocalOrRemote: packedRoleCondFormulaValueIsLocalOrRemoteSchema, + RoleCondFormulaValueAssignedRole: packedRoleCondFormulaValueAssignedRoleSchema, + RoleCondFormulaValueCreated: packedRoleCondFormulaValueCreatedSchema, + RoleCondFormulaFollowersOrFollowingOrNotes: packedRoleCondFormulaFollowersOrFollowingOrNotesSchema, + RoleCondFormulaValue: packedRoleCondFormulaValueSchema, RoleLite: packedRoleLiteSchema, Role: packedRoleSchema, + RolePolicies: packedRolePoliciesSchema, ReversiGameLite: packedReversiGameLiteSchema, ReversiGameDetailed: packedReversiGameDetailedSchema, + MetaLite: packedMetaLiteSchema, + MetaDetailedOnly: packedMetaDetailedOnlySchema, + MetaDetailed: packedMetaDetailedSchema, }; export type Packed = SchemaType; +export type KeyOf = PropertiesToUnion; +type PropertiesToUnion

= p['properties'] extends NonNullable ? keyof p['properties'] : never; + type TypeStringef = 'null' | 'boolean' | 'integer' | 'number' | 'string' | 'array' | 'object' | 'any'; type StringDefToType = T extends 'null' ? null : @@ -114,6 +145,7 @@ export interface Schema extends OfSchema { readonly example?: any; readonly format?: string; readonly ref?: keyof typeof refs; + readonly selfRef?: boolean; readonly enum?: ReadonlyArray; readonly default?: (this['type'] extends TypeStringef ? StringDefToType : any) | null; readonly maxLength?: number; diff --git a/packages/backend/src/misc/langmap.ts b/packages/backend/src/misc/langmap.ts index 9e287677df..5ff9338651 100644 --- a/packages/backend/src/misc/langmap.ts +++ b/packages/backend/src/misc/langmap.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/normalize-for-search.ts b/packages/backend/src/misc/normalize-for-search.ts index 9d96f4169d..3f19617e14 100644 --- a/packages/backend/src/misc/normalize-for-search.ts +++ b/packages/backend/src/misc/normalize-for-search.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/prelude/array.ts b/packages/backend/src/misc/prelude/array.ts index b2f29bcecf..dbfe1fff18 100644 --- a/packages/backend/src/misc/prelude/array.ts +++ b/packages/backend/src/misc/prelude/array.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/prelude/await-all.ts b/packages/backend/src/misc/prelude/await-all.ts index 6b8a91f8a5..48249fe1ae 100644 --- a/packages/backend/src/misc/prelude/await-all.ts +++ b/packages/backend/src/misc/prelude/await-all.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/prelude/math.ts b/packages/backend/src/misc/prelude/math.ts index 87b5017d09..38556def2d 100644 --- a/packages/backend/src/misc/prelude/math.ts +++ b/packages/backend/src/misc/prelude/math.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/prelude/maybe.ts b/packages/backend/src/misc/prelude/maybe.ts index 17c100b80d..1c58ccb9c7 100644 --- a/packages/backend/src/misc/prelude/maybe.ts +++ b/packages/backend/src/misc/prelude/maybe.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/prelude/relation.ts b/packages/backend/src/misc/prelude/relation.ts index 3456c1a0bc..7dcd4c700a 100644 --- a/packages/backend/src/misc/prelude/relation.ts +++ b/packages/backend/src/misc/prelude/relation.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/prelude/string.ts b/packages/backend/src/misc/prelude/string.ts index a727ab7f1d..67ea529961 100644 --- a/packages/backend/src/misc/prelude/string.ts +++ b/packages/backend/src/misc/prelude/string.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/prelude/symbol.ts b/packages/backend/src/misc/prelude/symbol.ts index 91c058a845..7e8d39bdb6 100644 --- a/packages/backend/src/misc/prelude/symbol.ts +++ b/packages/backend/src/misc/prelude/symbol.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/prelude/time.ts b/packages/backend/src/misc/prelude/time.ts index 4479db1081..275b67ed00 100644 --- a/packages/backend/src/misc/prelude/time.ts +++ b/packages/backend/src/misc/prelude/time.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/prelude/url.ts b/packages/backend/src/misc/prelude/url.ts index 633eb98218..270a075075 100644 --- a/packages/backend/src/misc/prelude/url.ts +++ b/packages/backend/src/misc/prelude/url.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/prelude/xml.ts b/packages/backend/src/misc/prelude/xml.ts index bca116a7ec..61c166cee5 100644 --- a/packages/backend/src/misc/prelude/xml.ts +++ b/packages/backend/src/misc/prelude/xml.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/promise-tracker.ts b/packages/backend/src/misc/promise-tracker.ts index c7166c6de9..8a52ca703e 100644 --- a/packages/backend/src/misc/promise-tracker.ts +++ b/packages/backend/src/misc/promise-tracker.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/reset-db.ts b/packages/backend/src/misc/reset-db.ts index a571460a59..75fb4c3e7b 100644 --- a/packages/backend/src/misc/reset-db.ts +++ b/packages/backend/src/misc/reset-db.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/safe-for-sql.ts b/packages/backend/src/misc/safe-for-sql.ts index d7bdd0a81c..ac4b8e2e2e 100644 --- a/packages/backend/src/misc/safe-for-sql.ts +++ b/packages/backend/src/misc/safe-for-sql.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/secure-rndstr.ts b/packages/backend/src/misc/secure-rndstr.ts index 01368d808a..7853100d89 100644 --- a/packages/backend/src/misc/secure-rndstr.ts +++ b/packages/backend/src/misc/secure-rndstr.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/show-machine-info.ts b/packages/backend/src/misc/show-machine-info.ts index ed0fa651f1..8ddec35f23 100644 --- a/packages/backend/src/misc/show-machine-info.ts +++ b/packages/backend/src/misc/show-machine-info.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/sql-like-escape.ts b/packages/backend/src/misc/sql-like-escape.ts index 85cc7405e1..0c05255674 100644 --- a/packages/backend/src/misc/sql-like-escape.ts +++ b/packages/backend/src/misc/sql-like-escape.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/status-error.ts b/packages/backend/src/misc/status-error.ts index be213088a8..c3533db607 100644 --- a/packages/backend/src/misc/status-error.ts +++ b/packages/backend/src/misc/status-error.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/misc/truncate.ts b/packages/backend/src/misc/truncate.ts index b65202fbd4..1c8a274609 100644 --- a/packages/backend/src/misc/truncate.ts +++ b/packages/backend/src/misc/truncate.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/AbuseUserReport.ts b/packages/backend/src/models/AbuseUserReport.ts index 593c44f66b..0615fd7eb5 100644 --- a/packages/backend/src/models/AbuseUserReport.ts +++ b/packages/backend/src/models/AbuseUserReport.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/AccessToken.ts b/packages/backend/src/models/AccessToken.ts index 452711eb8c..6f98c14ec1 100644 --- a/packages/backend/src/models/AccessToken.ts +++ b/packages/backend/src/models/AccessToken.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Ad.ts b/packages/backend/src/models/Ad.ts index b1d7d7d79e..108e991c70 100644 --- a/packages/backend/src/models/Ad.ts +++ b/packages/backend/src/models/Ad.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Announcement.ts b/packages/backend/src/models/Announcement.ts index 8f8be88fed..d0c59fff50 100644 --- a/packages/backend/src/models/Announcement.ts +++ b/packages/backend/src/models/Announcement.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -38,7 +38,7 @@ export class MiAnnouncement { length: 256, nullable: false, default: 'info', }) - public icon: string; + public icon: 'info' | 'warning' | 'error' | 'success'; // normal ... お知らせページ掲載 // banner ... お知らせページ掲載 + バナー表示 @@ -47,7 +47,7 @@ export class MiAnnouncement { length: 256, nullable: false, default: 'normal', }) - public display: string; + public display: 'normal' | 'banner' | 'dialog'; @Column('boolean', { default: false, diff --git a/packages/backend/src/models/AnnouncementRead.ts b/packages/backend/src/models/AnnouncementRead.ts index db09e65f50..47de8dd180 100644 --- a/packages/backend/src/models/AnnouncementRead.ts +++ b/packages/backend/src/models/AnnouncementRead.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Antenna.ts b/packages/backend/src/models/Antenna.ts index b74c61b728..332a899768 100644 --- a/packages/backend/src/models/Antenna.ts +++ b/packages/backend/src/models/Antenna.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/App.ts b/packages/backend/src/models/App.ts index 5c56a224a2..0185e2995c 100644 --- a/packages/backend/src/models/App.ts +++ b/packages/backend/src/models/App.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/AuthSession.ts b/packages/backend/src/models/AuthSession.ts index 81bed21211..03050ba955 100644 --- a/packages/backend/src/models/AuthSession.ts +++ b/packages/backend/src/models/AuthSession.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/AvatarDecoration.ts b/packages/backend/src/models/AvatarDecoration.ts index 08ebbdeac1..13f0b05667 100644 --- a/packages/backend/src/models/AvatarDecoration.ts +++ b/packages/backend/src/models/AvatarDecoration.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Blocking.ts b/packages/backend/src/models/Blocking.ts index 9bf7a63b6e..34a6efe5a6 100644 --- a/packages/backend/src/models/Blocking.ts +++ b/packages/backend/src/models/Blocking.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/BubbleGameRecord.ts b/packages/backend/src/models/BubbleGameRecord.ts index 4b483ed4d3..686e39c118 100644 --- a/packages/backend/src/models/BubbleGameRecord.ts +++ b/packages/backend/src/models/BubbleGameRecord.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -48,7 +48,7 @@ export class MiBubbleGameRecord { @Column('jsonb', { default: [], }) - public logs: any[]; + public logs: number[][]; @Column('boolean', { default: false, diff --git a/packages/backend/src/models/Channel.ts b/packages/backend/src/models/Channel.ts index a7f9e262b1..f5e9b17e3e 100644 --- a/packages/backend/src/models/Channel.ts +++ b/packages/backend/src/models/Channel.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/ChannelFavorite.ts b/packages/backend/src/models/ChannelFavorite.ts index fc25ffe260..167f41cf16 100644 --- a/packages/backend/src/models/ChannelFavorite.ts +++ b/packages/backend/src/models/ChannelFavorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/ChannelFollowing.ts b/packages/backend/src/models/ChannelFollowing.ts index 4dd391a082..c7afdd05b0 100644 --- a/packages/backend/src/models/ChannelFollowing.ts +++ b/packages/backend/src/models/ChannelFollowing.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Clip.ts b/packages/backend/src/models/Clip.ts index 2483b0925a..6295a329fb 100644 --- a/packages/backend/src/models/Clip.ts +++ b/packages/backend/src/models/Clip.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/ClipFavorite.ts b/packages/backend/src/models/ClipFavorite.ts index aa949b3ea8..40bdb9f4aa 100644 --- a/packages/backend/src/models/ClipFavorite.ts +++ b/packages/backend/src/models/ClipFavorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/ClipNote.ts b/packages/backend/src/models/ClipNote.ts index b7cc5ee39b..6e1d2bec4c 100644 --- a/packages/backend/src/models/ClipNote.ts +++ b/packages/backend/src/models/ClipNote.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/DriveFile.ts b/packages/backend/src/models/DriveFile.ts index 24e6be9c90..438b32f79a 100644 --- a/packages/backend/src/models/DriveFile.ts +++ b/packages/backend/src/models/DriveFile.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/DriveFolder.ts b/packages/backend/src/models/DriveFolder.ts index 18f6d17709..07046d6e11 100644 --- a/packages/backend/src/models/DriveFolder.ts +++ b/packages/backend/src/models/DriveFolder.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Emoji.ts b/packages/backend/src/models/Emoji.ts index 563ac1d9d3..d62b6e9f6f 100644 --- a/packages/backend/src/models/Emoji.ts +++ b/packages/backend/src/models/Emoji.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Flash.ts b/packages/backend/src/models/Flash.ts index ac880843b0..a1469a0d94 100644 --- a/packages/backend/src/models/Flash.ts +++ b/packages/backend/src/models/Flash.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/FlashLike.ts b/packages/backend/src/models/FlashLike.ts index ad7f4966b4..a9fb48123e 100644 --- a/packages/backend/src/models/FlashLike.ts +++ b/packages/backend/src/models/FlashLike.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/FollowRequest.ts b/packages/backend/src/models/FollowRequest.ts index 9899694dd6..3ff5e7a478 100644 --- a/packages/backend/src/models/FollowRequest.ts +++ b/packages/backend/src/models/FollowRequest.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Following.ts b/packages/backend/src/models/Following.ts index e320911a1d..62cbc29f26 100644 --- a/packages/backend/src/models/Following.ts +++ b/packages/backend/src/models/Following.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/GalleryLike.ts b/packages/backend/src/models/GalleryLike.ts index 84d4ce9c3e..ed0963122d 100644 --- a/packages/backend/src/models/GalleryLike.ts +++ b/packages/backend/src/models/GalleryLike.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/GalleryPost.ts b/packages/backend/src/models/GalleryPost.ts index b72220caf9..04d8823e37 100644 --- a/packages/backend/src/models/GalleryPost.ts +++ b/packages/backend/src/models/GalleryPost.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Hashtag.ts b/packages/backend/src/models/Hashtag.ts index 1493774752..3add06d0c3 100644 --- a/packages/backend/src/models/Hashtag.ts +++ b/packages/backend/src/models/Hashtag.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Instance.ts b/packages/backend/src/models/Instance.ts index b225d918d6..9863c9d75d 100644 --- a/packages/backend/src/models/Instance.ts +++ b/packages/backend/src/models/Instance.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -144,4 +144,9 @@ export class MiInstance { nullable: true, }) public infoUpdatedAt: Date | null; + + @Column('varchar', { + length: 16384, default: '', + }) + public moderationNote: string; } diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index 3265e85dd7..66f19ce197 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -76,6 +76,11 @@ export class MiMeta { }) public sensitiveWords: string[]; + @Column('varchar', { + length: 1024, array: true, default: '{}', + }) + public prohibitedWords: string[]; + @Column('varchar', { length: 1024, array: true, default: '{}', }) @@ -248,6 +253,8 @@ export class MiMeta { }) public turnstileSecretKey: string | null; + // chaptcha系を追加した際にはnodeinfoのレスポンスに追加するのを忘れないようにすること + @Column('enum', { enum: ['none', 'all', 'local', 'remote'], default: 'none', @@ -352,9 +359,9 @@ export class MiMeta { @Column('varchar', { length: 1024, default: 'https://github.com/misskey-dev/misskey', - nullable: false, + nullable: true, }) - public repositoryUrl: string; + public repositoryUrl: string | null; @Column('varchar', { length: 1024, diff --git a/packages/backend/src/models/ModerationLog.ts b/packages/backend/src/models/ModerationLog.ts index 71b33c3e47..edde315fdf 100644 --- a/packages/backend/src/models/ModerationLog.ts +++ b/packages/backend/src/models/ModerationLog.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Muting.ts b/packages/backend/src/models/Muting.ts index a528e1e7d7..e1240b9c4e 100644 --- a/packages/backend/src/models/Muting.ts +++ b/packages/backend/src/models/Muting.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Note.ts b/packages/backend/src/models/Note.ts index dee2560b7c..9a95c6faab 100644 --- a/packages/backend/src/models/Note.ts +++ b/packages/backend/src/models/Note.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/NoteFavorite.ts b/packages/backend/src/models/NoteFavorite.ts index 364eaabd98..cf76c767b0 100644 --- a/packages/backend/src/models/NoteFavorite.ts +++ b/packages/backend/src/models/NoteFavorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/NoteReaction.ts b/packages/backend/src/models/NoteReaction.ts index ee3a447464..42dfcaa9ad 100644 --- a/packages/backend/src/models/NoteReaction.ts +++ b/packages/backend/src/models/NoteReaction.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/NoteThreadMuting.ts b/packages/backend/src/models/NoteThreadMuting.ts index 00311aa570..e7bd39f348 100644 --- a/packages/backend/src/models/NoteThreadMuting.ts +++ b/packages/backend/src/models/NoteThreadMuting.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/NoteUnread.ts b/packages/backend/src/models/NoteUnread.ts index d86a474553..c759181117 100644 --- a/packages/backend/src/models/NoteUnread.ts +++ b/packages/backend/src/models/NoteUnread.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts index 3bc2edaa0d..df88b99636 100644 --- a/packages/backend/src/models/Notification.ts +++ b/packages/backend/src/models/Notification.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Page.ts b/packages/backend/src/models/Page.ts index 9cab875499..1695bf570e 100644 --- a/packages/backend/src/models/Page.ts +++ b/packages/backend/src/models/Page.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/PageLike.ts b/packages/backend/src/models/PageLike.ts index b845f58b7d..05ca22cf2c 100644 --- a/packages/backend/src/models/PageLike.ts +++ b/packages/backend/src/models/PageLike.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/PasswordResetRequest.ts b/packages/backend/src/models/PasswordResetRequest.ts index 5be439511f..fdaf21056b 100644 --- a/packages/backend/src/models/PasswordResetRequest.ts +++ b/packages/backend/src/models/PasswordResetRequest.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Poll.ts b/packages/backend/src/models/Poll.ts index 5ce0b9a2fc..c2693dbb19 100644 --- a/packages/backend/src/models/Poll.ts +++ b/packages/backend/src/models/Poll.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/PollVote.ts b/packages/backend/src/models/PollVote.ts index 751be8a32b..b5c780293c 100644 --- a/packages/backend/src/models/PollVote.ts +++ b/packages/backend/src/models/PollVote.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/PromoNote.ts b/packages/backend/src/models/PromoNote.ts index f4425fe88b..ae27adec9e 100644 --- a/packages/backend/src/models/PromoNote.ts +++ b/packages/backend/src/models/PromoNote.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/PromoRead.ts b/packages/backend/src/models/PromoRead.ts index d9f3075416..b2a698cc7b 100644 --- a/packages/backend/src/models/PromoRead.ts +++ b/packages/backend/src/models/PromoRead.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/RegistrationTicket.ts b/packages/backend/src/models/RegistrationTicket.ts index 730cedffba..0a4e4b9189 100644 --- a/packages/backend/src/models/RegistrationTicket.ts +++ b/packages/backend/src/models/RegistrationTicket.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/RegistryItem.ts b/packages/backend/src/models/RegistryItem.ts index 60bdced957..335e8b9eab 100644 --- a/packages/backend/src/models/RegistryItem.ts +++ b/packages/backend/src/models/RegistryItem.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Relay.ts b/packages/backend/src/models/Relay.ts index 293fccecfc..eca2916032 100644 --- a/packages/backend/src/models/Relay.ts +++ b/packages/backend/src/models/Relay.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/RenoteMuting.ts b/packages/backend/src/models/RenoteMuting.ts index 17df43ea31..448a0b7663 100644 --- a/packages/backend/src/models/RenoteMuting.ts +++ b/packages/backend/src/models/RenoteMuting.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts index 2b2aaeb91c..bd447570dd 100644 --- a/packages/backend/src/models/RepositoryModule.ts +++ b/packages/backend/src/models/RepositoryModule.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/RetentionAggregation.ts b/packages/backend/src/models/RetentionAggregation.ts index 9da401597c..139f3e4dfd 100644 --- a/packages/backend/src/models/RetentionAggregation.ts +++ b/packages/backend/src/models/RetentionAggregation.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Role.ts b/packages/backend/src/models/Role.ts index 6976956e13..058abe3118 100644 --- a/packages/backend/src/models/Role.ts +++ b/packages/backend/src/models/Role.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -29,6 +29,11 @@ type CondFormulaValueIsRemote = { type: 'isRemote'; }; +type CondFormulaValueRoleAssignedTo = { + type: 'roleAssignedTo'; + roleId: string; +}; + type CondFormulaValueCreatedLessThan = { type: 'createdLessThan'; sec: number; @@ -69,12 +74,13 @@ type CondFormulaValueNotesMoreThanOrEq = { value: number; }; -export type RoleCondFormulaValue = +export type RoleCondFormulaValue = { id: string } & ( CondFormulaValueAnd | CondFormulaValueOr | CondFormulaValueNot | CondFormulaValueIsLocal | CondFormulaValueIsRemote | + CondFormulaValueRoleAssignedTo | CondFormulaValueCreatedLessThan | CondFormulaValueCreatedMoreThan | CondFormulaValueFollowersLessThanOrEq | @@ -82,7 +88,8 @@ export type RoleCondFormulaValue = CondFormulaValueFollowingLessThanOrEq | CondFormulaValueFollowingMoreThanOrEq | CondFormulaValueNotesLessThanOrEq | - CondFormulaValueNotesMoreThanOrEq; + CondFormulaValueNotesMoreThanOrEq +); @Entity('role') export class MiRole { diff --git a/packages/backend/src/models/RoleAssignment.ts b/packages/backend/src/models/RoleAssignment.ts index 30c7e19f2a..37755d631b 100644 --- a/packages/backend/src/models/RoleAssignment.ts +++ b/packages/backend/src/models/RoleAssignment.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Signin.ts b/packages/backend/src/models/Signin.ts index 656b44dfe0..f8ff9c57d7 100644 --- a/packages/backend/src/models/Signin.ts +++ b/packages/backend/src/models/Signin.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/SwSubscription.ts b/packages/backend/src/models/SwSubscription.ts index f685a8ff3e..0c531132b3 100644 --- a/packages/backend/src/models/SwSubscription.ts +++ b/packages/backend/src/models/SwSubscription.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UsedUsername.ts b/packages/backend/src/models/UsedUsername.ts index c75bf424c1..fbfc126763 100644 --- a/packages/backend/src/models/UsedUsername.ts +++ b/packages/backend/src/models/UsedUsername.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 219497a125..9e2d7a3444 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UserIp.ts b/packages/backend/src/models/UserIp.ts index 60a7bc8b01..3e757fcf79 100644 --- a/packages/backend/src/models/UserIp.ts +++ b/packages/backend/src/models/UserIp.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UserKeypair.ts b/packages/backend/src/models/UserKeypair.ts index a316dbaeb4..f5252d126c 100644 --- a/packages/backend/src/models/UserKeypair.ts +++ b/packages/backend/src/models/UserKeypair.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UserList.ts b/packages/backend/src/models/UserList.ts index 7ad15419d7..5fb991a87d 100644 --- a/packages/backend/src/models/UserList.ts +++ b/packages/backend/src/models/UserList.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UserListFavorite.ts b/packages/backend/src/models/UserListFavorite.ts index a18ed9253a..80b2d61eb7 100644 --- a/packages/backend/src/models/UserListFavorite.ts +++ b/packages/backend/src/models/UserListFavorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UserListMembership.ts b/packages/backend/src/models/UserListMembership.ts index fa8287f17a..af659d071d 100644 --- a/packages/backend/src/models/UserListMembership.ts +++ b/packages/backend/src/models/UserListMembership.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UserMemo.ts b/packages/backend/src/models/UserMemo.ts index ab5e812c44..29e28d290a 100644 --- a/packages/backend/src/models/UserMemo.ts +++ b/packages/backend/src/models/UserMemo.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UserNotePining.ts b/packages/backend/src/models/UserNotePining.ts index ae5977aa56..92c5cd55d0 100644 --- a/packages/backend/src/models/UserNotePining.ts +++ b/packages/backend/src/models/UserNotePining.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UserPending.ts b/packages/backend/src/models/UserPending.ts index 8b1f8f617f..99f8a22a84 100644 --- a/packages/backend/src/models/UserPending.ts +++ b/packages/backend/src/models/UserPending.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts index 328dbeaa1c..7dbe0b3717 100644 --- a/packages/backend/src/models/UserProfile.ts +++ b/packages/backend/src/models/UserProfile.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -249,6 +249,8 @@ export class MiUserProfile { type: 'follower'; } | { type: 'mutualFollow'; + } | { + type: 'followingOrFollower'; } | { type: 'list'; userListId: MiUserList['id']; diff --git a/packages/backend/src/models/UserPublickey.ts b/packages/backend/src/models/UserPublickey.ts index 33de73c636..6bcd785304 100644 --- a/packages/backend/src/models/UserPublickey.ts +++ b/packages/backend/src/models/UserPublickey.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/UserSecurityKey.ts b/packages/backend/src/models/UserSecurityKey.ts index 02c29bfbb5..0babbe1abe 100644 --- a/packages/backend/src/models/UserSecurityKey.ts +++ b/packages/backend/src/models/UserSecurityKey.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/Webhook.ts b/packages/backend/src/models/Webhook.ts index ec4e13cc76..db24c03b3d 100644 --- a/packages/backend/src/models/Webhook.ts +++ b/packages/backend/src/models/Webhook.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts index a1a0d8823d..43d42d80dd 100644 --- a/packages/backend/src/models/_.ts +++ b/packages/backend/src/models/_.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/ad.ts b/packages/backend/src/models/json-schema/ad.ts index 649ffcd4dc..b01b39a38b 100644 --- a/packages/backend/src/models/json-schema/ad.ts +++ b/packages/backend/src/models/json-schema/ad.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/announcement.ts b/packages/backend/src/models/json-schema/announcement.ts index 78a98872b2..b9352bd31e 100644 --- a/packages/backend/src/models/json-schema/announcement.ts +++ b/packages/backend/src/models/json-schema/announcement.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -37,10 +37,12 @@ export const packedAnnouncementSchema = { icon: { type: 'string', optional: false, nullable: false, + enum: ['info', 'warning', 'error', 'success'], }, display: { type: 'string', optional: false, nullable: false, + enum: ['dialog', 'normal', 'banner'], }, needConfirmationToRead: { type: 'boolean', diff --git a/packages/backend/src/models/json-schema/antenna.ts b/packages/backend/src/models/json-schema/antenna.ts index 4a9f0ed355..74622b6193 100644 --- a/packages/backend/src/models/json-schema/antenna.ts +++ b/packages/backend/src/models/json-schema/antenna.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/app.ts b/packages/backend/src/models/json-schema/app.ts index 9e0916299c..6148232224 100644 --- a/packages/backend/src/models/json-schema/app.ts +++ b/packages/backend/src/models/json-schema/app.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/blocking.ts b/packages/backend/src/models/json-schema/blocking.ts index 0b58f1f8d7..2d02ba6a70 100644 --- a/packages/backend/src/models/json-schema/blocking.ts +++ b/packages/backend/src/models/json-schema/blocking.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -25,7 +25,7 @@ export const packedBlockingSchema = { blockee: { type: 'object', optional: false, nullable: false, - ref: 'UserDetailed', + ref: 'UserDetailedNotMe', }, }, } as const; diff --git a/packages/backend/src/models/json-schema/channel.ts b/packages/backend/src/models/json-schema/channel.ts index 5b0fa0f15d..d233f7858d 100644 --- a/packages/backend/src/models/json-schema/channel.ts +++ b/packages/backend/src/models/json-schema/channel.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/clip.ts b/packages/backend/src/models/json-schema/clip.ts index 1ab96c2b3b..ca4886c978 100644 --- a/packages/backend/src/models/json-schema/clip.ts +++ b/packages/backend/src/models/json-schema/clip.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/drive-file.ts b/packages/backend/src/models/json-schema/drive-file.ts index 79f242a711..ca88cc0e39 100644 --- a/packages/backend/src/models/json-schema/drive-file.ts +++ b/packages/backend/src/models/json-schema/drive-file.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/drive-folder.ts b/packages/backend/src/models/json-schema/drive-folder.ts index aaad301303..12012a7e12 100644 --- a/packages/backend/src/models/json-schema/drive-folder.ts +++ b/packages/backend/src/models/json-schema/drive-folder.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/emoji.ts b/packages/backend/src/models/json-schema/emoji.ts index 99a58f8773..62686ad5ae 100644 --- a/packages/backend/src/models/json-schema/emoji.ts +++ b/packages/backend/src/models/json-schema/emoji.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -27,6 +27,10 @@ export const packedEmojiSimpleSchema = { type: 'string', optional: false, nullable: false, }, + localOnly: { + type: 'boolean', + optional: true, nullable: false, + }, isSensitive: { type: 'boolean', optional: true, nullable: false, diff --git a/packages/backend/src/models/json-schema/federation-instance.ts b/packages/backend/src/models/json-schema/federation-instance.ts index 3417314272..42d98fe523 100644 --- a/packages/backend/src/models/json-schema/federation-instance.ts +++ b/packages/backend/src/models/json-schema/federation-instance.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -107,5 +107,9 @@ export const packedFederationInstanceSchema = { optional: false, nullable: true, format: 'date-time', }, + moderationNote: { + type: 'string', + optional: true, nullable: true, + }, }, } as const; diff --git a/packages/backend/src/models/json-schema/flash.ts b/packages/backend/src/models/json-schema/flash.ts index f08fa7a279..952df649ad 100644 --- a/packages/backend/src/models/json-schema/flash.ts +++ b/packages/backend/src/models/json-schema/flash.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/following.ts b/packages/backend/src/models/json-schema/following.ts index e92cff20a1..c5295a5128 100644 --- a/packages/backend/src/models/json-schema/following.ts +++ b/packages/backend/src/models/json-schema/following.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -30,12 +30,12 @@ export const packedFollowingSchema = { followee: { type: 'object', optional: true, nullable: false, - ref: 'UserDetailed', + ref: 'UserDetailedNotMe', }, follower: { type: 'object', optional: true, nullable: false, - ref: 'UserDetailed', + ref: 'UserDetailedNotMe', }, }, } as const; diff --git a/packages/backend/src/models/json-schema/gallery-post.ts b/packages/backend/src/models/json-schema/gallery-post.ts index df7038950c..a46d5115c2 100644 --- a/packages/backend/src/models/json-schema/gallery-post.ts +++ b/packages/backend/src/models/json-schema/gallery-post.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/hashtag.ts b/packages/backend/src/models/json-schema/hashtag.ts index a48e972a5d..4fd136afed 100644 --- a/packages/backend/src/models/json-schema/hashtag.ts +++ b/packages/backend/src/models/json-schema/hashtag.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/invite-code.ts b/packages/backend/src/models/json-schema/invite-code.ts index cd8bf98d90..08d1b8fd0c 100644 --- a/packages/backend/src/models/json-schema/invite-code.ts +++ b/packages/backend/src/models/json-schema/invite-code.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts new file mode 100644 index 0000000000..17789f3b46 --- /dev/null +++ b/packages/backend/src/models/json-schema/meta.ts @@ -0,0 +1,328 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export const packedMetaLiteSchema = { + type: 'object', + optional: false, nullable: false, + properties: { + maintainerName: { + type: 'string', + optional: false, nullable: true, + }, + maintainerEmail: { + type: 'string', + optional: false, nullable: true, + }, + version: { + type: 'string', + optional: false, nullable: false, + }, + providesTarball: { + type: 'boolean', + optional: false, nullable: false, + }, + name: { + type: 'string', + optional: false, nullable: true, + }, + shortName: { + type: 'string', + optional: false, nullable: true, + }, + uri: { + type: 'string', + optional: false, nullable: false, + format: 'url', + example: 'https://misskey.example.com', + }, + description: { + type: 'string', + optional: false, nullable: true, + }, + langs: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'string', + optional: false, nullable: false, + }, + }, + tosUrl: { + type: 'string', + optional: false, nullable: true, + }, + repositoryUrl: { + type: 'string', + optional: false, nullable: true, + default: 'https://github.com/misskey-dev/misskey', + }, + feedbackUrl: { + type: 'string', + optional: false, nullable: true, + default: 'https://github.com/misskey-dev/misskey/issues/new', + }, + defaultDarkTheme: { + type: 'string', + optional: false, nullable: true, + }, + defaultLightTheme: { + type: 'string', + optional: false, nullable: true, + }, + disableRegistration: { + type: 'boolean', + optional: false, nullable: false, + }, + emailRequiredForSignup: { + type: 'boolean', + optional: false, nullable: false, + }, + enableHcaptcha: { + type: 'boolean', + optional: false, nullable: false, + }, + hcaptchaSiteKey: { + type: 'string', + optional: false, nullable: true, + }, + enableMcaptcha: { + type: 'boolean', + optional: false, nullable: false, + }, + mcaptchaSiteKey: { + type: 'string', + optional: false, nullable: true, + }, + mcaptchaInstanceUrl: { + type: 'string', + optional: false, nullable: true, + }, + enableRecaptcha: { + type: 'boolean', + optional: false, nullable: false, + }, + recaptchaSiteKey: { + type: 'string', + optional: false, nullable: true, + }, + enableTurnstile: { + type: 'boolean', + optional: false, nullable: false, + }, + turnstileSiteKey: { + type: 'string', + optional: false, nullable: true, + }, + swPublickey: { + type: 'string', + optional: false, nullable: true, + }, + mascotImageUrl: { + type: 'string', + optional: false, nullable: false, + default: '/assets/ai.png', + }, + bannerUrl: { + type: 'string', + optional: false, nullable: true, + }, + serverErrorImageUrl: { + type: 'string', + optional: false, nullable: true, + }, + infoImageUrl: { + type: 'string', + optional: false, nullable: true, + }, + notFoundImageUrl: { + type: 'string', + optional: false, nullable: true, + }, + iconUrl: { + type: 'string', + optional: false, nullable: true, + }, + maxNoteTextLength: { + type: 'number', + optional: false, nullable: false, + }, + ads: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + properties: { + id: { + type: 'string', + optional: false, nullable: false, + format: 'id', + example: 'xxxxxxxxxx', + }, + url: { + type: 'string', + optional: false, nullable: false, + format: 'url', + }, + place: { + type: 'string', + optional: false, nullable: false, + }, + ratio: { + type: 'number', + optional: false, nullable: false, + }, + imageUrl: { + type: 'string', + optional: false, nullable: false, + format: 'url', + }, + dayOfWeek: { + type: 'integer', + optional: false, nullable: false, + }, + }, + }, + }, + notesPerOneAd: { + type: 'number', + optional: false, nullable: false, + default: 0, + }, + enableEmail: { + type: 'boolean', + optional: false, nullable: false, + }, + enableServiceWorker: { + type: 'boolean', + optional: false, nullable: false, + }, + translatorAvailable: { + type: 'boolean', + optional: false, nullable: false, + }, + mediaProxy: { + type: 'string', + optional: false, nullable: false, + }, + backgroundImageUrl: { + type: 'string', + optional: false, nullable: true, + }, + impressumUrl: { + type: 'string', + optional: false, nullable: true, + }, + logoImageUrl: { + type: 'string', + optional: false, nullable: true, + }, + privacyPolicyUrl: { + type: 'string', + optional: false, nullable: true, + }, + serverRules: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'string', + }, + }, + themeColor: { + type: 'string', + optional: false, nullable: true, + }, + policies: { + type: 'object', + optional: false, nullable: false, + ref: 'RolePolicies', + }, + }, +} as const; + +export const packedMetaDetailedOnlySchema = { + type: 'object', + optional: false, nullable: false, + properties: { + features: { + type: 'object', + optional: true, nullable: false, + properties: { + registration: { + type: 'boolean', + optional: false, nullable: false, + }, + emailRequiredForSignup: { + type: 'boolean', + optional: false, nullable: false, + }, + localTimeline: { + type: 'boolean', + optional: false, nullable: false, + }, + globalTimeline: { + type: 'boolean', + optional: false, nullable: false, + }, + hcaptcha: { + type: 'boolean', + optional: false, nullable: false, + }, + turnstile: { + type: 'boolean', + optional: false, nullable: false, + }, + recaptcha: { + type: 'boolean', + optional: false, nullable: false, + }, + objectStorage: { + type: 'boolean', + optional: false, nullable: false, + }, + serviceWorker: { + type: 'boolean', + optional: false, nullable: false, + }, + miauth: { + type: 'boolean', + optional: true, nullable: false, + default: true, + }, + }, + }, + proxyAccountName: { + type: 'string', + optional: false, nullable: true, + }, + requireSetup: { + type: 'boolean', + optional: false, nullable: false, + example: false, + }, + cacheRemoteFiles: { + type: 'boolean', + optional: false, nullable: false, + }, + cacheRemoteSensitiveFiles: { + type: 'boolean', + optional: false, nullable: false, + }, + }, +} as const; + +export const packedMetaDetailedSchema = { + type: 'object', + allOf: [ + { + type: 'object', + ref: 'MetaLite', + }, + { + type: 'object', + ref: 'MetaDetailedOnly', + }, + ], +} as const; diff --git a/packages/backend/src/models/json-schema/muting.ts b/packages/backend/src/models/json-schema/muting.ts index dde9dc0288..b5fab013ef 100644 --- a/packages/backend/src/models/json-schema/muting.ts +++ b/packages/backend/src/models/json-schema/muting.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -30,7 +30,7 @@ export const packedMutingSchema = { mutee: { type: 'object', optional: false, nullable: false, - ref: 'UserDetailed', + ref: 'UserDetailedNotMe', }, }, } as const; diff --git a/packages/backend/src/models/json-schema/note-favorite.ts b/packages/backend/src/models/json-schema/note-favorite.ts index 3f0007d917..d2a3745f4b 100644 --- a/packages/backend/src/models/json-schema/note-favorite.ts +++ b/packages/backend/src/models/json-schema/note-favorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/note-reaction.ts b/packages/backend/src/models/json-schema/note-reaction.ts index e3335f426e..95658ace1f 100644 --- a/packages/backend/src/models/json-schema/note-reaction.ts +++ b/packages/backend/src/models/json-schema/note-reaction.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts index 2b7722129b..bb4ccc7ee4 100644 --- a/packages/backend/src/models/json-schema/note.ts +++ b/packages/backend/src/models/json-schema/note.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -69,6 +69,7 @@ export const packedNoteSchema = { visibility: { type: 'string', optional: false, nullable: false, + enum: ['public', 'home', 'followers', 'specified'], }, mentions: { type: 'array', @@ -117,6 +118,48 @@ export const packedNoteSchema = { poll: { type: 'object', optional: true, nullable: true, + properties: { + expiresAt: { + type: 'string', + optional: true, nullable: true, + format: 'date-time', + }, + multiple: { + type: 'boolean', + optional: false, nullable: false, + }, + choices: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + properties: { + isVoted: { + type: 'boolean', + optional: false, nullable: false, + }, + text: { + type: 'string', + optional: false, nullable: false, + }, + votes: { + type: 'number', + optional: false, nullable: false, + }, + }, + }, + }, + }, + }, + emojis: { + type: 'object', + optional: true, nullable: false, + additionalProperties: { + anyOf: [{ + type: 'string', + }], + }, }, channelId: { type: 'string', @@ -162,9 +205,23 @@ export const packedNoteSchema = { type: 'string', optional: false, nullable: true, }, + reactionEmojis: { + type: 'object', + optional: false, nullable: false, + additionalProperties: { + anyOf: [{ + type: 'string', + }], + }, + }, reactions: { type: 'object', optional: false, nullable: false, + additionalProperties: { + anyOf: [{ + type: 'number', + }], + }, }, renoteCount: { type: 'number', @@ -196,7 +253,7 @@ export const packedNoteSchema = { }, myReaction: { - type: 'object', + type: 'string', optional: true, nullable: true, }, }, diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts index c6d6e84317..b4c4442758 100644 --- a/packages/backend/src/models/json-schema/notification.ts +++ b/packages/backend/src/models/json-schema/notification.ts @@ -1,11 +1,11 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ import { notificationTypes } from '@/types.js'; -export const packedNotificationSchema = { +const baseSchema = { type: 'object', properties: { id: { @@ -23,68 +23,368 @@ export const packedNotificationSchema = { optional: false, nullable: false, enum: [...notificationTypes, 'reaction:grouped', 'renote:grouped'], }, - user: { - type: 'object', - ref: 'UserLite', - optional: true, nullable: true, - }, - userId: { - type: 'string', - optional: true, nullable: true, - format: 'id', - }, - note: { - type: 'object', - ref: 'Note', - optional: true, nullable: true, - }, - reaction: { - type: 'string', - optional: true, nullable: true, - }, - achievement: { - type: 'string', - optional: true, nullable: false, - }, - body: { - type: 'string', - optional: true, nullable: true, - }, - header: { - type: 'string', - optional: true, nullable: true, - }, - icon: { - type: 'string', - optional: true, nullable: true, - }, - reactions: { - type: 'array', - optional: true, nullable: true, - items: { - type: 'object', - properties: { - user: { - type: 'object', - ref: 'UserLite', - optional: false, nullable: false, - }, - reaction: { - type: 'string', - optional: false, nullable: false, - }, - }, - required: ['user', 'reaction'], + }, +} as const; + +export const packedNotificationSchema = { + type: 'object', + oneOf: [{ + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['note'], }, - }, - users: { - type: 'array', - optional: true, nullable: true, - items: { + user: { type: 'object', ref: 'UserLite', optional: false, nullable: false, }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + note: { + type: 'object', + ref: 'Note', + optional: false, nullable: false, + }, }, - }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['mention'], + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + note: { + type: 'object', + ref: 'Note', + optional: false, nullable: false, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['reply'], + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + note: { + type: 'object', + ref: 'Note', + optional: false, nullable: false, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['renote'], + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + note: { + type: 'object', + ref: 'Note', + optional: false, nullable: false, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['quote'], + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + note: { + type: 'object', + ref: 'Note', + optional: false, nullable: false, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['reaction'], + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + note: { + type: 'object', + ref: 'Note', + optional: false, nullable: false, + }, + reaction: { + type: 'string', + optional: false, nullable: false, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['pollEnded'], + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + note: { + type: 'object', + ref: 'Note', + optional: false, nullable: false, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['follow'], + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['receiveFollowRequest'], + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['followRequestAccepted'], + }, + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + userId: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['roleAssigned'], + }, + role: { + type: 'object', + ref: 'Role', + optional: false, nullable: false, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['achievementEarned'], + }, + achievement: { + type: 'string', + optional: false, nullable: false, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['app'], + }, + body: { + type: 'string', + optional: false, nullable: false, + }, + header: { + type: 'string', + optional: false, nullable: false, + }, + icon: { + type: 'string', + optional: false, nullable: false, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['reaction:grouped'], + }, + note: { + type: 'object', + ref: 'Note', + optional: false, nullable: false, + }, + reactions: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + properties: { + user: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + reaction: { + type: 'string', + optional: false, nullable: false, + }, + }, + required: ['user', 'reaction'], + }, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['renote:grouped'], + }, + note: { + type: 'object', + ref: 'Note', + optional: false, nullable: false, + }, + users: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + ref: 'UserLite', + optional: false, nullable: false, + }, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['test'], + }, + }, + }], } as const; diff --git a/packages/backend/src/models/json-schema/page.ts b/packages/backend/src/models/json-schema/page.ts index 9baacd6884..748d6f1245 100644 --- a/packages/backend/src/models/json-schema/page.ts +++ b/packages/backend/src/models/json-schema/page.ts @@ -1,8 +1,110 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +const blockBaseSchema = { + type: 'object', + properties: { + id: { + type: 'string', + optional: false, nullable: false, + }, + type: { + type: 'string', + optional: false, nullable: false, + }, + }, +} as const; + +const textBlockSchema = { + type: 'object', + properties: { + ...blockBaseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['text'], + }, + text: { + type: 'string', + optional: false, nullable: false, + }, + }, +} as const; + +const sectionBlockSchema = { + type: 'object', + properties: { + ...blockBaseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['section'], + }, + title: { + type: 'string', + optional: false, nullable: false, + }, + children: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'PageBlock', + selfRef: true, + }, + }, + }, +} as const; + +const imageBlockSchema = { + type: 'object', + properties: { + ...blockBaseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['image'], + }, + fileId: { + type: 'string', + optional: false, nullable: true, + }, + }, +} as const; + +const noteBlockSchema = { + type: 'object', + properties: { + ...blockBaseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['note'], + }, + detailed: { + type: 'boolean', + optional: false, nullable: false, + }, + note: { + type: 'string', + optional: false, nullable: true, + }, + }, +} as const; + +export const packedPageBlockSchema = { + type: 'object', + oneOf: [ + textBlockSchema, + sectionBlockSchema, + imageBlockSchema, + noteBlockSchema, + ], +} as const; + export const packedPageSchema = { type: 'object', properties: { @@ -38,6 +140,7 @@ export const packedPageSchema = { items: { type: 'object', optional: false, nullable: false, + ref: 'PageBlock', }, }, variables: { diff --git a/packages/backend/src/models/json-schema/queue.ts b/packages/backend/src/models/json-schema/queue.ts index 43da6e605d..2ecf5c831f 100644 --- a/packages/backend/src/models/json-schema/queue.ts +++ b/packages/backend/src/models/json-schema/queue.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/renote-muting.ts b/packages/backend/src/models/json-schema/renote-muting.ts index feed1ceb09..344d6c7c00 100644 --- a/packages/backend/src/models/json-schema/renote-muting.ts +++ b/packages/backend/src/models/json-schema/renote-muting.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -25,7 +25,7 @@ export const packedRenoteMutingSchema = { mutee: { type: 'object', optional: false, nullable: false, - ref: 'UserDetailed', + ref: 'UserDetailedNotMe', }, }, } as const; diff --git a/packages/backend/src/models/json-schema/reversi-game.ts b/packages/backend/src/models/json-schema/reversi-game.ts index ff4c78eeb0..cb37200384 100644 --- a/packages/backend/src/models/json-schema/reversi-game.ts +++ b/packages/backend/src/models/json-schema/reversi-game.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -47,12 +47,12 @@ export const packedReversiGameLiteSchema = { user1: { type: 'object', optional: false, nullable: false, - ref: 'User', + ref: 'UserLite', }, user2: { type: 'object', optional: false, nullable: false, - ref: 'User', + ref: 'UserLite', }, winnerId: { type: 'string', @@ -62,7 +62,7 @@ export const packedReversiGameLiteSchema = { winner: { type: 'object', optional: false, nullable: true, - ref: 'User', + ref: 'UserLite', }, surrenderedUserId: { type: 'string', @@ -165,12 +165,12 @@ export const packedReversiGameDetailedSchema = { user1: { type: 'object', optional: false, nullable: false, - ref: 'User', + ref: 'UserLite', }, user2: { type: 'object', optional: false, nullable: false, - ref: 'User', + ref: 'UserLite', }, winnerId: { type: 'string', @@ -180,7 +180,7 @@ export const packedReversiGameDetailedSchema = { winner: { type: 'object', optional: false, nullable: true, - ref: 'User', + ref: 'UserLite', }, surrenderedUserId: { type: 'string', @@ -226,6 +226,9 @@ export const packedReversiGameDetailedSchema = { items: { type: 'array', optional: false, nullable: false, + items: { + type: 'number', + }, }, }, map: { diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts index b0c6804bb8..c770250503 100644 --- a/packages/backend/src/models/json-schema/role.ts +++ b/packages/backend/src/models/json-schema/role.ts @@ -1,26 +1,256 @@ -const rolePolicyValue = { +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export const packedRoleCondFormulaLogicsSchema = { type: 'object', properties: { + id: { + type: 'string', optional: false, + }, + type: { + type: 'string', + nullable: false, optional: false, + enum: ['and', 'or'], + }, + values: { + type: 'array', + nullable: false, optional: false, + items: { + ref: 'RoleCondFormulaValue', + }, + }, + }, +} as const; + +export const packedRoleCondFormulaValueNot = { + type: 'object', + properties: { + id: { + type: 'string', optional: false, + }, + type: { + type: 'string', + nullable: false, optional: false, + enum: ['not'], + }, value: { - oneOf: [ - { - type: 'integer', - optional: false, nullable: false, - }, - { - type: 'boolean', - optional: false, nullable: false, - }, + type: 'object', + optional: false, + ref: 'RoleCondFormulaValue', + }, + }, +} as const; + +export const packedRoleCondFormulaValueIsLocalOrRemoteSchema = { + type: 'object', + properties: { + id: { + type: 'string', optional: false, + }, + type: { + type: 'string', + nullable: false, optional: false, + enum: ['isLocal', 'isRemote'], + }, + }, +} as const; + +export const packedRoleCondFormulaValueAssignedRoleSchema = { + type: 'object', + properties: { + id: { + type: 'string', optional: false, + }, + type: { + type: 'string', + nullable: false, optional: false, + enum: ['roleAssignedTo'], + }, + roleId: { + type: 'string', + nullable: false, optional: false, + format: 'id', + example: 'xxxxxxxxxx', + }, + }, +} as const; + +export const packedRoleCondFormulaValueCreatedSchema = { + type: 'object', + properties: { + id: { + type: 'string', optional: false, + }, + type: { + type: 'string', + nullable: false, optional: false, + enum: [ + 'createdLessThan', + 'createdMoreThan', ], }, - priority: { + sec: { + type: 'number', + nullable: false, optional: false, + }, + }, +} as const; + +export const packedRoleCondFormulaFollowersOrFollowingOrNotesSchema = { + type: 'object', + properties: { + id: { + type: 'string', optional: false, + }, + type: { + type: 'string', + nullable: false, optional: false, + enum: [ + 'followersLessThanOrEq', + 'followersMoreThanOrEq', + 'followingLessThanOrEq', + 'followingMoreThanOrEq', + 'notesLessThanOrEq', + 'notesMoreThanOrEq', + ], + }, + value: { + type: 'number', + nullable: false, optional: false, + }, + }, +} as const; + +export const packedRoleCondFormulaValueSchema = { + type: 'object', + oneOf: [ + { + ref: 'RoleCondFormulaLogics', + }, + { + ref: 'RoleCondFormulaValueNot', + }, + { + ref: 'RoleCondFormulaValueIsLocalOrRemote', + }, + { + ref: 'RoleCondFormulaValueAssignedRole', + }, + { + ref: 'RoleCondFormulaValueCreated', + }, + { + ref: 'RoleCondFormulaFollowersOrFollowingOrNotes', + }, + ], +} as const; + +export const packedRolePoliciesSchema = { + type: 'object', + optional: false, nullable: false, + properties: { + gtlAvailable: { + type: 'boolean', + optional: false, nullable: false, + }, + ltlAvailable: { + type: 'boolean', + optional: false, nullable: false, + }, + canPublicNote: { + type: 'boolean', + optional: false, nullable: false, + }, + mentionLimit: { type: 'integer', optional: false, nullable: false, }, - useDefault: { + canInvite: { type: 'boolean', optional: false, nullable: false, }, + inviteLimit: { + type: 'integer', + optional: false, nullable: false, + }, + inviteLimitCycle: { + type: 'integer', + optional: false, nullable: false, + }, + inviteExpirationTime: { + type: 'integer', + optional: false, nullable: false, + }, + canManageCustomEmojis: { + type: 'boolean', + optional: false, nullable: false, + }, + canManageAvatarDecorations: { + type: 'boolean', + optional: false, nullable: false, + }, + canSearchNotes: { + type: 'boolean', + optional: false, nullable: false, + }, + canUseTranslator: { + type: 'boolean', + optional: false, nullable: false, + }, + canHideAds: { + type: 'boolean', + optional: false, nullable: false, + }, + driveCapacityMb: { + type: 'integer', + optional: false, nullable: false, + }, + alwaysMarkNsfw: { + type: 'boolean', + optional: false, nullable: false, + }, + pinLimit: { + type: 'integer', + optional: false, nullable: false, + }, + antennaLimit: { + type: 'integer', + optional: false, nullable: false, + }, + wordMuteLimit: { + type: 'integer', + optional: false, nullable: false, + }, + webhookLimit: { + type: 'integer', + optional: false, nullable: false, + }, + clipLimit: { + type: 'integer', + optional: false, nullable: false, + }, + noteEachClipsLimit: { + type: 'integer', + optional: false, nullable: false, + }, + userListLimit: { + type: 'integer', + optional: false, nullable: false, + }, + userEachUserListsLimit: { + type: 'integer', + optional: false, nullable: false, + }, + rateLimitFactor: { + type: 'integer', + optional: false, nullable: false, + }, + avatarDecorationLimit: { + type: 'integer', + optional: false, nullable: false, + }, }, } as const; @@ -97,6 +327,7 @@ export const packedRoleSchema = { condFormula: { type: 'object', optional: false, nullable: false, + ref: 'RoleCondFormulaValue', }, isPublic: { type: 'boolean', @@ -121,31 +352,28 @@ export const packedRoleSchema = { policies: { type: 'object', optional: false, nullable: false, - properties: { - pinLimit: rolePolicyValue, - canInvite: rolePolicyValue, - clipLimit: rolePolicyValue, - canHideAds: rolePolicyValue, - inviteLimit: rolePolicyValue, - antennaLimit: rolePolicyValue, - gtlAvailable: rolePolicyValue, - ltlAvailable: rolePolicyValue, - webhookLimit: rolePolicyValue, - canPublicNote: rolePolicyValue, - userListLimit: rolePolicyValue, - wordMuteLimit: rolePolicyValue, - alwaysMarkNsfw: rolePolicyValue, - canSearchNotes: rolePolicyValue, - driveCapacityMb: rolePolicyValue, - rateLimitFactor: rolePolicyValue, - inviteLimitCycle: rolePolicyValue, - noteEachClipsLimit: rolePolicyValue, - inviteExpirationTime: rolePolicyValue, - canManageCustomEmojis: rolePolicyValue, - userEachUserListsLimit: rolePolicyValue, - canManageAvatarDecorations: rolePolicyValue, - canUseTranslator: rolePolicyValue, - avatarDecorationLimit: rolePolicyValue, + additionalProperties: { + anyOf: [{ + type: 'object', + properties: { + value: { + oneOf: [ + { + type: 'integer', + }, + { + type: 'boolean', + }, + ], + }, + priority: { + type: 'integer', + }, + useDefault: { + type: 'boolean', + }, + }, + }], }, }, usersCount: { diff --git a/packages/backend/src/models/json-schema/user-list.ts b/packages/backend/src/models/json-schema/user-list.ts index e257d9984c..dc9af25602 100644 --- a/packages/backend/src/models/json-schema/user-list.ts +++ b/packages/backend/src/models/json-schema/user-list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 6a0d43b1ac..947a9317d7 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -1,18 +1,40 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -const notificationRecieveConfig = { +export const notificationRecieveConfig = { type: 'object', - nullable: false, optional: true, - properties: { - type: { - type: 'string', - nullable: false, optional: false, - enum: ['all', 'following', 'follower', 'mutualFollow', 'list', 'never'], + oneOf: [ + { + type: 'object', + nullable: false, + properties: { + type: { + type: 'string', + nullable: false, + enum: ['all', 'following', 'follower', 'mutualFollow', 'followingOrFollower', 'never'], + }, + }, + required: ['type'], }, - }, + { + type: 'object', + nullable: false, + properties: { + type: { + type: 'string', + nullable: false, + enum: ['list'], + }, + userListId: { + type: 'string', + format: 'misskey:id', + }, + }, + required: ['type', 'userListId'], + }, + ], } as const; export const packedUserLiteSchema = { @@ -126,6 +148,9 @@ export const packedUserLiteSchema = { emojis: { type: 'object', nullable: false, optional: false, + additionalProperties: { + type: 'string', + }, }, onlineStatus: { type: 'string', @@ -546,15 +571,20 @@ export const packedMeDetailedOnlySchema = { type: 'object', nullable: false, optional: false, properties: { - app: notificationRecieveConfig, - quote: notificationRecieveConfig, - reply: notificationRecieveConfig, - follow: notificationRecieveConfig, - renote: notificationRecieveConfig, - mention: notificationRecieveConfig, - reaction: notificationRecieveConfig, - pollEnded: notificationRecieveConfig, - receiveFollowRequest: notificationRecieveConfig, + note: { optional: true, ...notificationRecieveConfig }, + follow: { optional: true, ...notificationRecieveConfig }, + mention: { optional: true, ...notificationRecieveConfig }, + reply: { optional: true, ...notificationRecieveConfig }, + renote: { optional: true, ...notificationRecieveConfig }, + quote: { optional: true, ...notificationRecieveConfig }, + reaction: { optional: true, ...notificationRecieveConfig }, + pollEnded: { optional: true, ...notificationRecieveConfig }, + receiveFollowRequest: { optional: true, ...notificationRecieveConfig }, + followRequestAccepted: { optional: true, ...notificationRecieveConfig }, + roleAssigned: { optional: true, ...notificationRecieveConfig }, + achievementEarned: { optional: true, ...notificationRecieveConfig }, + app: { optional: true, ...notificationRecieveConfig }, + test: { optional: true, ...notificationRecieveConfig }, }, }, emailNotificationTypes: { @@ -590,104 +620,7 @@ export const packedMeDetailedOnlySchema = { policies: { type: 'object', nullable: false, optional: false, - properties: { - gtlAvailable: { - type: 'boolean', - nullable: false, optional: false, - }, - ltlAvailable: { - type: 'boolean', - nullable: false, optional: false, - }, - canPublicNote: { - type: 'boolean', - nullable: false, optional: false, - }, - canInvite: { - type: 'boolean', - nullable: false, optional: false, - }, - inviteLimit: { - type: 'number', - nullable: false, optional: false, - }, - inviteLimitCycle: { - type: 'number', - nullable: false, optional: false, - }, - inviteExpirationTime: { - type: 'number', - nullable: false, optional: false, - }, - canManageCustomEmojis: { - type: 'boolean', - nullable: false, optional: false, - }, - canManageAvatarDecorations: { - type: 'boolean', - nullable: false, optional: false, - }, - canSearchNotes: { - type: 'boolean', - nullable: false, optional: false, - }, - canUseTranslator: { - type: 'boolean', - nullable: false, optional: false, - }, - canHideAds: { - type: 'boolean', - nullable: false, optional: false, - }, - driveCapacityMb: { - type: 'number', - nullable: false, optional: false, - }, - alwaysMarkNsfw: { - type: 'boolean', - nullable: false, optional: false, - }, - pinLimit: { - type: 'number', - nullable: false, optional: false, - }, - antennaLimit: { - type: 'number', - nullable: false, optional: false, - }, - wordMuteLimit: { - type: 'number', - nullable: false, optional: false, - }, - webhookLimit: { - type: 'number', - nullable: false, optional: false, - }, - clipLimit: { - type: 'number', - nullable: false, optional: false, - }, - noteEachClipsLimit: { - type: 'number', - nullable: false, optional: false, - }, - userListLimit: { - type: 'number', - nullable: false, optional: false, - }, - userEachUserListsLimit: { - type: 'number', - nullable: false, optional: false, - }, - rateLimitFactor: { - type: 'number', - nullable: false, optional: false, - }, - avatarDecorationLimit: { - type: 'number', - nullable: false, optional: false, - }, - }, + ref: 'RolePolicies', }, //#region secrets email: { @@ -782,13 +715,5 @@ export const packedUserSchema = { type: 'object', ref: 'UserDetailed', }, - { - type: 'object', - ref: 'UserDetailedNotMe', - }, - { - type: 'object', - ref: 'MeDetailed', - }, ], } as const; diff --git a/packages/backend/src/models/util/id.ts b/packages/backend/src/models/util/id.ts index 81e83b8db9..2d742702c7 100644 --- a/packages/backend/src/models/util/id.ts +++ b/packages/backend/src/models/util/id.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/postgres.ts b/packages/backend/src/postgres.ts index 543cedc867..2d14537bbb 100644 --- a/packages/backend/src/postgres.ts +++ b/packages/backend/src/postgres.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/QueueLoggerService.ts b/packages/backend/src/queue/QueueLoggerService.ts index 618d1d5c2f..65869afd46 100644 --- a/packages/backend/src/queue/QueueLoggerService.ts +++ b/packages/backend/src/queue/QueueLoggerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/QueueProcessorModule.ts b/packages/backend/src/queue/QueueProcessorModule.ts index 9c52c7d76a..8086158997 100644 --- a/packages/backend/src/queue/QueueProcessorModule.ts +++ b/packages/backend/src/queue/QueueProcessorModule.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts index bcc1a69f80..ce999d9cef 100644 --- a/packages/backend/src/queue/QueueProcessorService.ts +++ b/packages/backend/src/queue/QueueProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -283,9 +283,9 @@ export class QueueProcessorService implements OnApplicationShutdown { }, { ...baseQueueOptions(this.config, QUEUE.RELATIONSHIP), autorun: false, - concurrency: this.config.relashionshipJobConcurrency ?? 16, + concurrency: this.config.relationshipJobConcurrency ?? 16, limiter: { - max: this.config.relashionshipJobPerSec ?? 64, + max: this.config.relationshipJobPerSec ?? 64, duration: 1000, }, }); diff --git a/packages/backend/src/queue/const.ts b/packages/backend/src/queue/const.ts index 87d075304d..132e916612 100644 --- a/packages/backend/src/queue/const.ts +++ b/packages/backend/src/queue/const.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts b/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts index 9f49d85c7f..4769cccabf 100644 --- a/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts +++ b/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/CheckExpiredMutingsProcessorService.ts b/packages/backend/src/queue/processors/CheckExpiredMutingsProcessorService.ts index 9b07389dc3..448fc9c763 100644 --- a/packages/backend/src/queue/processors/CheckExpiredMutingsProcessorService.ts +++ b/packages/backend/src/queue/processors/CheckExpiredMutingsProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/CleanChartsProcessorService.ts b/packages/backend/src/queue/processors/CleanChartsProcessorService.ts index 55c444eee6..110468801c 100644 --- a/packages/backend/src/queue/processors/CleanChartsProcessorService.ts +++ b/packages/backend/src/queue/processors/CleanChartsProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/CleanProcessorService.ts b/packages/backend/src/queue/processors/CleanProcessorService.ts index 17b6c8ba0c..a26b69cd2b 100644 --- a/packages/backend/src/queue/processors/CleanProcessorService.ts +++ b/packages/backend/src/queue/processors/CleanProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts b/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts index b62cc8a8fd..917de8b72c 100644 --- a/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts +++ b/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts b/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts index 39967165d4..14a53e0c42 100644 --- a/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts +++ b/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/DeleteDriveFilesProcessorService.ts b/packages/backend/src/queue/processors/DeleteDriveFilesProcessorService.ts index 6d0a45bcc0..291fa4a6d8 100644 --- a/packages/backend/src/queue/processors/DeleteDriveFilesProcessorService.ts +++ b/packages/backend/src/queue/processors/DeleteDriveFilesProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/DeleteFileProcessorService.ts b/packages/backend/src/queue/processors/DeleteFileProcessorService.ts index a4638bfaaf..fc1dd93ce7 100644 --- a/packages/backend/src/queue/processors/DeleteFileProcessorService.ts +++ b/packages/backend/src/queue/processors/DeleteFileProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/DeliverProcessorService.ts b/packages/backend/src/queue/processors/DeliverProcessorService.ts index 64c3445552..5fed070929 100644 --- a/packages/backend/src/queue/processors/DeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/DeliverProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts b/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts index 4a48084436..29c1f27bb1 100644 --- a/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts +++ b/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts index d0968d2923..af48bad417 100644 --- a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts b/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts index 0a37e3ca1e..6ec3c18786 100644 --- a/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ExportClipsProcessorService.ts b/packages/backend/src/queue/processors/ExportClipsProcessorService.ts index 5221497bd3..01eab26e96 100644 --- a/packages/backend/src/queue/processors/ExportClipsProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportClipsProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts b/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts index d5387fe42e..e4eb4791bd 100644 --- a/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts b/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts index af2a3434a9..7bb626dd31 100644 --- a/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts index c9739eb1cb..1cc80e66d7 100644 --- a/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ExportMutingProcessorService.ts b/packages/backend/src/queue/processors/ExportMutingProcessorService.ts index c8425c1f2d..243b74f2c2 100644 --- a/packages/backend/src/queue/processors/ExportMutingProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportMutingProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ExportNotesProcessorService.ts b/packages/backend/src/queue/processors/ExportNotesProcessorService.ts index cd4ccb0b07..c7611012d7 100644 --- a/packages/backend/src/queue/processors/ExportNotesProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportNotesProcessorService.ts @@ -1,9 +1,9 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -import * as fs from 'node:fs'; +import { ReadableStream, TextEncoderStream } from 'node:stream/web'; import { Inject, Injectable } from '@nestjs/common'; import { MoreThan } from 'typeorm'; import { format as dateFormat } from 'date-fns'; @@ -18,10 +18,82 @@ import { bindThis } from '@/decorators.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import { Packed } from '@/misc/json-schema.js'; import { IdService } from '@/core/IdService.js'; +import { JsonArrayStream } from '@/misc/JsonArrayStream.js'; +import { FileWriterStream } from '@/misc/FileWriterStream.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; import type * as Bull from 'bullmq'; import type { DbJobDataWithUser } from '../types.js'; +class NoteStream extends ReadableStream> { + constructor( + job: Bull.Job, + notesRepository: NotesRepository, + pollsRepository: PollsRepository, + driveFileEntityService: DriveFileEntityService, + idService: IdService, + userId: string, + ) { + let exportedNotesCount = 0; + let cursor: MiNote['id'] | null = null; + + const serialize = ( + note: MiNote, + poll: MiPoll | null, + files: Packed<'DriveFile'>[], + ): Record => { + return { + id: note.id, + text: note.text, + createdAt: idService.parse(note.id).date.toISOString(), + fileIds: note.fileIds, + files: files, + replyId: note.replyId, + renoteId: note.renoteId, + poll: poll, + cw: note.cw, + visibility: note.visibility, + visibleUserIds: note.visibleUserIds, + localOnly: note.localOnly, + reactionAcceptance: note.reactionAcceptance, + }; + }; + + super({ + async pull(controller): Promise { + const notes = await notesRepository.find({ + where: { + userId, + ...(cursor !== null ? { id: MoreThan(cursor) } : {}), + }, + take: 100, // 100件ずつ取得 + order: { id: 1 }, + }); + + if (notes.length === 0) { + job.updateProgress(100); + controller.close(); + } + + cursor = notes.at(-1)?.id ?? null; + + for (const note of notes) { + const poll = note.hasPoll + ? await pollsRepository.findOneByOrFail({ noteId: note.id }) // N+1 + : null; + const files = await driveFileEntityService.packManyByIds(note.fileIds); // N+1 + const content = serialize(note, poll, files); + + controller.enqueue(content); + exportedNotesCount++; + } + + const total = await notesRepository.countBy({ userId }); + job.updateProgress(exportedNotesCount / total); + }, + }); + } +} + @Injectable() export class ExportNotesProcessorService { private logger: Logger; @@ -59,67 +131,19 @@ export class ExportNotesProcessorService { this.logger.info(`Temp file is ${path}`); try { - const stream = fs.createWriteStream(path, { flags: 'a' }); + // メモリが足りなくならないようにストリームで処理する + await new NoteStream( + job, + this.notesRepository, + this.pollsRepository, + this.driveFileEntityService, + this.idService, + user.id, + ) + .pipeThrough(new JsonArrayStream()) + .pipeThrough(new TextEncoderStream()) + .pipeTo(new FileWriterStream(path)); - const write = (text: string): Promise => { - return new Promise((res, rej) => { - stream.write(text, err => { - if (err) { - this.logger.error(err); - rej(err); - } else { - res(); - } - }); - }); - }; - - await write('['); - - let exportedNotesCount = 0; - let cursor: MiNote['id'] | null = null; - - while (true) { - const notes = await this.notesRepository.find({ - where: { - userId: user.id, - ...(cursor ? { id: MoreThan(cursor) } : {}), - }, - take: 100, - order: { - id: 1, - }, - }) as MiNote[]; - - if (notes.length === 0) { - job.updateProgress(100); - break; - } - - cursor = notes.at(-1)?.id ?? null; - - for (const note of notes) { - let poll: MiPoll | undefined; - if (note.hasPoll) { - poll = await this.pollsRepository.findOneByOrFail({ noteId: note.id }); - } - const files = await this.driveFileEntityService.packManyByIds(note.fileIds); - const content = JSON.stringify(this.serialize(note, poll, files)); - const isFirst = exportedNotesCount === 0; - await write(isFirst ? content : ',\n' + content); - exportedNotesCount++; - } - - const total = await this.notesRepository.countBy({ - userId: user.id, - }); - - job.updateProgress(exportedNotesCount / total); - } - - await write(']'); - - stream.end(); this.logger.succ(`Exported to: ${path}`); const fileName = 'notes-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.json'; @@ -130,22 +154,4 @@ export class ExportNotesProcessorService { cleanup(); } } - - private serialize(note: MiNote, poll: MiPoll | null = null, files: Packed<'DriveFile'>[]): Record { - return { - id: note.id, - text: note.text, - createdAt: this.idService.parse(note.id).date.toISOString(), - fileIds: note.fileIds, - files: files, - replyId: note.replyId, - renoteId: note.renoteId, - poll: poll, - cw: note.cw, - visibility: note.visibility, - visibleUserIds: note.visibleUserIds, - localOnly: note.localOnly, - reactionAcceptance: note.reactionAcceptance, - }; - } } diff --git a/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts b/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts index a3f9441dc2..ee87cff5d3 100644 --- a/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts index 291ea14b67..951b560597 100644 --- a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts b/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts index 64520b770b..b78229c648 100644 --- a/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts index a52af54a39..171809d25c 100644 --- a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts index e75499a56f..70c9f3a096 100644 --- a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ImportMutingProcessorService.ts b/packages/backend/src/queue/processors/ImportMutingProcessorService.ts index 9db4e5d8e0..ec9d2b6c4c 100644 --- a/packages/backend/src/queue/processors/ImportMutingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportMutingProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts b/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts index 5dd3fbe887..a5992c28c8 100644 --- a/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index 50e7a1631e..3addead058 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -24,6 +24,7 @@ import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; import { LdSignatureService } from '@/core/activitypub/LdSignatureService.js'; import { ApInboxService } from '@/core/activitypub/ApInboxService.js'; import { bindThis } from '@/decorators.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; import type { InboxJobData } from '../types.js'; @@ -180,7 +181,17 @@ export class InboxProcessorService { }); // アクティビティを処理 - await this.apInboxService.performActivity(authUser.user, activity); + try { + await this.apInboxService.performActivity(authUser.user, activity); + } catch (e) { + if (e instanceof IdentifiableError) { + if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') { + return 'blocked notes with prohibited words'; + } + if (e.id === '85ab9bd7-3a41-4530-959d-f07073900109') return 'actor has been suspended'; + } + throw e; + } return 'ok'; } } diff --git a/packages/backend/src/queue/processors/RelationshipProcessorService.ts b/packages/backend/src/queue/processors/RelationshipProcessorService.ts index b2d8e3631f..408b02fb38 100644 --- a/packages/backend/src/queue/processors/RelationshipProcessorService.ts +++ b/packages/backend/src/queue/processors/RelationshipProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts b/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts index b3b055ef8c..570cdf9a75 100644 --- a/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts +++ b/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/TickChartsProcessorService.ts b/packages/backend/src/queue/processors/TickChartsProcessorService.ts index 7b1efb71e0..93ec34162d 100644 --- a/packages/backend/src/queue/processors/TickChartsProcessorService.ts +++ b/packages/backend/src/queue/processors/TickChartsProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts b/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts index 7a0d533846..8c260c0137 100644 --- a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts index 5a9952e807..ce57ba745e 100644 --- a/packages/backend/src/queue/types.ts +++ b/packages/backend/src/queue/types.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts index 4fa6b8afee..60366dd5c2 100644 --- a/packages/backend/src/server/ActivityPubServerService.ts +++ b/packages/backend/src/server/ActivityPubServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts index 7745a6cb78..f51d7aebca 100644 --- a/packages/backend/src/server/FileServerService.ts +++ b/packages/backend/src/server/FileServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -27,6 +27,7 @@ import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; import { isMimeImage } from '@/misc/is-mime-image.js'; import { correctFilename } from '@/misc/correct-filename.js'; +import { handleRequestRedirectToOmitSearch } from '@/misc/fastify-hook-handlers.js'; import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify'; const _filename = fileURLToPath(import.meta.url); @@ -67,20 +68,23 @@ export class FileServerService { done(); }); - fastify.get('/files/app-default.jpg', (request, reply) => { - const file = fs.createReadStream(`${_dirname}/assets/dummy.png`); - reply.header('Content-Type', 'image/jpeg'); - reply.header('Cache-Control', 'max-age=31536000, immutable'); - return reply.send(file); - }); + fastify.register((fastify, options, done) => { + fastify.addHook('onRequest', handleRequestRedirectToOmitSearch); + fastify.get('/files/app-default.jpg', (request, reply) => { + const file = fs.createReadStream(`${_dirname}/assets/dummy.png`); + reply.header('Content-Type', 'image/jpeg'); + reply.header('Cache-Control', 'max-age=31536000, immutable'); + return reply.send(file); + }); - fastify.get<{ Params: { key: string; } }>('/files/:key', async (request, reply) => { - return await this.sendDriveFile(request, reply) - .catch(err => this.errorHandler(request, reply, err)); - }); - fastify.get<{ Params: { key: string; } }>('/files/:key/*', async (request, reply) => { - return await this.sendDriveFile(request, reply) - .catch(err => this.errorHandler(request, reply, err)); + fastify.get<{ Params: { key: string; } }>('/files/:key', async (request, reply) => { + return await this.sendDriveFile(request, reply) + .catch(err => this.errorHandler(request, reply, err)); + }); + fastify.get<{ Params: { key: string; } }>('/files/:key/*', async (request, reply) => { + return await reply.redirect(301, `${this.config.url}/files/${request.params.key}`); + }); + done(); }); fastify.get<{ diff --git a/packages/backend/src/server/NodeinfoServerService.ts b/packages/backend/src/server/NodeinfoServerService.ts index 4d94fcdd54..c1e5af08c9 100644 --- a/packages/backend/src/server/NodeinfoServerService.ts +++ b/packages/backend/src/server/NodeinfoServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -117,6 +117,8 @@ export class NodeinfoServerService { emailRequiredForSignup: meta.emailRequiredForSignup, enableHcaptcha: meta.enableHcaptcha, enableRecaptcha: meta.enableRecaptcha, + enableMcaptcha: meta.enableMcaptcha, + enableTurnstile: meta.enableTurnstile, maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, enableEmail: meta.enableEmail, enableServiceWorker: meta.enableServiceWorker, diff --git a/packages/backend/src/server/ServerModule.ts b/packages/backend/src/server/ServerModule.ts index aed352d15e..f43968d236 100644 --- a/packages/backend/src/server/ServerModule.ts +++ b/packages/backend/src/server/ServerModule.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts index 632a7692cd..671dd31eb1 100644 --- a/packages/backend/src/server/ServerService.ts +++ b/packages/backend/src/server/ServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -204,7 +204,7 @@ export class ServerService implements OnApplicationShutdown { }); this.globalEventService.publishMainStream(profile.userId, 'meUpdated', await this.userEntityService.pack(profile.userId, { id: profile.userId }, { - detail: true, + schema: 'MeDetailed', includeSecrets: true, })); diff --git a/packages/backend/src/server/WellKnownServerService.ts b/packages/backend/src/server/WellKnownServerService.ts index c3eaf53a14..8e326da89a 100644 --- a/packages/backend/src/server/WellKnownServerService.ts +++ b/packages/backend/src/server/WellKnownServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts index 56f804dee8..9836689872 100644 --- a/packages/backend/src/server/api/ApiCallService.ts +++ b/packages/backend/src/server/api/ApiCallService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/ApiLoggerService.ts b/packages/backend/src/server/api/ApiLoggerService.ts index 2339366a5d..72b71c0b5c 100644 --- a/packages/backend/src/server/api/ApiLoggerService.ts +++ b/packages/backend/src/server/api/ApiLoggerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts index 1758c03aca..e99244cdd0 100644 --- a/packages/backend/src/server/api/ApiServerService.ts +++ b/packages/backend/src/server/api/ApiServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -157,7 +157,7 @@ export class ApiServerService { return { ok: true, token: token.token, - user: await this.userEntityService.pack(token.userId, null, { detail: true }), + user: await this.userEntityService.pack(token.userId, null, { schema: 'UserDetailedNotMe' }), }; } else { return { diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts index f075688194..ddef8db987 100644 --- a/packages/backend/src/server/api/AuthenticateService.ts +++ b/packages/backend/src/server/api/AuthenticateService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index e74441834e..88d3999eb0 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -293,6 +293,7 @@ import * as ep___notes_translate from './endpoints/notes/translate.js'; import * as ep___notes_unrenote from './endpoints/notes/unrenote.js'; import * as ep___notes_userListTimeline from './endpoints/notes/user-list-timeline.js'; import * as ep___notifications_create from './endpoints/notifications/create.js'; +import * as ep___notifications_flush from './endpoints/notifications/flush.js'; import * as ep___notifications_markAllAsRead from './endpoints/notifications/mark-all-as-read.js'; import * as ep___notifications_testNotification from './endpoints/notifications/test-notification.js'; import * as ep___pagePush from './endpoints/page-push.js'; @@ -664,6 +665,7 @@ const $notes_translate: Provider = { provide: 'ep:notes/translate', useClass: ep const $notes_unrenote: Provider = { provide: 'ep:notes/unrenote', useClass: ep___notes_unrenote.default }; const $notes_userListTimeline: Provider = { provide: 'ep:notes/user-list-timeline', useClass: ep___notes_userListTimeline.default }; const $notifications_create: Provider = { provide: 'ep:notifications/create', useClass: ep___notifications_create.default }; +const $notifications_flush: Provider = { provide: 'ep:notifications/flush', useClass: ep___notifications_flush.default }; const $notifications_markAllAsRead: Provider = { provide: 'ep:notifications/mark-all-as-read', useClass: ep___notifications_markAllAsRead.default }; const $notifications_testNotification: Provider = { provide: 'ep:notifications/test-notification', useClass: ep___notifications_testNotification.default }; const $pagePush: Provider = { provide: 'ep:page-push', useClass: ep___pagePush.default }; @@ -1039,6 +1041,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $notes_unrenote, $notes_userListTimeline, $notifications_create, + $notifications_flush, $notifications_markAllAsRead, $notifications_testNotification, $pagePush, @@ -1408,7 +1411,9 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $notes_unrenote, $notes_userListTimeline, $notifications_create, + $notifications_flush, $notifications_markAllAsRead, + $notifications_testNotification, $pagePush, $pages_create, $pages_delete, diff --git a/packages/backend/src/server/api/GetterService.ts b/packages/backend/src/server/api/GetterService.ts index e2b98c34e7..bff3ab96f3 100644 --- a/packages/backend/src/server/api/GetterService.ts +++ b/packages/backend/src/server/api/GetterService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index 0e644aa091..0439cdfe5e 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/SigninApiService.ts b/packages/backend/src/server/api/SigninApiService.ts index f3115690fe..edac9b3beb 100644 --- a/packages/backend/src/server/api/SigninApiService.ts +++ b/packages/backend/src/server/api/SigninApiService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -22,7 +22,7 @@ import { WebAuthnService } from '@/core/WebAuthnService.js'; import { UserAuthService } from '@/core/UserAuthService.js'; import { RateLimiterService } from './RateLimiterService.js'; import { SigninService } from './SigninService.js'; -import type { AuthenticationResponseJSON } from '@simplewebauthn/typescript-types'; +import type { AuthenticationResponseJSON } from '@simplewebauthn/types'; import type { FastifyReply, FastifyRequest } from 'fastify'; @Injectable() diff --git a/packages/backend/src/server/api/SigninService.ts b/packages/backend/src/server/api/SigninService.ts index 98e9027006..714e56e8c3 100644 --- a/packages/backend/src/server/api/SigninService.ts +++ b/packages/backend/src/server/api/SigninService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/SignupApiService.ts b/packages/backend/src/server/api/SignupApiService.ts index 6b4d9d9f70..546de48e6b 100644 --- a/packages/backend/src/server/api/SignupApiService.ts +++ b/packages/backend/src/server/api/SignupApiService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -163,12 +163,12 @@ export class SignupApiService { } if (instance.emailRequiredForSignup) { - if (await this.usersRepository.exist({ where: { usernameLower: username.toLowerCase(), host: IsNull() } })) { + if (await this.usersRepository.exists({ where: { usernameLower: username.toLowerCase(), host: IsNull() } })) { throw new FastifyReplyError(400, 'DUPLICATED_USERNAME'); } // Check deleted username duplication - if (await this.usedUsernamesRepository.exist({ where: { username: username.toLowerCase() } })) { + if (await this.usedUsernamesRepository.exists({ where: { username: username.toLowerCase() } })) { throw new FastifyReplyError(400, 'USED_USERNAME'); } @@ -213,7 +213,7 @@ export class SignupApiService { }); const res = await this.userEntityService.pack(account, account, { - detail: true, + schema: 'MeDetailed', includeSecrets: true, }); diff --git a/packages/backend/src/server/api/StreamingApiServerService.ts b/packages/backend/src/server/api/StreamingApiServerService.ts index 3b387d92ca..b8f448477b 100644 --- a/packages/backend/src/server/api/StreamingApiServerService.ts +++ b/packages/backend/src/server/api/StreamingApiServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoint-base.ts b/packages/backend/src/server/api/endpoint-base.ts index d5279faa1c..e061aa3a8e 100644 --- a/packages/backend/src/server/api/endpoint-base.ts +++ b/packages/backend/src/server/api/endpoint-base.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 4a88216d06..f7e64a7356 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -1,11 +1,10 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ import { permissions } from 'misskey-js'; -import type { Schema } from '@/misc/json-schema.js'; -import { RolePolicies } from '@/core/RoleService.js'; +import type { KeyOf, Schema } from '@/misc/json-schema.js'; import * as ep___admin_meta from './endpoints/admin/meta.js'; import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js'; @@ -294,6 +293,7 @@ import * as ep___notes_translate from './endpoints/notes/translate.js'; import * as ep___notes_unrenote from './endpoints/notes/unrenote.js'; import * as ep___notes_userListTimeline from './endpoints/notes/user-list-timeline.js'; import * as ep___notifications_create from './endpoints/notifications/create.js'; +import * as ep___notifications_flush from './endpoints/notifications/flush.js'; import * as ep___notifications_markAllAsRead from './endpoints/notifications/mark-all-as-read.js'; import * as ep___notifications_testNotification from './endpoints/notifications/test-notification.js'; import * as ep___pagePush from './endpoints/page-push.js'; @@ -663,6 +663,7 @@ const eps = [ ['notes/unrenote', ep___notes_unrenote], ['notes/user-list-timeline', ep___notes_userListTimeline], ['notifications/create', ep___notifications_create], + ['notifications/flush', ep___notifications_flush], ['notifications/mark-all-as-read', ep___notifications_markAllAsRead], ['notifications/test-notification', ep___notifications_testNotification], ['page-push', ep___pagePush], @@ -776,7 +777,7 @@ interface IEndpointMetaBase { */ readonly requireAdmin?: boolean; - readonly requireRolePolicy?: keyof RolePolicies; + readonly requireRolePolicy?: KeyOf<'RolePolicies'>; /** * 引っ越し済みのユーザーによるリクエストを禁止するか diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts index 3484d6707a..cf3f257ca6 100644 --- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts +++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -62,17 +62,17 @@ export const meta = { reporter: { type: 'object', nullable: false, optional: false, - ref: 'User', + ref: 'UserDetailedNotMe', }, targetUser: { type: 'object', nullable: false, optional: false, - ref: 'User', + ref: 'UserDetailedNotMe', }, assignee: { type: 'object', nullable: true, optional: true, - ref: 'User', + ref: 'UserDetailedNotMe', }, }, }, diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts index f54d567fff..a7e8a3b018 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -9,8 +9,10 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import type { UsersRepository } from '@/models/_.js'; import { SignupService } from '@/core/SignupService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { InstanceActorService } from '@/core/InstanceActorService.js'; import { localUsernameSchema, passwordSchema } from '@/models/User.js'; import { DI } from '@/di-symbols.js'; +import { Packed } from '@/misc/json-schema.js'; export const meta = { tags: ['admin'], @@ -18,7 +20,7 @@ export const meta = { res: { type: 'object', optional: false, nullable: false, - ref: 'User', + ref: 'MeDetailed', properties: { token: { type: 'string', @@ -45,13 +47,12 @@ export default class extends Endpoint { // eslint- private userEntityService: UserEntityService, private signupService: SignupService, + private instanceActorService: InstanceActorService, ) { super(meta, paramDef, async (ps, _me, token) => { const me = _me ? await this.usersRepository.findOneByOrFail({ id: _me.id }) : null; - const noUsers = (await this.usersRepository.countBy({ - host: IsNull(), - })) === 0; - if ((!noUsers && !me?.isRoot) || token !== null) throw new Error('access denied'); + const realUsers = await this.instanceActorService.realLocalUsersPresent(); + if ((realUsers && !me?.isRoot) || token !== null) throw new Error('access denied'); const { account, secret } = await this.signupService.signup({ username: ps.username, @@ -60,11 +61,11 @@ export default class extends Endpoint { // eslint- }); const res = await this.userEntityService.pack(account, account, { - detail: true, + schema: 'MeDetailed', includeSecrets: true, - }); + }) as Packed<'MeDetailed'> & { token: string }; - (res as any).token = secret; + res.token = secret; return res; }); diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts index 52d8c8ce18..4074e416b8 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts b/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts index 93673453d6..12cd5cf295 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -27,7 +27,7 @@ export const meta = { res: { type: 'object', optional: false, nullable: false, - ref: 'User', + ref: 'UserDetailedNotMe', }, } as const; @@ -58,7 +58,7 @@ export default class extends Endpoint { // eslint- } const res = await this.userEntityService.pack(profile.user!, null, { - detail: true, + schema: 'UserDetailedNotMe', }); return res; diff --git a/packages/backend/src/server/api/endpoints/admin/ad/create.ts b/packages/backend/src/server/api/endpoints/admin/ad/create.ts index 041b10f9f7..1e7a9fb3ec 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts index 5b18b347d3..501e13c6a7 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/ad/list.ts b/packages/backend/src/server/api/endpoints/admin/ad/list.ts index 586c1f44db..6406709cda 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts index bf96e44b0c..62358457ff 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts index c9df70c76b..2dae1df87d 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts index 939333345e..6d1e1b0a10 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts index 429b138599..87eaad31a3 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts index db6db8356d..6fce6e4e0a 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts index 4ac74253cc..fd21309818 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts index 88977f801a..3a5673d99d 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts index 33122c3eef..aee90023e1 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts index 6211345f96..34b3b5a11f 100644 --- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/delete-account.ts b/packages/backend/src/server/api/endpoints/admin/delete-account.ts index 2c82c2879d..b6f0f22d60 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-account.ts +++ b/packages/backend/src/server/api/endpoints/admin/delete-account.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -15,9 +15,6 @@ export const meta = { requireCredential: true, requireAdmin: true, kind: 'write:admin:delete-account', - - res: { - }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts index 7d33065f2e..d8341b3ad7 100644 --- a/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/delete-all-files-of-a-user.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts b/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts index af2bb6b1ca..d420a929bd 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/clean-remote-files.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts index a3b221284b..d612572e2e 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/cleanup.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/drive/files.ts b/packages/backend/src/server/api/endpoints/admin/drive/files.ts index 37fa439bcf..915d777e77 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/files.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/files.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts index 3aeb3e45e3..459d8880fa 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -84,6 +84,24 @@ export const meta = { properties: { type: 'object', optional: false, nullable: false, + properties: { + width: { + type: 'number', + optional: true, nullable: false, + }, + height: { + type: 'number', + optional: true, nullable: false, + }, + orientation: { + type: 'number', + optional: true, nullable: false, + }, + avgColor: { + type: 'string', + optional: true, nullable: false, + }, + }, }, storedInternal: { type: 'boolean', diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts index 1cd8125c52..a30a080e59 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add-aliases-bulk.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts index 4a9418d051..796f273330 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -31,7 +31,10 @@ export const meta = { }, }, - ref: 'EmojiDetailed', + res: { + type: 'object', + ref: 'EmojiDetailed', + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts index 476780b23f..975f892df9 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/copy.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts index 450695984a..cec9f700c3 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete-bulk.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts index e1e6e7c2c4..50c45b6ac5 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts b/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts index 208616c0ac..8e5f69c894 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/import-zip.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts index f3e0c1ef1f..0889ceb76f 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts index 59e87253f6..ffb5dbf4b5 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts index 26dd43e926..0fa119eabe 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/remove-aliases-bulk.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts index 18961976f9..d9ee18699c 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-aliases-bulk.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts index c680f2e2d4..dc25df2767 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-category-bulk.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts b/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts index 47c692b613..4ba99faab7 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/set-license-bulk.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts index 550bb0052b..22609a16a3 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -57,7 +57,10 @@ export const paramDef = { type: 'string', } }, }, - required: ['id', 'name', 'aliases'], + anyOf: [ + { required: ['id'] }, + { required: ['name'] }, + ], } as const; @Injectable() @@ -70,27 +73,33 @@ export default class extends Endpoint { // eslint- ) { super(meta, paramDef, async (ps, me) => { let driveFile; - if (ps.fileId) { driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); if (driveFile == null) throw new ApiError(meta.errors.noSuchFile); } - const emoji = await this.customEmojiService.getEmojiById(ps.id); - if (emoji != null) { - if (ps.name !== emoji.name) { + + let emojiId; + if (ps.id) { + emojiId = ps.id; + const emoji = await this.customEmojiService.getEmojiById(ps.id); + if (!emoji) throw new ApiError(meta.errors.noSuchEmoji); + if (ps.name && (ps.name !== emoji.name)) { const isDuplicate = await this.customEmojiService.checkDuplicate(ps.name); if (isDuplicate) throw new ApiError(meta.errors.sameNameEmojiExists); } } else { - throw new ApiError(meta.errors.noSuchEmoji); + if (!ps.name) throw new Error('Invalid Params unexpectedly passed. This is a BUG. Please report it to the development team.'); + const emoji = await this.customEmojiService.getEmojiByName(ps.name); + if (!emoji) throw new ApiError(meta.errors.noSuchEmoji); + emojiId = emoji.id; } - await this.customEmojiService.update(ps.id, { + await this.customEmojiService.update(emojiId, { driveFile, name: ps.name, - category: ps.category ?? null, + category: ps.category, aliases: ps.aliases, - license: ps.license ?? null, + license: ps.license, isSensitive: ps.isSensitive, localOnly: ps.localOnly, roleIdsThatCanBeUsedThisEmojiAsReaction: ps.roleIdsThatCanBeUsedThisEmojiAsReaction, diff --git a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts index 57612850b4..4a54c26009 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/delete-all-files.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts index 0d061c685f..556e291025 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts index c15fb83454..9e93310746 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/remove-all-following.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts index f429949e16..0bcdc2a4b8 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/update-instance.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -24,8 +24,9 @@ export const paramDef = { properties: { host: { type: 'string' }, isSuspended: { type: 'boolean' }, + moderationNote: { type: 'string' }, }, - required: ['host', 'isSuspended'], + required: ['host'], } as const; @Injectable() @@ -47,9 +48,10 @@ export default class extends Endpoint { // eslint- await this.federatedInstanceService.update(instance.id, { isSuspended: ps.isSuspended, + moderationNote: ps.moderationNote, }); - if (instance.isSuspended !== ps.isSuspended) { + if (ps.isSuspended != null && instance.isSuspended !== ps.isSuspended) { if (ps.isSuspended) { this.moderationLogService.log(me, 'suspendRemoteInstance', { id: instance.id, @@ -62,6 +64,15 @@ export default class extends Endpoint { // eslint- }); } } + + if (ps.moderationNote != null && instance.moderationNote !== ps.moderationNote) { + this.moderationLogService.log(me, 'updateRemoteInstanceNote', { + id: instance.id, + host: instance.host, + before: instance.moderationNote, + after: ps.moderationNote, + }); + } }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts index 0b50212119..90a3fa0200 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-index-stats.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts index 0d44b288cb..eb85fca179 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-table-stats.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -18,6 +18,18 @@ export const meta = { res: { type: 'object', optional: false, nullable: false, + additionalProperties: { + type: 'object', + properties: { + count: { + type: 'number', + }, + size: { + type: 'number', + }, + }, + required: ['count', 'size'], + }, example: { migrations: { count: 66, diff --git a/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts b/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts index 1b437f718b..b7781b8c99 100644 --- a/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts +++ b/packages/backend/src/server/api/endpoints/admin/get-user-ips.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/invite/create.ts b/packages/backend/src/server/api/endpoints/admin/invite/create.ts index 396b84623f..0f551e1ba2 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/invite/list.ts b/packages/backend/src/server/api/endpoints/admin/invite/list.ts index d293dcadc6..e33a9a1aec 100644 --- a/packages/backend/src/server/api/endpoints/admin/invite/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/invite/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 0627c5055c..88c5907bcc 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -156,6 +156,13 @@ export const meta = { type: 'string', }, }, + prohibitedWords: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'string', + }, + }, bannedEmailDomains: { type: 'array', optional: true, nullable: false, @@ -422,7 +429,7 @@ export const meta = { }, repositoryUrl: { type: 'string', - optional: false, nullable: false, + optional: false, nullable: true, }, summalyProxy: { type: 'string', @@ -515,6 +522,7 @@ export default class extends Endpoint { // eslint- blockedHosts: instance.blockedHosts, silencedHosts: instance.silencedHosts, sensitiveWords: instance.sensitiveWords, + prohibitedWords: instance.prohibitedWords, preservedUsernames: instance.preservedUsernames, hcaptchaSecretKey: instance.hcaptchaSecretKey, mcaptchaSecretKey: instance.mcaptchaSecretKey, diff --git a/packages/backend/src/server/api/endpoints/admin/promo/create.ts b/packages/backend/src/server/api/endpoints/admin/promo/create.ts index ab69dfba96..1d32c6cc00 100644 --- a/packages/backend/src/server/api/endpoints/admin/promo/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/promo/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -55,7 +55,7 @@ export default class extends Endpoint { // eslint- throw e; }); - const exist = await this.promoNotesRepository.exist({ where: { noteId: note.id } }); + const exist = await this.promoNotesRepository.exists({ where: { noteId: note.id } }); if (exist) { throw new ApiError(meta.errors.alreadyPromoted); diff --git a/packages/backend/src/server/api/endpoints/admin/queue/clear.ts b/packages/backend/src/server/api/endpoints/admin/queue/clear.ts index 9912043c8b..3f7df0e63d 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/clear.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/clear.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts index 8473909103..7a3410ffa7 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts index 19f7cb85c0..305ae1af1d 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/queue/promote.ts b/packages/backend/src/server/api/endpoints/admin/queue/promote.ts index d06780e044..7502d4e1f7 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/promote.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/promote.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts index 189690b703..9694b3fa40 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/relays/add.ts b/packages/backend/src/server/api/endpoints/admin/relays/add.ts index d55dff7b0c..3d7bc4567e 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/add.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/relays/list.ts b/packages/backend/src/server/api/endpoints/admin/relays/list.ts index 61ea287bff..587d5c3b03 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/relays/remove.ts b/packages/backend/src/server/api/endpoints/admin/relays/remove.ts index 8a6dd4e152..1f6e773cd4 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/remove.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/remove.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index 1a402b4a4a..53db096c1d 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts index 26c4038b98..8b0456068b 100644 --- a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts +++ b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/roles/assign.ts b/packages/backend/src/server/api/endpoints/admin/roles/assign.ts index 8eb3d2bf59..b6c7953781 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/assign.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/assign.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/roles/create.ts b/packages/backend/src/server/api/endpoints/admin/roles/create.ts index de23d2fb11..e0c02f7a5d 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/roles/delete.ts b/packages/backend/src/server/api/endpoints/admin/roles/delete.ts index 9e2968e317..638e2b15b9 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/roles/list.ts b/packages/backend/src/server/api/endpoints/admin/roles/list.ts index d3d1a10a69..333fac6aa6 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/roles/show.ts b/packages/backend/src/server/api/endpoints/admin/roles/show.ts index ad4345e5a5..13e5cbb995 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/show.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts b/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts index c11265252c..e7da3384b1 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts b/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts index 203f749a6e..d7209965db 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update.ts b/packages/backend/src/server/api/endpoints/admin/roles/update.ts index 74d5aae5d8..5242e0be2f 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/roles/users.ts b/packages/backend/src/server/api/endpoints/admin/roles/users.ts index 66f4d9d26b..45758d4f50 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/users.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -17,7 +17,7 @@ export const meta = { tags: ['admin', 'role', 'users'], requireCredential: false, - requireAdmin: true, + requireModerator: true, kind: 'read:admin:roles', errors: { @@ -40,7 +40,7 @@ export const meta = { }, required: ['id', 'createdAt', 'user'], }, - } + }, } as const; export const paramDef = { @@ -92,7 +92,7 @@ export default class extends Endpoint { // eslint- return await Promise.all(assigns.map(async assign => ({ id: assign.id, createdAt: this.idService.parse(assign.id).date.toISOString(), - user: await this.userEntityService.pack(assign.user!, me, { detail: true }), + user: await this.userEntityService.pack(assign.user!, me, { schema: 'UserDetailed' }), expiresAt: assign.expiresAt?.toISOString() ?? null, }))); }); diff --git a/packages/backend/src/server/api/endpoints/admin/send-email.ts b/packages/backend/src/server/api/endpoints/admin/send-email.ts index d20aee656c..f01a7778a8 100644 --- a/packages/backend/src/server/api/endpoints/admin/send-email.ts +++ b/packages/backend/src/server/api/endpoints/admin/send-email.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/server-info.ts b/packages/backend/src/server/api/endpoints/admin/server-info.ts index 374712f57d..80b6a4d32e 100644 --- a/packages/backend/src/server/api/endpoints/admin/server-info.ts +++ b/packages/backend/src/server/api/endpoints/admin/server-info.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts index f3601be9bb..58c5f1f60a 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -50,7 +50,7 @@ export const meta = { user: { type: 'object', optional: false, nullable: false, - ref: 'UserDetailed', + ref: 'UserDetailedNotMe', }, }, }, diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 2b50354cef..5a1c05f41a 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -10,6 +10,7 @@ import { DI } from '@/di-symbols.js'; import { RoleService } from '@/core/RoleService.js'; import { RoleEntityService } from '@/core/entities/RoleEntityService.js'; import { IdService } from '@/core/IdService.js'; +import { notificationRecieveConfig } from '@/models/json-schema/user.js'; export const meta = { tags: ['admin'], @@ -21,6 +22,157 @@ export const meta = { res: { type: 'object', nullable: false, optional: false, + properties: { + email: { + type: 'string', + optional: false, nullable: true, + }, + emailVerified: { + type: 'boolean', + optional: false, nullable: false, + }, + autoAcceptFollowed: { + type: 'boolean', + optional: false, nullable: false, + }, + noCrawle: { + type: 'boolean', + optional: false, nullable: false, + }, + preventAiLearning: { + type: 'boolean', + optional: false, nullable: false, + }, + alwaysMarkNsfw: { + type: 'boolean', + optional: false, nullable: false, + }, + autoSensitive: { + type: 'boolean', + optional: false, nullable: false, + }, + carefulBot: { + type: 'boolean', + optional: false, nullable: false, + }, + injectFeaturedNote: { + type: 'boolean', + optional: false, nullable: false, + }, + receiveAnnouncementEmail: { + type: 'boolean', + optional: false, nullable: false, + }, + mutedWords: { + type: 'array', + optional: false, nullable: false, + items: { + anyOf: [ + { + type: 'string', + }, + { + type: 'array', + items: { + type: 'string', + }, + }, + ], + }, + }, + mutedInstances: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'string', + }, + }, + notificationRecieveConfig: { + type: 'object', + optional: false, nullable: false, + properties: { + note: { optional: true, ...notificationRecieveConfig }, + follow: { optional: true, ...notificationRecieveConfig }, + mention: { optional: true, ...notificationRecieveConfig }, + reply: { optional: true, ...notificationRecieveConfig }, + renote: { optional: true, ...notificationRecieveConfig }, + quote: { optional: true, ...notificationRecieveConfig }, + reaction: { optional: true, ...notificationRecieveConfig }, + pollEnded: { optional: true, ...notificationRecieveConfig }, + receiveFollowRequest: { optional: true, ...notificationRecieveConfig }, + followRequestAccepted: { optional: true, ...notificationRecieveConfig }, + roleAssigned: { optional: true, ...notificationRecieveConfig }, + achievementEarned: { optional: true, ...notificationRecieveConfig }, + app: { optional: true, ...notificationRecieveConfig }, + test: { optional: true, ...notificationRecieveConfig }, + }, + }, + isModerator: { + type: 'boolean', + optional: false, nullable: false, + }, + isSilenced: { + type: 'boolean', + optional: false, nullable: false, + }, + isSuspended: { + type: 'boolean', + optional: false, nullable: false, + }, + isHibernated: { + type: 'boolean', + optional: false, nullable: false, + }, + lastActiveDate: { + type: 'string', + optional: false, nullable: true, + }, + moderationNote: { + type: 'string', + optional: false, nullable: false, + }, + signins: { + type: 'array', + optional: false, nullable: false, + items: { + ref: 'Signin', + }, + }, + policies: { + type: 'object', + optional: false, nullable: false, + ref: 'RolePolicies', + }, + roles: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + ref: 'Role', + }, + }, + roleAssigns: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + properties: { + createdAt: { + type: 'string', + optional: false, nullable: false, + }, + expiresAt: { + type: 'string', + optional: false, nullable: true, + }, + roleId: { + type: 'string', + optional: false, nullable: false, + }, + }, + }, + }, + }, }, } as const; @@ -89,7 +241,7 @@ export default class extends Endpoint { // eslint- isSilenced: isSilenced, isSuspended: user.isSuspended, isHibernated: user.isHibernated, - lastActiveDate: user.lastActiveDate, + lastActiveDate: user.lastActiveDate ? user.lastActiveDate.toISOString() : null, moderationNote: profile.moderationNote ?? '', signins, policies: await this.roleService.getUserPolicies(user.id), diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts index 1d31e5e80f..424212ba24 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-users.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -114,7 +114,7 @@ export default class extends Endpoint { // eslint- const users = await query.getMany(); - return await this.userEntityService.packMany(users, me, { detail: true }); + return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' }); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts index a26fa81c13..8a946405cc 100644 --- a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts b/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts index 8b22fad1d4..ddab6f3a9d 100644 --- a/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-user-avatar.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts b/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts index 5ec359c0ef..e16dad719c 100644 --- a/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts +++ b/packages/backend/src/server/api/endpoints/admin/unset-user-banner.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts index 9c896f0e64..2c2b1bf6f5 100644 --- a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index d76d3dfeea..bffceef815 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -41,6 +41,11 @@ export const paramDef = { type: 'string', }, }, + prohibitedWords: { + type: 'array', nullable: true, items: { + type: 'string', + }, + }, themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' }, mascotImageUrl: { type: 'string', nullable: true }, bannerUrl: { type: 'string', nullable: true }, @@ -99,8 +104,8 @@ export const paramDef = { swPublicKey: { type: 'string', nullable: true }, swPrivateKey: { type: 'string', nullable: true }, tosUrl: { type: 'string', nullable: true }, - repositoryUrl: { type: 'string' }, - feedbackUrl: { type: 'string' }, + repositoryUrl: { type: 'string', nullable: true }, + feedbackUrl: { type: 'string', nullable: true }, impressumUrl: { type: 'string', nullable: true }, privacyPolicyUrl: { type: 'string', nullable: true }, useObjectStorage: { type: 'boolean' }, @@ -177,6 +182,9 @@ export default class extends Endpoint { // eslint- if (Array.isArray(ps.sensitiveWords)) { set.sensitiveWords = ps.sensitiveWords.filter(Boolean); } + if (Array.isArray(ps.prohibitedWords)) { + set.prohibitedWords = ps.prohibitedWords.filter(Boolean); + } if (Array.isArray(ps.silencedHosts)) { let lastValue = ''; set.silencedHosts = ps.silencedHosts.sort().filter((h) => { @@ -394,7 +402,7 @@ export default class extends Endpoint { // eslint- } if (ps.repositoryUrl !== undefined) { - set.repositoryUrl = ps.repositoryUrl; + set.repositoryUrl = URL.canParse(ps.repositoryUrl!) ? ps.repositoryUrl : null; } if (ps.feedbackUrl !== undefined) { diff --git a/packages/backend/src/server/api/endpoints/admin/update-user-note.ts b/packages/backend/src/server/api/endpoints/admin/update-user-note.ts index e582147e72..e9930422c0 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-user-note.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-user-note.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/announcements.ts b/packages/backend/src/server/api/endpoints/announcements.ts index 7c242dbcd5..3b12f5b62c 100644 --- a/packages/backend/src/server/api/endpoints/announcements.ts +++ b/packages/backend/src/server/api/endpoints/announcements.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts index b029493d3a..191de8f833 100644 --- a/packages/backend/src/server/api/endpoints/antennas/create.ts +++ b/packages/backend/src/server/api/endpoints/antennas/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/antennas/delete.ts b/packages/backend/src/server/api/endpoints/antennas/delete.ts index e6240aec65..2258954b56 100644 --- a/packages/backend/src/server/api/endpoints/antennas/delete.ts +++ b/packages/backend/src/server/api/endpoints/antennas/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/antennas/list.ts b/packages/backend/src/server/api/endpoints/antennas/list.ts index 3a9f969d24..83d29f9c8c 100644 --- a/packages/backend/src/server/api/endpoints/antennas/list.ts +++ b/packages/backend/src/server/api/endpoints/antennas/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 7293c2e39b..f4dfe1ecc4 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -124,9 +124,7 @@ export default class extends Endpoint { // eslint- notes.sort((a, b) => a.id > b.id ? -1 : 1); } - if (notes.length > 0) { - this.noteReadService.read(me.id, notes); - } + this.noteReadService.read(me.id, notes); return await this.noteEntityService.packMany(notes, me); }); diff --git a/packages/backend/src/server/api/endpoints/antennas/show.ts b/packages/backend/src/server/api/endpoints/antennas/show.ts index 77c9b31763..a40f187d0b 100644 --- a/packages/backend/src/server/api/endpoints/antennas/show.ts +++ b/packages/backend/src/server/api/endpoints/antennas/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/antennas/update.ts b/packages/backend/src/server/api/endpoints/antennas/update.ts index 3457bb6f66..459729f61f 100644 --- a/packages/backend/src/server/api/endpoints/antennas/update.ts +++ b/packages/backend/src/server/api/endpoints/antennas/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/ap/get.ts b/packages/backend/src/server/api/endpoints/ap/get.ts index e0ef5d413a..d8c55de7ec 100644 --- a/packages/backend/src/server/api/endpoints/ap/get.ts +++ b/packages/backend/src/server/api/endpoints/ap/get.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index 7e5c7a917c..d3c40dba59 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -148,7 +148,7 @@ export default class extends Endpoint { // eslint- if (user != null) { return { type: 'User', - object: await this.userEntityService.pack(user, me, { detail: true }), + object: await this.userEntityService.pack(user, me, { schema: 'UserDetailedNotMe' }), }; } else if (note != null) { try { diff --git a/packages/backend/src/server/api/endpoints/app/create.ts b/packages/backend/src/server/api/endpoints/app/create.ts index f89d9823ba..492705d6f9 100644 --- a/packages/backend/src/server/api/endpoints/app/create.ts +++ b/packages/backend/src/server/api/endpoints/app/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/app/show.ts b/packages/backend/src/server/api/endpoints/app/show.ts index cb968a1c65..3db9a0d0d4 100644 --- a/packages/backend/src/server/api/endpoints/app/show.ts +++ b/packages/backend/src/server/api/endpoints/app/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/auth/accept.ts b/packages/backend/src/server/api/endpoints/auth/accept.ts index e0baeb3565..2e62f04df0 100644 --- a/packages/backend/src/server/api/endpoints/auth/accept.ts +++ b/packages/backend/src/server/api/endpoints/auth/accept.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -62,7 +62,7 @@ export default class extends Endpoint { // eslint- const accessToken = secureRndstr(32); // Fetch exist access token - const exist = await this.accessTokensRepository.exist({ + const exist = await this.accessTokensRepository.exists({ where: { appId: session.appId, userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/auth/session/generate.ts b/packages/backend/src/server/api/endpoints/auth/session/generate.ts index 6e474c59e0..26dd893138 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/generate.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/generate.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/auth/session/show.ts b/packages/backend/src/server/api/endpoints/auth/session/show.ts index 0f5da0f252..13e02a2541 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/show.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/auth/session/userkey.ts b/packages/backend/src/server/api/endpoints/auth/session/userkey.ts index ffddda090b..b490c5832d 100644 --- a/packages/backend/src/server/api/endpoints/auth/session/userkey.ts +++ b/packages/backend/src/server/api/endpoints/auth/session/userkey.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -112,7 +112,7 @@ export default class extends Endpoint { // eslint- return { accessToken: accessToken.token, user: await this.userEntityService.pack(session.userId, null, { - detail: true, + schema: 'UserDetailedNotMe', }), }; }); diff --git a/packages/backend/src/server/api/endpoints/blocking/create.ts b/packages/backend/src/server/api/endpoints/blocking/create.ts index 3c7d7ac8cd..5066215749 100644 --- a/packages/backend/src/server/api/endpoints/blocking/create.ts +++ b/packages/backend/src/server/api/endpoints/blocking/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -88,7 +88,7 @@ export default class extends Endpoint { // eslint- }); // Check if already blocking - const exist = await this.blockingsRepository.exist({ + const exist = await this.blockingsRepository.exists({ where: { blockerId: blocker.id, blockeeId: blockee.id, @@ -102,7 +102,7 @@ export default class extends Endpoint { // eslint- await this.userBlockingService.block(blocker, blockee); return await this.userEntityService.pack(blockee.id, blocker, { - detail: true, + schema: 'UserDetailedNotMe', }); }); } diff --git a/packages/backend/src/server/api/endpoints/blocking/delete.ts b/packages/backend/src/server/api/endpoints/blocking/delete.ts index 0ce334d559..cebb307338 100644 --- a/packages/backend/src/server/api/endpoints/blocking/delete.ts +++ b/packages/backend/src/server/api/endpoints/blocking/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -88,7 +88,7 @@ export default class extends Endpoint { // eslint- }); // Check not blocking - const exist = await this.blockingsRepository.exist({ + const exist = await this.blockingsRepository.exists({ where: { blockerId: blocker.id, blockeeId: blockee.id, @@ -103,7 +103,7 @@ export default class extends Endpoint { // eslint- await this.userBlockingService.unblock(blocker, blockee); return await this.userEntityService.pack(blockee.id, blocker, { - detail: true, + schema: 'UserDetailedNotMe', }); }); } diff --git a/packages/backend/src/server/api/endpoints/blocking/list.ts b/packages/backend/src/server/api/endpoints/blocking/list.ts index 58d24540d1..8431fa6b34 100644 --- a/packages/backend/src/server/api/endpoints/blocking/list.ts +++ b/packages/backend/src/server/api/endpoints/blocking/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/bubble-game/ranking.ts b/packages/backend/src/server/api/endpoints/bubble-game/ranking.ts index 9c057760ca..ab877bbe20 100644 --- a/packages/backend/src/server/api/endpoints/bubble-game/ranking.ts +++ b/packages/backend/src/server/api/endpoints/bubble-game/ranking.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -24,9 +24,19 @@ export const meta = { type: 'object', optional: false, nullable: false, properties: { - id: { type: 'string', format: 'misskey:id' }, - score: { type: 'integer' }, - user: { ref: 'UserLite' }, + id: { + type: 'string', format: 'misskey:id', + optional: false, nullable: false, + }, + score: { + type: 'integer', + optional: false, nullable: false, + }, + user: { + type: 'object', + optional: true, nullable: false, + ref: 'UserLite', + }, }, }, }, @@ -61,7 +71,7 @@ export default class extends Endpoint { // eslint- relations: ['user'], }); - const users = await this.userEntityService.packMany(records.map(r => r.user!), null, { detail: false }); + const users = await this.userEntityService.packMany(records.map(r => r.user!), null); return records.map(r => ({ id: r.id, diff --git a/packages/backend/src/server/api/endpoints/bubble-game/register.ts b/packages/backend/src/server/api/endpoints/bubble-game/register.ts index 8eb90fdbf9..0a999e42cd 100644 --- a/packages/backend/src/server/api/endpoints/bubble-game/register.ts +++ b/packages/backend/src/server/api/endpoints/bubble-game/register.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -29,9 +29,6 @@ export const meta = { id: 'eb627bc7-574b-4a52-a860-3c3eae772b88', }, }, - - res: { - }, } as const; export const paramDef = { @@ -39,7 +36,15 @@ export const paramDef = { properties: { score: { type: 'integer', minimum: 0 }, seed: { type: 'string', minLength: 1, maxLength: 1024 }, - logs: { type: 'array' }, + logs: { + type: 'array', + items: { + type: 'array', + items: { + type: 'number', + }, + }, + }, gameMode: { type: 'string' }, gameVersion: { type: 'integer' }, }, diff --git a/packages/backend/src/server/api/endpoints/channels/create.ts b/packages/backend/src/server/api/endpoints/channels/create.ts index 3dd1eddd01..2866db5424 100644 --- a/packages/backend/src/server/api/endpoints/channels/create.ts +++ b/packages/backend/src/server/api/endpoints/channels/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/favorite.ts b/packages/backend/src/server/api/endpoints/channels/favorite.ts index c175718919..a1ae9b80a7 100644 --- a/packages/backend/src/server/api/endpoints/channels/favorite.ts +++ b/packages/backend/src/server/api/endpoints/channels/favorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/featured.ts b/packages/backend/src/server/api/endpoints/channels/featured.ts index 412ea1bb16..a9a79ba8fc 100644 --- a/packages/backend/src/server/api/endpoints/channels/featured.ts +++ b/packages/backend/src/server/api/endpoints/channels/featured.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/follow.ts b/packages/backend/src/server/api/endpoints/channels/follow.ts index bb5a477eb8..1812820ba2 100644 --- a/packages/backend/src/server/api/endpoints/channels/follow.ts +++ b/packages/backend/src/server/api/endpoints/channels/follow.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/followed.ts b/packages/backend/src/server/api/endpoints/channels/followed.ts index 6514f1ea3c..d2f36f251e 100644 --- a/packages/backend/src/server/api/endpoints/channels/followed.ts +++ b/packages/backend/src/server/api/endpoints/channels/followed.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/my-favorites.ts b/packages/backend/src/server/api/endpoints/channels/my-favorites.ts index 057a438ac9..d96e6c3ad2 100644 --- a/packages/backend/src/server/api/endpoints/channels/my-favorites.ts +++ b/packages/backend/src/server/api/endpoints/channels/my-favorites.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/owned.ts b/packages/backend/src/server/api/endpoints/channels/owned.ts index b1dd693537..daab685f1b 100644 --- a/packages/backend/src/server/api/endpoints/channels/owned.ts +++ b/packages/backend/src/server/api/endpoints/channels/owned.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/search.ts b/packages/backend/src/server/api/endpoints/channels/search.ts index 9c78a94844..ae32203603 100644 --- a/packages/backend/src/server/api/endpoints/channels/search.ts +++ b/packages/backend/src/server/api/endpoints/channels/search.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/show.ts b/packages/backend/src/server/api/endpoints/channels/show.ts index 3eaa83c7e8..332ce2c9dc 100644 --- a/packages/backend/src/server/api/endpoints/channels/show.ts +++ b/packages/backend/src/server/api/endpoints/channels/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts index 006228ceee..8c55673590 100644 --- a/packages/backend/src/server/api/endpoints/channels/timeline.ts +++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/unfavorite.ts b/packages/backend/src/server/api/endpoints/channels/unfavorite.ts index b4c7af8154..fc6b75e295 100644 --- a/packages/backend/src/server/api/endpoints/channels/unfavorite.ts +++ b/packages/backend/src/server/api/endpoints/channels/unfavorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/unfollow.ts b/packages/backend/src/server/api/endpoints/channels/unfollow.ts index c95332c7f8..48c5261135 100644 --- a/packages/backend/src/server/api/endpoints/channels/unfollow.ts +++ b/packages/backend/src/server/api/endpoints/channels/unfollow.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/channels/update.ts b/packages/backend/src/server/api/endpoints/channels/update.ts index 93d02e4a12..dba2938b39 100644 --- a/packages/backend/src/server/api/endpoints/channels/update.ts +++ b/packages/backend/src/server/api/endpoints/channels/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/active-users.ts b/packages/backend/src/server/api/endpoints/charts/active-users.ts index e768923ce1..fd21e3d9fe 100644 --- a/packages/backend/src/server/api/endpoints/charts/active-users.ts +++ b/packages/backend/src/server/api/endpoints/charts/active-users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/ap-request.ts b/packages/backend/src/server/api/endpoints/charts/ap-request.ts index f518ae41ca..cbe792376b 100644 --- a/packages/backend/src/server/api/endpoints/charts/ap-request.ts +++ b/packages/backend/src/server/api/endpoints/charts/ap-request.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/drive.ts b/packages/backend/src/server/api/endpoints/charts/drive.ts index 94afab113e..d32bc765a4 100644 --- a/packages/backend/src/server/api/endpoints/charts/drive.ts +++ b/packages/backend/src/server/api/endpoints/charts/drive.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/federation.ts b/packages/backend/src/server/api/endpoints/charts/federation.ts index bc33930ca4..dad21e9e8e 100644 --- a/packages/backend/src/server/api/endpoints/charts/federation.ts +++ b/packages/backend/src/server/api/endpoints/charts/federation.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/instance.ts b/packages/backend/src/server/api/endpoints/charts/instance.ts index a432845b38..68aa12ac0e 100644 --- a/packages/backend/src/server/api/endpoints/charts/instance.ts +++ b/packages/backend/src/server/api/endpoints/charts/instance.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/notes.ts b/packages/backend/src/server/api/endpoints/charts/notes.ts index e1e9d06311..e1979cfe8b 100644 --- a/packages/backend/src/server/api/endpoints/charts/notes.ts +++ b/packages/backend/src/server/api/endpoints/charts/notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/user/drive.ts b/packages/backend/src/server/api/endpoints/charts/user/drive.ts index b4a58c9872..dcb72084b7 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/drive.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/drive.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/user/following.ts b/packages/backend/src/server/api/endpoints/charts/user/following.ts index c609c5a7fe..0a019ce4fb 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/following.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/following.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/user/notes.ts b/packages/backend/src/server/api/endpoints/charts/user/notes.ts index ad6a342fb7..06b15bca18 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/notes.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/user/pv.ts b/packages/backend/src/server/api/endpoints/charts/user/pv.ts index 635a403d12..d359b491e2 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/pv.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/pv.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/user/reactions.ts b/packages/backend/src/server/api/endpoints/charts/user/reactions.ts index 92bc7028ad..4355aa5348 100644 --- a/packages/backend/src/server/api/endpoints/charts/user/reactions.ts +++ b/packages/backend/src/server/api/endpoints/charts/user/reactions.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/charts/users.ts b/packages/backend/src/server/api/endpoints/charts/users.ts index 3be3721e3a..1f5f5fea54 100644 --- a/packages/backend/src/server/api/endpoints/charts/users.ts +++ b/packages/backend/src/server/api/endpoints/charts/users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/clips/add-note.ts b/packages/backend/src/server/api/endpoints/clips/add-note.ts index 749593aa65..d7c9ea3964 100644 --- a/packages/backend/src/server/api/endpoints/clips/add-note.ts +++ b/packages/backend/src/server/api/endpoints/clips/add-note.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/clips/create.ts b/packages/backend/src/server/api/endpoints/clips/create.ts index b4c7b52e72..ceebc8ba5e 100644 --- a/packages/backend/src/server/api/endpoints/clips/create.ts +++ b/packages/backend/src/server/api/endpoints/clips/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/clips/delete.ts b/packages/backend/src/server/api/endpoints/clips/delete.ts index 239945e8a4..ca8ff2e1f1 100644 --- a/packages/backend/src/server/api/endpoints/clips/delete.ts +++ b/packages/backend/src/server/api/endpoints/clips/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/clips/favorite.ts b/packages/backend/src/server/api/endpoints/clips/favorite.ts index 015b2cfa85..11f8ec3e92 100644 --- a/packages/backend/src/server/api/endpoints/clips/favorite.ts +++ b/packages/backend/src/server/api/endpoints/clips/favorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -62,7 +62,7 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.noSuchClip); } - const exist = await this.clipFavoritesRepository.exist({ + const exist = await this.clipFavoritesRepository.exists({ where: { clipId: clip.id, userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/clips/list.ts b/packages/backend/src/server/api/endpoints/clips/list.ts index c124762e33..2e4a3ff820 100644 --- a/packages/backend/src/server/api/endpoints/clips/list.ts +++ b/packages/backend/src/server/api/endpoints/clips/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/clips/my-favorites.ts b/packages/backend/src/server/api/endpoints/clips/my-favorites.ts index c58c16e25f..44719592d1 100644 --- a/packages/backend/src/server/api/endpoints/clips/my-favorites.ts +++ b/packages/backend/src/server/api/endpoints/clips/my-favorites.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/clips/notes.ts b/packages/backend/src/server/api/endpoints/clips/notes.ts index 1427d8d0a7..943c31c894 100644 --- a/packages/backend/src/server/api/endpoints/clips/notes.ts +++ b/packages/backend/src/server/api/endpoints/clips/notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/clips/remove-note.ts b/packages/backend/src/server/api/endpoints/clips/remove-note.ts index 7b153cb555..33f9ecd25b 100644 --- a/packages/backend/src/server/api/endpoints/clips/remove-note.ts +++ b/packages/backend/src/server/api/endpoints/clips/remove-note.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/clips/show.ts b/packages/backend/src/server/api/endpoints/clips/show.ts index 03b1e09dfb..1078a1b176 100644 --- a/packages/backend/src/server/api/endpoints/clips/show.ts +++ b/packages/backend/src/server/api/endpoints/clips/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/clips/unfavorite.ts b/packages/backend/src/server/api/endpoints/clips/unfavorite.ts index d1007f7a19..a458fda4a0 100644 --- a/packages/backend/src/server/api/endpoints/clips/unfavorite.ts +++ b/packages/backend/src/server/api/endpoints/clips/unfavorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/clips/update.ts b/packages/backend/src/server/api/endpoints/clips/update.ts index 0b9878578c..3b44ba81b3 100644 --- a/packages/backend/src/server/api/endpoints/clips/update.ts +++ b/packages/backend/src/server/api/endpoints/clips/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive.ts b/packages/backend/src/server/api/endpoints/drive.ts index 71d3ca5f14..7e9b0fa0e1 100644 --- a/packages/backend/src/server/api/endpoints/drive.ts +++ b/packages/backend/src/server/api/endpoints/drive.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/files.ts b/packages/backend/src/server/api/endpoints/drive/files.ts index 0ca31dc993..10c521332d 100644 --- a/packages/backend/src/server/api/endpoints/drive/files.ts +++ b/packages/backend/src/server/api/endpoints/drive/files.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts index 7a0b8b4417..4670392025 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts index 85e6312b6a..cc7920505f 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -38,7 +38,7 @@ export default class extends Endpoint { // eslint- private driveFilesRepository: DriveFilesRepository, ) { super(meta, paramDef, async (ps, me) => { - const exist = await this.driveFilesRepository.exist({ + const exist = await this.driveFilesRepository.exists({ where: { md5: ps.md5, userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/drive/files/create.ts b/packages/backend/src/server/api/endpoints/drive/files/create.ts index 5e97588c99..9c17f93ab2 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/files/delete.ts b/packages/backend/src/server/api/endpoints/drive/files/delete.ts index f46bf49965..fa6e11da49 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/delete.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts b/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts index 7b784f253e..090cff6875 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/find-by-hash.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/files/find.ts b/packages/backend/src/server/api/endpoints/drive/files/find.ts index 0ceb31e58d..595a6957b2 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/find.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/find.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/files/show.ts b/packages/backend/src/server/api/endpoints/drive/files/show.ts index 474c7f02d3..e8f4539d61 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/show.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/files/update.ts b/packages/backend/src/server/api/endpoints/drive/files/update.ts index c01f3de03c..df1622cce0 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts b/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts index bbe62063cf..b964ae95b8 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/upload-from-url.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/folders.ts b/packages/backend/src/server/api/endpoints/drive/folders.ts index 3a09266591..8c4848f8e1 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/folders/create.ts b/packages/backend/src/server/api/endpoints/drive/folders/create.ts index d18199f19b..c94070d9ff 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/create.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/folders/delete.ts b/packages/backend/src/server/api/endpoints/drive/folders/delete.ts index 46a00ca3dc..85d63873a4 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/delete.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/folders/find.ts b/packages/backend/src/server/api/endpoints/drive/folders/find.ts index 2f5cdcc648..eb45a30bc0 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/find.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/find.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/folders/show.ts b/packages/backend/src/server/api/endpoints/drive/folders/show.ts index dd44fc46c9..a1c0df6697 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/show.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/folders/update.ts b/packages/backend/src/server/api/endpoints/drive/folders/update.ts index f8683132b2..52b8b335b5 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/drive/stream.ts b/packages/backend/src/server/api/endpoints/drive/stream.ts index 27e1656f82..f7c1ed39b5 100644 --- a/packages/backend/src/server/api/endpoints/drive/stream.ts +++ b/packages/backend/src/server/api/endpoints/drive/stream.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/email-address/available.ts b/packages/backend/src/server/api/endpoints/email-address/available.ts index 787009f13c..1d7dacd60e 100644 --- a/packages/backend/src/server/api/endpoints/email-address/available.ts +++ b/packages/backend/src/server/api/endpoints/email-address/available.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/emoji.ts b/packages/backend/src/server/api/endpoints/emoji.ts index ead8c9979e..ccfbda0d44 100644 --- a/packages/backend/src/server/api/endpoints/emoji.ts +++ b/packages/backend/src/server/api/endpoints/emoji.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/emojis.ts b/packages/backend/src/server/api/endpoints/emojis.ts index 2adf0a21b3..46ef4eca1b 100644 --- a/packages/backend/src/server/api/endpoints/emojis.ts +++ b/packages/backend/src/server/api/endpoints/emojis.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/endpoint.ts b/packages/backend/src/server/api/endpoints/endpoint.ts index 66ac8f664f..fe7e9c36f3 100644 --- a/packages/backend/src/server/api/endpoints/endpoint.ts +++ b/packages/backend/src/server/api/endpoints/endpoint.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/endpoints.ts b/packages/backend/src/server/api/endpoints/endpoints.ts index 86def04aca..4aedf62a84 100644 --- a/packages/backend/src/server/api/endpoints/endpoints.ts +++ b/packages/backend/src/server/api/endpoints/endpoints.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/export-custom-emojis.ts b/packages/backend/src/server/api/endpoints/export-custom-emojis.ts index 7380c593e3..5ff099524d 100644 --- a/packages/backend/src/server/api/endpoints/export-custom-emojis.ts +++ b/packages/backend/src/server/api/endpoints/export-custom-emojis.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/federation/followers.ts b/packages/backend/src/server/api/endpoints/federation/followers.ts index a92cf6a9d8..ce4dd13067 100644 --- a/packages/backend/src/server/api/endpoints/federation/followers.ts +++ b/packages/backend/src/server/api/endpoints/federation/followers.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/federation/following.ts b/packages/backend/src/server/api/endpoints/federation/following.ts index d72ceeeea2..1a793889c7 100644 --- a/packages/backend/src/server/api/endpoints/federation/following.ts +++ b/packages/backend/src/server/api/endpoints/federation/following.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 457309731f..4ef4315fb3 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/federation/show-instance.ts b/packages/backend/src/server/api/endpoints/federation/show-instance.ts index 781c15e742..2972861a4b 100644 --- a/packages/backend/src/server/api/endpoints/federation/show-instance.ts +++ b/packages/backend/src/server/api/endpoints/federation/show-instance.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -43,7 +43,7 @@ export default class extends Endpoint { // eslint- const instance = await this.instancesRepository .findOneBy({ host: this.utilityService.toPuny(ps.host) }); - return instance ? await this.instanceEntityService.pack(instance) : null; + return instance ? await this.instanceEntityService.pack(instance, me) : null; }); } } diff --git a/packages/backend/src/server/api/endpoints/federation/stats.ts b/packages/backend/src/server/api/endpoints/federation/stats.ts index 262aa68776..bac54970ab 100644 --- a/packages/backend/src/server/api/endpoints/federation/stats.ts +++ b/packages/backend/src/server/api/endpoints/federation/stats.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts b/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts index e6198ff601..f8430ef431 100644 --- a/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts +++ b/packages/backend/src/server/api/endpoints/federation/update-remote-user.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/federation/users.ts b/packages/backend/src/server/api/endpoints/federation/users.ts index d97171865a..71b1aeb07b 100644 --- a/packages/backend/src/server/api/endpoints/federation/users.ts +++ b/packages/backend/src/server/api/endpoints/federation/users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -54,7 +54,7 @@ export default class extends Endpoint { // eslint- .limit(ps.limit) .getMany(); - return await this.userEntityService.packMany(users, me, { detail: true }); + return await this.userEntityService.packMany(users, me, { schema: 'UserDetailedNotMe' }); }); } } diff --git a/packages/backend/src/server/api/endpoints/fetch-external-resources.ts b/packages/backend/src/server/api/endpoints/fetch-external-resources.ts index cbe579eb6b..f36136d53b 100644 --- a/packages/backend/src/server/api/endpoints/fetch-external-resources.ts +++ b/packages/backend/src/server/api/endpoints/fetch-external-resources.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/fetch-rss.ts b/packages/backend/src/server/api/endpoints/fetch-rss.ts index b2dee83fe9..2085b06365 100644 --- a/packages/backend/src/server/api/endpoints/fetch-rss.ts +++ b/packages/backend/src/server/api/endpoints/fetch-rss.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/flash/create.ts b/packages/backend/src/server/api/endpoints/flash/create.ts index 674f323734..584d167a29 100644 --- a/packages/backend/src/server/api/endpoints/flash/create.ts +++ b/packages/backend/src/server/api/endpoints/flash/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/flash/delete.ts b/packages/backend/src/server/api/endpoints/flash/delete.ts index e5448c816a..d3d47e5deb 100644 --- a/packages/backend/src/server/api/endpoints/flash/delete.ts +++ b/packages/backend/src/server/api/endpoints/flash/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/flash/featured.ts b/packages/backend/src/server/api/endpoints/flash/featured.ts index 1fa5612ac4..c2d6ab5085 100644 --- a/packages/backend/src/server/api/endpoints/flash/featured.ts +++ b/packages/backend/src/server/api/endpoints/flash/featured.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/flash/like.ts b/packages/backend/src/server/api/endpoints/flash/like.ts index 1003249c0c..e4dc5b61c5 100644 --- a/packages/backend/src/server/api/endpoints/flash/like.ts +++ b/packages/backend/src/server/api/endpoints/flash/like.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -70,7 +70,7 @@ export default class extends Endpoint { // eslint- } // if already liked - const exist = await this.flashLikesRepository.exist({ + const exist = await this.flashLikesRepository.exists({ where: { flashId: flash.id, userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/flash/my-likes.ts b/packages/backend/src/server/api/endpoints/flash/my-likes.ts index e328bdbee5..755cc5acfc 100644 --- a/packages/backend/src/server/api/endpoints/flash/my-likes.ts +++ b/packages/backend/src/server/api/endpoints/flash/my-likes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/flash/my.ts b/packages/backend/src/server/api/endpoints/flash/my.ts index 442d8dcd75..5746096232 100644 --- a/packages/backend/src/server/api/endpoints/flash/my.ts +++ b/packages/backend/src/server/api/endpoints/flash/my.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/flash/show.ts b/packages/backend/src/server/api/endpoints/flash/show.ts index c41a27c925..a6fbd8e76e 100644 --- a/packages/backend/src/server/api/endpoints/flash/show.ts +++ b/packages/backend/src/server/api/endpoints/flash/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/flash/unlike.ts b/packages/backend/src/server/api/endpoints/flash/unlike.ts index d5c20a1167..7869bcdf52 100644 --- a/packages/backend/src/server/api/endpoints/flash/unlike.ts +++ b/packages/backend/src/server/api/endpoints/flash/unlike.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/flash/update.ts b/packages/backend/src/server/api/endpoints/flash/update.ts index 8b5e1f99e9..e378669f0a 100644 --- a/packages/backend/src/server/api/endpoints/flash/update.ts +++ b/packages/backend/src/server/api/endpoints/flash/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -51,7 +51,7 @@ export const paramDef = { } }, visibility: { type: 'string', enum: ['public', 'private'] }, }, - required: ['flashId', 'title', 'summary', 'script', 'permissions'], + required: ['flashId'], } as const; @Injectable() @@ -71,11 +71,11 @@ export default class extends Endpoint { // eslint- await this.flashsRepository.update(flash.id, { updatedAt: new Date(), - title: ps.title, - summary: ps.summary, - script: ps.script, - permissions: ps.permissions, - visibility: ps.visibility, + ...Object.fromEntries( + Object.entries(ps).filter( + ([key, val]) => (key !== 'flashId') && Object.hasOwn(paramDef.properties, key) + ) + ), }); }); } diff --git a/packages/backend/src/server/api/endpoints/following/create.ts b/packages/backend/src/server/api/endpoints/following/create.ts index 9037944ef9..db320e7129 100644 --- a/packages/backend/src/server/api/endpoints/following/create.ts +++ b/packages/backend/src/server/api/endpoints/following/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -71,7 +71,7 @@ export const paramDef = { type: 'object', properties: { userId: { type: 'string', format: 'misskey:id' }, - withReplies: { type: 'boolean' } + withReplies: { type: 'boolean' }, }, required: ['userId'], } as const; @@ -100,22 +100,11 @@ export default class extends Endpoint { // eslint- throw err; }); - // Check if already following - const exist = await this.followingsRepository.exist({ - where: { - followerId: follower.id, - followeeId: followee.id, - }, - }); - - if (exist) { - throw new ApiError(meta.errors.alreadyFollowing); - } - try { await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies }); } catch (e) { if (e instanceof IdentifiableError) { + if (e.id === 'ec3f65c0-a9d1-47d9-8791-b2e7b9dcdced') throw new ApiError(meta.errors.alreadyFollowing); if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking); if (e.id === '3338392a-f764-498d-8855-db939dcf8c48') throw new ApiError(meta.errors.blocked); } diff --git a/packages/backend/src/server/api/endpoints/following/delete.ts b/packages/backend/src/server/api/endpoints/following/delete.ts index f44692ba6d..ba146b6703 100644 --- a/packages/backend/src/server/api/endpoints/following/delete.ts +++ b/packages/backend/src/server/api/endpoints/following/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -85,7 +85,7 @@ export default class extends Endpoint { // eslint- }); // Check not following - const exist = await this.followingsRepository.exist({ + const exist = await this.followingsRepository.exists({ where: { followerId: follower.id, followeeId: followee.id, diff --git a/packages/backend/src/server/api/endpoints/following/invalidate.ts b/packages/backend/src/server/api/endpoints/following/invalidate.ts index 53ef925b2f..8935c2c2da 100644 --- a/packages/backend/src/server/api/endpoints/following/invalidate.ts +++ b/packages/backend/src/server/api/endpoints/following/invalidate.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/following/requests/accept.ts b/packages/backend/src/server/api/endpoints/following/requests/accept.ts index 91fe922200..2d1446681c 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/accept.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/accept.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/following/requests/cancel.ts b/packages/backend/src/server/api/endpoints/following/requests/cancel.ts index d9d5c7041b..6d663d480c 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/cancel.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/cancel.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/following/requests/list.ts b/packages/backend/src/server/api/endpoints/following/requests/list.ts index c4faa88f65..88f559138b 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/list.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/following/requests/reject.ts b/packages/backend/src/server/api/endpoints/following/requests/reject.ts index 35f047bcef..4f78eae677 100644 --- a/packages/backend/src/server/api/endpoints/following/requests/reject.ts +++ b/packages/backend/src/server/api/endpoints/following/requests/reject.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/following/update-all.ts b/packages/backend/src/server/api/endpoints/following/update-all.ts index 28734cfdbd..c953feb393 100644 --- a/packages/backend/src/server/api/endpoints/following/update-all.ts +++ b/packages/backend/src/server/api/endpoints/following/update-all.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/following/update.ts b/packages/backend/src/server/api/endpoints/following/update.ts index db17d151df..d62cf210ed 100644 --- a/packages/backend/src/server/api/endpoints/following/update.ts +++ b/packages/backend/src/server/api/endpoints/following/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/gallery/featured.ts b/packages/backend/src/server/api/endpoints/gallery/featured.ts index cea4234065..7d2878e03f 100644 --- a/packages/backend/src/server/api/endpoints/gallery/featured.ts +++ b/packages/backend/src/server/api/endpoints/gallery/featured.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/gallery/popular.ts b/packages/backend/src/server/api/endpoints/gallery/popular.ts index c5d06f67dd..4ee252104a 100644 --- a/packages/backend/src/server/api/endpoints/gallery/popular.ts +++ b/packages/backend/src/server/api/endpoints/gallery/popular.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/gallery/posts.ts b/packages/backend/src/server/api/endpoints/gallery/posts.ts index 3ca5f4989a..d398418ab4 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts index 71e0ad4141..b07cdf1ed9 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -12,6 +12,7 @@ import type { MiDriveFile } from '@/models/DriveFile.js'; import { IdService } from '@/core/IdService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { DI } from '@/di-symbols.js'; +import { isNotNull } from '@/misc/is-not-null.js'; export const meta = { tags: ['gallery'], @@ -69,7 +70,7 @@ export default class extends Endpoint { // eslint- id: fileId, userId: me.id, }), - ))).filter((file): file is MiDriveFile => file != null); + ))).filter(isNotNull); if (files.length === 0) { throw new Error(); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts b/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts index deef2912bb..527e3fb52d 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts index cc424261b4..91e49e6463 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -72,7 +72,7 @@ export default class extends Endpoint { // eslint- } // if already liked - const exist = await this.galleryLikesRepository.exist({ + const exist = await this.galleryLikesRepository.exists({ where: { postId: post.id, userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/show.ts b/packages/backend/src/server/api/endpoints/gallery/posts/show.ts index b3eda1be52..bd69898229 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/show.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts index caa4d45553..f44e2c7afc 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/unlike.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts index 632214a0c2..8bd83ff5ba 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -10,6 +10,7 @@ import type { DriveFilesRepository, GalleryPostsRepository } from '@/models/_.js import type { MiDriveFile } from '@/models/DriveFile.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { DI } from '@/di-symbols.js'; +import { isNotNull } from '@/misc/is-not-null.js'; export const meta = { tags: ['gallery'], @@ -67,7 +68,7 @@ export default class extends Endpoint { // eslint- id: fileId, userId: me.id, }), - ))).filter((file): file is MiDriveFile => file != null); + ))).filter(isNotNull); if (files.length === 0) { throw new Error(); diff --git a/packages/backend/src/server/api/endpoints/get-avatar-decorations.ts b/packages/backend/src/server/api/endpoints/get-avatar-decorations.ts index dbe1626149..52acee1cfb 100644 --- a/packages/backend/src/server/api/endpoints/get-avatar-decorations.ts +++ b/packages/backend/src/server/api/endpoints/get-avatar-decorations.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/get-online-users-count.ts b/packages/backend/src/server/api/endpoints/get-online-users-count.ts index 737d637b7e..a57774be73 100644 --- a/packages/backend/src/server/api/endpoints/get-online-users-count.ts +++ b/packages/backend/src/server/api/endpoints/get-online-users-count.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/hashtags/list.ts b/packages/backend/src/server/api/endpoints/hashtags/list.ts index 21d863107d..5cd3c6584d 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/list.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/hashtags/search.ts b/packages/backend/src/server/api/endpoints/hashtags/search.ts index acfef16b11..d4eb851054 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/search.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/search.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -43,7 +43,7 @@ export default class extends Endpoint { // eslint- super(meta, paramDef, async (ps, me) => { const hashtags = await this.hashtagsRepository.createQueryBuilder('tag') .where('tag.name like :q', { q: sqlLikeEscape(ps.query.toLowerCase()) + '%' }) - .orderBy('tag.count', 'DESC') + .orderBy('tag.mentionedLocalUsersCount', 'DESC') .groupBy('tag.id') .limit(ps.limit) .offset(ps.offset) diff --git a/packages/backend/src/server/api/endpoints/hashtags/show.ts b/packages/backend/src/server/api/endpoints/hashtags/show.ts index 3ba16fdc85..940e3bd69d 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/show.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/hashtags/trend.ts b/packages/backend/src/server/api/endpoints/hashtags/trend.ts index 8f382eb96b..cb8065e3a6 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/trend.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/trend.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/hashtags/users.ts b/packages/backend/src/server/api/endpoints/hashtags/users.ts index 8302d2380f..30f0c1b0c8 100644 --- a/packages/backend/src/server/api/endpoints/hashtags/users.ts +++ b/packages/backend/src/server/api/endpoints/hashtags/users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -76,7 +76,7 @@ export default class extends Endpoint { // eslint- const users = await query.limit(ps.limit).getMany(); - return await this.userEntityService.packMany(users, me, { detail: true }); + return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' }); }); } } diff --git a/packages/backend/src/server/api/endpoints/i.ts b/packages/backend/src/server/api/endpoints/i.ts index c24e049180..d324e3e64a 100644 --- a/packages/backend/src/server/api/endpoints/i.ts +++ b/packages/backend/src/server/api/endpoints/i.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -71,8 +71,8 @@ export default class extends Endpoint { // eslint- userProfile.loggedInDates = [...userProfile.loggedInDates, today]; } - return await this.userEntityService.pack(userProfile.user!, userProfile.user!, { - detail: true, + return await this.userEntityService.pack(userProfile.user!, userProfile.user!, { + schema: 'MeDetailed', includeSecrets: isSecure, userProfile, }); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/done.ts b/packages/backend/src/server/api/endpoints/i/2fa/done.ts index 9f8e2894b8..2a30e8b0c3 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/done.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -15,6 +15,19 @@ export const meta = { requireCredential: true, secure: true, + + res: { + type: 'object', + properties: { + backupCodes: { + type: 'array', + optional: false, + items: { + type: 'string', + }, + }, + }, + }, } as const; export const paramDef = { @@ -64,7 +77,7 @@ export default class extends Endpoint { // eslint- // Publish meUpdated event this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, { - detail: true, + schema: 'MeDetailed', includeSecrets: true, })); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts index a7be47fd0f..5f738420f2 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -111,7 +111,7 @@ export default class extends Endpoint { // Publish meUpdated event this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, { - detail: true, + schema: 'MeDetailed', includeSecrets: true, })); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts b/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts index 2ed701014d..bf039ccd16 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -74,7 +74,7 @@ export default class extends Endpoint { // eslint- // Publish meUpdated event this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, { - detail: true, + schema: 'MeDetailed', includeSecrets: true, })); }); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts index 15c5011db9..9391aee5e0 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -47,7 +47,7 @@ export const meta = { properties: { id: { type: 'string', - nullable: true, + optional: true, }, }, }, diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register.ts b/packages/backend/src/server/api/endpoints/i/2fa/register.ts index cc083cbf7b..a54c598213 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts index da8ac98556..c350136eae 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -97,7 +97,7 @@ export default class extends Endpoint { // eslint- // Publish meUpdated event this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, { - detail: true, + schema: 'MeDetailed', includeSecrets: true, })); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts index 338f12c5cd..b5a53cc889 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -76,7 +76,7 @@ export default class extends Endpoint { // eslint- // Publish meUpdated event this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, { - detail: true, + schema: 'MeDetailed', includeSecrets: true, })); }); diff --git a/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts index 1a140c1d05..cfa07cc8d7 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -69,7 +69,7 @@ export default class extends Endpoint { // eslint- // Publish meUpdated event this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, { - detail: true, + schema: 'MeDetailed', includeSecrets: true, })); diff --git a/packages/backend/src/server/api/endpoints/i/apps.ts b/packages/backend/src/server/api/endpoints/i/apps.ts index ef89f93181..91c8597b1b 100644 --- a/packages/backend/src/server/api/endpoints/i/apps.ts +++ b/packages/backend/src/server/api/endpoints/i/apps.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -21,26 +21,31 @@ export const meta = { properties: { id: { type: 'string', + optional: false, format: 'misskey:id', }, name: { type: 'string', + optional: true, }, createdAt: { type: 'string', + optional: false, format: 'date-time', }, lastUsedAt: { type: 'string', + optional: true, format: 'date-time', }, permission: { type: 'array', + optional: false, uniqueItems: true, items: { - type: 'string' + type: 'string', }, - } + }, }, }, }, diff --git a/packages/backend/src/server/api/endpoints/i/authorized-apps.ts b/packages/backend/src/server/api/endpoints/i/authorized-apps.ts index a0ed371fb8..0b4faf5ef8 100644 --- a/packages/backend/src/server/api/endpoints/i/authorized-apps.ts +++ b/packages/backend/src/server/api/endpoints/i/authorized-apps.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -23,23 +23,27 @@ export const meta = { id: { type: 'string', format: 'misskey:id', + optional: false, }, name: { type: 'string', + optional: false, }, callbackUrl: { type: 'string', - nullable: true, + optional: false, nullable: true, }, permission: { type: 'array', + optional: false, uniqueItems: true, items: { - type: 'string' + type: 'string', }, }, isAuthorized: { type: 'boolean', + optional: true, }, }, }, diff --git a/packages/backend/src/server/api/endpoints/i/change-password.ts b/packages/backend/src/server/api/endpoints/i/change-password.ts index a3c37ffdb7..bb78d47149 100644 --- a/packages/backend/src/server/api/endpoints/i/change-password.ts +++ b/packages/backend/src/server/api/endpoints/i/change-password.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/claim-achievement.ts b/packages/backend/src/server/api/endpoints/i/claim-achievement.ts index 57f680bd7e..e70905ef1b 100644 --- a/packages/backend/src/server/api/endpoints/i/claim-achievement.ts +++ b/packages/backend/src/server/api/endpoints/i/claim-achievement.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/delete-account.ts b/packages/backend/src/server/api/endpoints/i/delete-account.ts index fbac845fda..bfa0b4605d 100644 --- a/packages/backend/src/server/api/endpoints/i/delete-account.ts +++ b/packages/backend/src/server/api/endpoints/i/delete-account.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/export-antennas.ts b/packages/backend/src/server/api/endpoints/i/export-antennas.ts index 23b2f6b4ce..77fb4a895f 100644 --- a/packages/backend/src/server/api/endpoints/i/export-antennas.ts +++ b/packages/backend/src/server/api/endpoints/i/export-antennas.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/export-blocking.ts b/packages/backend/src/server/api/endpoints/i/export-blocking.ts index 8068a3b305..7573018bec 100644 --- a/packages/backend/src/server/api/endpoints/i/export-blocking.ts +++ b/packages/backend/src/server/api/endpoints/i/export-blocking.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/export-clips.ts b/packages/backend/src/server/api/endpoints/i/export-clips.ts index 9435a2b23c..10d1fdac73 100644 --- a/packages/backend/src/server/api/endpoints/i/export-clips.ts +++ b/packages/backend/src/server/api/endpoints/i/export-clips.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/export-favorites.ts b/packages/backend/src/server/api/endpoints/i/export-favorites.ts index c22905bc67..5e03f70170 100644 --- a/packages/backend/src/server/api/endpoints/i/export-favorites.ts +++ b/packages/backend/src/server/api/endpoints/i/export-favorites.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/export-following.ts b/packages/backend/src/server/api/endpoints/i/export-following.ts index 880833ab76..2e5ba14737 100644 --- a/packages/backend/src/server/api/endpoints/i/export-following.ts +++ b/packages/backend/src/server/api/endpoints/i/export-following.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/export-mute.ts b/packages/backend/src/server/api/endpoints/i/export-mute.ts index 8eb70a387a..0384cf142b 100644 --- a/packages/backend/src/server/api/endpoints/i/export-mute.ts +++ b/packages/backend/src/server/api/endpoints/i/export-mute.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/export-notes.ts b/packages/backend/src/server/api/endpoints/i/export-notes.ts index 791f637790..db4e78f667 100644 --- a/packages/backend/src/server/api/endpoints/i/export-notes.ts +++ b/packages/backend/src/server/api/endpoints/i/export-notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/export-user-lists.ts b/packages/backend/src/server/api/endpoints/i/export-user-lists.ts index f387f6d016..6cd662102c 100644 --- a/packages/backend/src/server/api/endpoints/i/export-user-lists.ts +++ b/packages/backend/src/server/api/endpoints/i/export-user-lists.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/favorites.ts b/packages/backend/src/server/api/endpoints/i/favorites.ts index d6f13c535a..3558035eca 100644 --- a/packages/backend/src/server/api/endpoints/i/favorites.ts +++ b/packages/backend/src/server/api/endpoints/i/favorites.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/gallery/likes.ts b/packages/backend/src/server/api/endpoints/i/gallery/likes.ts index 7e37adc4ac..d492585ffa 100644 --- a/packages/backend/src/server/api/endpoints/i/gallery/likes.ts +++ b/packages/backend/src/server/api/endpoints/i/gallery/likes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/gallery/posts.ts b/packages/backend/src/server/api/endpoints/i/gallery/posts.ts index 148d38aa54..73a6fcc98b 100644 --- a/packages/backend/src/server/api/endpoints/i/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/i/gallery/posts.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/import-antennas.ts b/packages/backend/src/server/api/endpoints/i/import-antennas.ts index 71db8710af..b4661a93e2 100644 --- a/packages/backend/src/server/api/endpoints/i/import-antennas.ts +++ b/packages/backend/src/server/api/endpoints/i/import-antennas.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -71,7 +71,7 @@ export default class extends Endpoint { private downloadService: DownloadService, ) { super(meta, paramDef, async (ps, me) => { - const userExist = await this.usersRepository.exist({ where: { id: me.id } }); + const userExist = await this.usersRepository.exists({ where: { id: me.id } }); if (!userExist) throw new ApiError(meta.errors.noSuchUser); const file = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); if (file === null) throw new ApiError(meta.errors.noSuchFile); diff --git a/packages/backend/src/server/api/endpoints/i/import-blocking.ts b/packages/backend/src/server/api/endpoints/i/import-blocking.ts index 965ad30547..8ddbe5663e 100644 --- a/packages/backend/src/server/api/endpoints/i/import-blocking.ts +++ b/packages/backend/src/server/api/endpoints/i/import-blocking.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts index e5fa2ac96a..390dd9cd71 100644 --- a/packages/backend/src/server/api/endpoints/i/import-following.ts +++ b/packages/backend/src/server/api/endpoints/i/import-following.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/import-muting.ts b/packages/backend/src/server/api/endpoints/i/import-muting.ts index 926cf13d7f..51a9cdf5a5 100644 --- a/packages/backend/src/server/api/endpoints/i/import-muting.ts +++ b/packages/backend/src/server/api/endpoints/i/import-muting.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts index 2167996435..a3b67301a7 100644 --- a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts +++ b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/move.ts b/packages/backend/src/server/api/endpoints/i/move.ts index f3ba720c2b..1bd641232c 100644 --- a/packages/backend/src/server/api/endpoints/i/move.ts +++ b/packages/backend/src/server/api/endpoints/i/move.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts b/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts index 4ea94b07f6..dc6ffd3e02 100644 --- a/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts +++ b/packages/backend/src/server/api/endpoints/i/notifications-grouped.ts @@ -1,13 +1,13 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -import { Brackets, In } from 'typeorm'; +import { In } from 'typeorm'; import * as Redis from 'ioredis'; import { Inject, Injectable } from '@nestjs/common'; import type { NotesRepository } from '@/models/_.js'; -import { obsoleteNotificationTypes, notificationTypes, FilterUnionByProperty } from '@/types.js'; +import { obsoleteNotificationTypes, groupedNotificationTypes, FilterUnionByProperty } from '@/types.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { NoteReadService } from '@/core/NoteReadService.js'; import { NotificationEntityService } from '@/core/entities/NotificationEntityService.js'; @@ -48,10 +48,10 @@ export const paramDef = { markAsRead: { type: 'boolean', default: true }, // 後方互換のため、廃止された通知タイプも受け付ける includeTypes: { type: 'array', items: { - type: 'string', enum: [...notificationTypes, ...obsoleteNotificationTypes], + type: 'string', enum: [...groupedNotificationTypes, ...obsoleteNotificationTypes], } }, excludeTypes: { type: 'array', items: { - type: 'string', enum: [...notificationTypes, ...obsoleteNotificationTypes], + type: 'string', enum: [...groupedNotificationTypes, ...obsoleteNotificationTypes], } }, }, required: [], @@ -79,12 +79,12 @@ export default class extends Endpoint { // eslint- return []; } // excludeTypes に全指定されている場合はクエリしない - if (notificationTypes.every(type => ps.excludeTypes?.includes(type))) { + if (groupedNotificationTypes.every(type => ps.excludeTypes?.includes(type))) { return []; } - const includeTypes = ps.includeTypes && ps.includeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][]; - const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][]; + const includeTypes = ps.includeTypes && ps.includeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof groupedNotificationTypes[number][]; + const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof groupedNotificationTypes[number][]; const limit = (ps.limit + EXTRA_LIMIT) + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1 const notificationsRes = await this.redisClient.xrevrange( @@ -162,7 +162,6 @@ export default class extends Endpoint { // eslint- } groupedNotifications = groupedNotifications.slice(0, ps.limit); - const noteIds = groupedNotifications .filter((notification): notification is FilterUnionByProperty => ['mention', 'reply', 'quote'].includes(notification.type)) .map(notification => notification.noteId!); diff --git a/packages/backend/src/server/api/endpoints/i/notifications.ts b/packages/backend/src/server/api/endpoints/i/notifications.ts index 039fd9454c..320d9fdb00 100644 --- a/packages/backend/src/server/api/endpoints/i/notifications.ts +++ b/packages/backend/src/server/api/endpoints/i/notifications.ts @@ -1,9 +1,9 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -import { Brackets, In } from 'typeorm'; +import { In } from 'typeorm'; import * as Redis from 'ioredis'; import { Inject, Injectable } from '@nestjs/common'; import type { NotesRepository } from '@/models/_.js'; diff --git a/packages/backend/src/server/api/endpoints/i/page-likes.ts b/packages/backend/src/server/api/endpoints/i/page-likes.ts index 6bf7e6aa9b..d4c09426a7 100644 --- a/packages/backend/src/server/api/endpoints/i/page-likes.ts +++ b/packages/backend/src/server/api/endpoints/i/page-likes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/pages.ts b/packages/backend/src/server/api/endpoints/i/pages.ts index b8082c018f..1b6359a633 100644 --- a/packages/backend/src/server/api/endpoints/i/pages.ts +++ b/packages/backend/src/server/api/endpoints/i/pages.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/pin.ts b/packages/backend/src/server/api/endpoints/i/pin.ts index c89cdfa3a4..b7cafd74df 100644 --- a/packages/backend/src/server/api/endpoints/i/pin.ts +++ b/packages/backend/src/server/api/endpoints/i/pin.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -66,8 +66,8 @@ export default class extends Endpoint { // eslint- throw err; }); - return await this.userEntityService.pack(me.id, me, { - detail: true, + return await this.userEntityService.pack(me.id, me, { + schema: 'MeDetailed', }); }); } diff --git a/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts b/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts index e43ab7c15e..d1a8eccb1d 100644 --- a/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts +++ b/packages/backend/src/server/api/endpoints/i/read-all-unread-notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/read-announcement.ts b/packages/backend/src/server/api/endpoints/i/read-announcement.ts index ba7859d0d4..4db1ca73c1 100644 --- a/packages/backend/src/server/api/endpoints/i/read-announcement.ts +++ b/packages/backend/src/server/api/endpoints/i/read-announcement.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts index b70dcfbace..78f3cce9ad 100644 --- a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts +++ b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-all.ts b/packages/backend/src/server/api/endpoints/i/registry/get-all.ts index 79a81cb73f..f1797cfde7 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-all.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-all.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts b/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts index d9b26cab2c..d53c390460 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get-detail.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -22,7 +22,16 @@ export const meta = { res: { type: 'object', - } + properties: { + updatedAt: { + type: 'string', + optional: false, + }, + value: { + optional: false, + }, + }, + }, } as const; export const paramDef = { @@ -50,7 +59,7 @@ export default class extends Endpoint { // eslint- } return { - updatedAt: item.updatedAt, + updatedAt: item.updatedAt.toISOString(), value: item.value, }; }); diff --git a/packages/backend/src/server/api/endpoints/i/registry/get.ts b/packages/backend/src/server/api/endpoints/i/registry/get.ts index c373410256..d9a8fdd449 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/get.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/get.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts b/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts index a91dcd9543..3fe339606d 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/keys-with-type.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -13,6 +13,9 @@ export const meta = { res: { type: 'object', + additionalProperties: { + type: 'string', + }, }, } as const; diff --git a/packages/backend/src/server/api/endpoints/i/registry/keys.ts b/packages/backend/src/server/api/endpoints/i/registry/keys.ts index ad203d5203..28f158c62d 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/keys.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/keys.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -10,6 +10,13 @@ import { RegistryApiService } from '@/core/RegistryApiService.js'; export const meta = { requireCredential: true, kind: 'read:account', + + res: { + type: 'array', + items: { + type: 'string', + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/i/registry/remove.ts b/packages/backend/src/server/api/endpoints/i/registry/remove.ts index 9cbe271b91..cf965ba0cf 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/remove.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/remove.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts b/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts index 0aca2a26fe..67a99b028a 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/scopes-with-domain.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/registry/set.ts b/packages/backend/src/server/api/endpoints/i/registry/set.ts index c61d5b8727..8723035d84 100644 --- a/packages/backend/src/server/api/endpoints/i/registry/set.ts +++ b/packages/backend/src/server/api/endpoints/i/registry/set.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/revoke-token.ts b/packages/backend/src/server/api/endpoints/i/revoke-token.ts index 98d866f867..c05ee93c6f 100644 --- a/packages/backend/src/server/api/endpoints/i/revoke-token.ts +++ b/packages/backend/src/server/api/endpoints/i/revoke-token.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -34,7 +34,7 @@ export default class extends Endpoint { // eslint- ) { super(meta, paramDef, async (ps, me) => { if (ps.tokenId) { - const tokenExist = await this.accessTokensRepository.exist({ where: { id: ps.tokenId } }); + const tokenExist = await this.accessTokensRepository.exists({ where: { id: ps.tokenId } }); if (tokenExist) { await this.accessTokensRepository.delete({ @@ -43,7 +43,7 @@ export default class extends Endpoint { // eslint- }); } } else if (ps.token) { - const tokenExist = await this.accessTokensRepository.exist({ where: { token: ps.token } }); + const tokenExist = await this.accessTokensRepository.exists({ where: { token: ps.token } }); if (tokenExist) { await this.accessTokensRepository.delete({ diff --git a/packages/backend/src/server/api/endpoints/i/signin-history.ts b/packages/backend/src/server/api/endpoints/i/signin-history.ts index f82e3f9b28..76ad0bbe21 100644 --- a/packages/backend/src/server/api/endpoints/i/signin-history.ts +++ b/packages/backend/src/server/api/endpoints/i/signin-history.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/unpin.ts b/packages/backend/src/server/api/endpoints/i/unpin.ts index b59c0e954f..74825cf9f3 100644 --- a/packages/backend/src/server/api/endpoints/i/unpin.ts +++ b/packages/backend/src/server/api/endpoints/i/unpin.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -51,8 +51,8 @@ export default class extends Endpoint { // eslint- throw err; }); - return await this.userEntityService.pack(me.id, me, { - detail: true, + return await this.userEntityService.pack(me.id, me, { + schema: 'MeDetailed', }); }); } diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts index 52977f5a07..3868278690 100644 --- a/packages/backend/src/server/api/endpoints/i/update-email.ts +++ b/packages/backend/src/server/api/endpoints/i/update-email.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -43,7 +43,7 @@ export const meta = { res: { type: 'object', - ref: 'UserDetailed', + ref: 'MeDetailed', }, } as const; @@ -106,7 +106,7 @@ export default class extends Endpoint { // eslint- }); const iObj = await this.userEntityService.pack(me.id, me, { - detail: true, + schema: 'MeDetailed', includeSecrets: true, }); diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index eed3082258..84a1931a3d 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -33,6 +33,7 @@ import { HttpRequestService } from '@/core/HttpRequestService.js'; import type { Config } from '@/config.js'; import { safeForSql } from '@/misc/safe-for-sql.js'; import { AvatarDecorationService } from '@/core/AvatarDecorationService.js'; +import { notificationRecieveConfig } from '@/models/json-schema/user.js'; import { ApiLoggerService } from '../../ApiLoggerService.js'; import { ApiError } from '../../error.js'; @@ -184,7 +185,26 @@ export const paramDef = { mutedInstances: { type: 'array', items: { type: 'string', } }, - notificationRecieveConfig: { type: 'object' }, + notificationRecieveConfig: { + type: 'object', + nullable: false, + properties: { + note: notificationRecieveConfig, + follow: notificationRecieveConfig, + mention: notificationRecieveConfig, + reply: notificationRecieveConfig, + renote: notificationRecieveConfig, + quote: notificationRecieveConfig, + reaction: notificationRecieveConfig, + pollEnded: notificationRecieveConfig, + receiveFollowRequest: notificationRecieveConfig, + followRequestAccepted: notificationRecieveConfig, + roleAssigned: notificationRecieveConfig, + achievementEarned: notificationRecieveConfig, + app: notificationRecieveConfig, + test: notificationRecieveConfig, + }, + }, emailNotificationTypes: { type: 'array', items: { type: 'string', } }, @@ -436,9 +456,9 @@ export default class extends Endpoint { // eslint- this.hashtagService.updateUsertags(user, tags); //#endregion - if (Object.keys(updates).length > 0) await this.usersRepository.update(user.id, updates); - if (Object.keys(updates).includes('alsoKnownAs')) { - this.cacheService.uriPersonCache.set(this.userEntityService.genLocalUserUri(user.id), { ...user, ...updates }); + if (Object.keys(updates).length > 0) { + await this.usersRepository.update(user.id, updates); + this.globalEventService.publishInternalEvent('localUserUpdated', { id: user.id }); } await this.userProfilesRepository.update(user.id, { @@ -446,8 +466,8 @@ export default class extends Endpoint { // eslint- verifiedLinks: [], }); - const iObj = await this.userEntityService.pack(user.id, user, { - detail: true, + const iObj = await this.userEntityService.pack(user.id, user, { + schema: 'MeDetailed', includeSecrets: isSecure, }); diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts index bdc9f9ea8b..535a3ea308 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -33,7 +33,7 @@ export const meta = { properties: { id: { type: 'string', - format: 'misskey:id' + format: 'misskey:id', }, userId: { type: 'string', @@ -45,7 +45,7 @@ export const meta = { items: { type: 'string', enum: webhookEventTypes, - } + }, }, url: { type: 'string' }, secret: { type: 'string' }, @@ -108,7 +108,7 @@ export default class extends Endpoint { // eslint- url: webhook.url, secret: webhook.secret, active: webhook.active, - latestSentAt: webhook.latestSentAt?.toISOString(), + latestSentAt: webhook.latestSentAt ? webhook.latestSentAt.toISOString() : null, latestStatus: webhook.latestStatus, }; }); diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/delete.ts b/packages/backend/src/server/api/endpoints/i/webhooks/delete.ts index db7d0db13c..1b1ac00670 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/delete.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/list.ts b/packages/backend/src/server/api/endpoints/i/webhooks/list.ts index afb2d0509e..fe07afb2d0 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/list.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -23,7 +23,7 @@ export const meta = { properties: { id: { type: 'string', - format: 'misskey:id' + format: 'misskey:id', }, userId: { type: 'string', @@ -35,7 +35,7 @@ export const meta = { items: { type: 'string', enum: webhookEventTypes, - } + }, }, url: { type: 'string' }, secret: { type: 'string' }, @@ -43,8 +43,8 @@ export const meta = { latestSentAt: { type: 'string', format: 'date-time', nullable: true }, latestStatus: { type: 'integer', nullable: true }, }, - } - } + }, + }, } as const; export const paramDef = { @@ -73,7 +73,7 @@ export default class extends Endpoint { // eslint- url: webhook.url, secret: webhook.secret, active: webhook.active, - latestSentAt: webhook.latestSentAt?.toISOString(), + latestSentAt: webhook.latestSentAt ? webhook.latestSentAt.toISOString() : null, latestStatus: webhook.latestStatus, } )); diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/show.ts b/packages/backend/src/server/api/endpoints/i/webhooks/show.ts index 5c6dd908b4..5ddb79caf2 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/show.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -30,7 +30,7 @@ export const meta = { properties: { id: { type: 'string', - format: 'misskey:id' + format: 'misskey:id', }, userId: { type: 'string', @@ -42,7 +42,7 @@ export const meta = { items: { type: 'string', enum: webhookEventTypes, - } + }, }, url: { type: 'string' }, secret: { type: 'string' }, @@ -85,7 +85,7 @@ export default class extends Endpoint { // eslint- url: webhook.url, secret: webhook.secret, active: webhook.active, - latestSentAt: webhook.latestSentAt?.toISOString(), + latestSentAt: webhook.latestSentAt ? webhook.latestSentAt.toISOString() : null, latestStatus: webhook.latestStatus, }; }); diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/update.ts b/packages/backend/src/server/api/endpoints/i/webhooks/update.ts index b3e000524d..6e380d76f8 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/update.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/invite/create.ts b/packages/backend/src/server/api/endpoints/invite/create.ts index 4f37f2f4bb..0ff125ad9c 100644 --- a/packages/backend/src/server/api/endpoints/invite/create.ts +++ b/packages/backend/src/server/api/endpoints/invite/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/invite/delete.ts b/packages/backend/src/server/api/endpoints/invite/delete.ts index d84430a49f..e960ff9f4e 100644 --- a/packages/backend/src/server/api/endpoints/invite/delete.ts +++ b/packages/backend/src/server/api/endpoints/invite/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/invite/limit.ts b/packages/backend/src/server/api/endpoints/invite/limit.ts index fc3bb9bdc2..2786bd98d5 100644 --- a/packages/backend/src/server/api/endpoints/invite/limit.ts +++ b/packages/backend/src/server/api/endpoints/invite/limit.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/invite/list.ts b/packages/backend/src/server/api/endpoints/invite/list.ts index 6734f27e14..23aefe83a2 100644 --- a/packages/backend/src/server/api/endpoints/invite/list.ts +++ b/packages/backend/src/server/api/endpoints/invite/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 529e82678d..5460635e1d 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -1,19 +1,11 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -import { IsNull, LessThanOrEqual, MoreThan, Brackets } from 'typeorm'; -import { Inject, Injectable } from '@nestjs/common'; -import JSON5 from 'json5'; -import type { AdsRepository, UsersRepository } from '@/models/_.js'; -import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; +import { Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { MetaService } from '@/core/MetaService.js'; -import type { Config } from '@/config.js'; -import { DI } from '@/di-symbols.js'; -import { DEFAULT_POLICIES } from '@/core/RoleService.js'; +import { MetaEntityService } from '@/core/entities/MetaEntityService.js'; export const meta = { tags: ['meta'], @@ -22,288 +14,10 @@ export const meta = { res: { type: 'object', - optional: false, nullable: false, - properties: { - maintainerName: { - type: 'string', - optional: false, nullable: true, - }, - maintainerEmail: { - type: 'string', - optional: false, nullable: true, - }, - version: { - type: 'string', - optional: false, nullable: false, - }, - name: { - type: 'string', - optional: false, nullable: false, - }, - shortName: { - type: 'string', - optional: false, nullable: true, - }, - uri: { - type: 'string', - optional: false, nullable: false, - format: 'url', - example: 'https://misskey.example.com', - }, - description: { - type: 'string', - optional: false, nullable: true, - }, - langs: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'string', - optional: false, nullable: false, - }, - }, - tosUrl: { - type: 'string', - optional: false, nullable: true, - }, - repositoryUrl: { - type: 'string', - optional: false, nullable: false, - default: 'https://github.com/misskey-dev/misskey', - }, - feedbackUrl: { - type: 'string', - optional: false, nullable: false, - default: 'https://github.com/misskey-dev/misskey/issues/new', - }, - defaultDarkTheme: { - type: 'string', - optional: false, nullable: true, - }, - defaultLightTheme: { - type: 'string', - optional: false, nullable: true, - }, - disableRegistration: { - type: 'boolean', - optional: false, nullable: false, - }, - cacheRemoteFiles: { - type: 'boolean', - optional: false, nullable: false, - }, - cacheRemoteSensitiveFiles: { - type: 'boolean', - optional: false, nullable: false, - }, - emailRequiredForSignup: { - type: 'boolean', - optional: false, nullable: false, - }, - enableHcaptcha: { - type: 'boolean', - optional: false, nullable: false, - }, - hcaptchaSiteKey: { - type: 'string', - optional: false, nullable: true, - }, - enableMcaptcha: { - type: 'boolean', - optional: false, nullable: false, - }, - mcaptchaSiteKey: { - type: 'string', - optional: false, nullable: true, - }, - mcaptchaInstanceUrl: { - type: 'string', - optional: false, nullable: true, - }, - enableRecaptcha: { - type: 'boolean', - optional: false, nullable: false, - }, - recaptchaSiteKey: { - type: 'string', - optional: false, nullable: true, - }, - enableTurnstile: { - type: 'boolean', - optional: false, nullable: false, - }, - turnstileSiteKey: { - type: 'string', - optional: false, nullable: true, - }, - swPublickey: { - type: 'string', - optional: false, nullable: true, - }, - mascotImageUrl: { - type: 'string', - optional: false, nullable: false, - default: '/assets/ai.png', - }, - bannerUrl: { - type: 'string', - optional: false, nullable: false, - }, - serverErrorImageUrl: { - type: 'string', - optional: false, nullable: true, - }, - infoImageUrl: { - type: 'string', - optional: false, nullable: true, - }, - notFoundImageUrl: { - type: 'string', - optional: false, nullable: true, - }, - iconUrl: { - type: 'string', - optional: false, nullable: true, - }, - maxNoteTextLength: { - type: 'number', - optional: false, nullable: false, - }, - ads: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'object', - optional: false, nullable: false, - properties: { - id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', - }, - url: { - type: 'string', - optional: false, nullable: false, - format: 'url', - }, - place: { - type: 'string', - optional: false, nullable: false, - }, - ratio: { - type: 'number', - optional: false, nullable: false, - }, - imageUrl: { - type: 'string', - optional: false, nullable: false, - format: 'url', - }, - dayOfWeek: { - type: 'integer', - optional: false, nullable: false, - }, - }, - }, - }, - notesPerOneAd: { - type: 'number', - optional: false, nullable: false, - default: 0, - }, - requireSetup: { - type: 'boolean', - optional: false, nullable: false, - example: false, - }, - enableEmail: { - type: 'boolean', - optional: false, nullable: false, - }, - enableServiceWorker: { - type: 'boolean', - optional: false, nullable: false, - }, - translatorAvailable: { - type: 'boolean', - optional: false, nullable: false, - }, - proxyAccountName: { - type: 'string', - optional: false, nullable: true, - }, - mediaProxy: { - type: 'string', - optional: false, nullable: false, - }, - features: { - type: 'object', - optional: true, nullable: false, - properties: { - registration: { - type: 'boolean', - optional: false, nullable: false, - }, - localTimeline: { - type: 'boolean', - optional: false, nullable: false, - }, - globalTimeline: { - type: 'boolean', - optional: false, nullable: false, - }, - hcaptcha: { - type: 'boolean', - optional: false, nullable: false, - }, - recaptcha: { - type: 'boolean', - optional: false, nullable: false, - }, - objectStorage: { - type: 'boolean', - optional: false, nullable: false, - }, - serviceWorker: { - type: 'boolean', - optional: false, nullable: false, - }, - miauth: { - type: 'boolean', - optional: true, nullable: false, - default: true, - }, - }, - }, - backgroundImageUrl: { - type: 'string', - optional: false, nullable: true, - }, - impressumUrl: { - type: 'string', - optional: false, nullable: true, - }, - logoImageUrl: { - type: 'string', - optional: false, nullable: true, - }, - privacyPolicyUrl: { - type: 'string', - optional: false, nullable: true, - }, - serverRules: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'string', - }, - }, - themeColor: { - type: 'string', - optional: false, nullable: true, - }, - }, + oneOf: [ + { type: 'object', ref: 'MetaLite' }, + { type: 'object', ref: 'MetaDetailed' }, + ], }, } as const; @@ -318,118 +32,10 @@ export const paramDef = { @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( - @Inject(DI.config) - private config: Config, - - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - - @Inject(DI.adsRepository) - private adsRepository: AdsRepository, - - private userEntityService: UserEntityService, - private metaService: MetaService, + private metaEntityService: MetaEntityService, ) { super(meta, paramDef, async (ps, me) => { - const instance = await this.metaService.fetch(true); - - const ads = await this.adsRepository.createQueryBuilder('ads') - .where('ads.expiresAt > :now', { now: new Date() }) - .andWhere('ads.startsAt <= :now', { now: new Date() }) - .andWhere(new Brackets(qb => { - // 曜日のビットフラグを確認する - qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << new Date().getDay() }) - .orWhere('ads.dayOfWeek = 0'); - })) - .getMany(); - - const response: any = { - maintainerName: instance.maintainerName, - maintainerEmail: instance.maintainerEmail, - - version: this.config.version, - - name: instance.name, - shortName: instance.shortName, - uri: this.config.url, - description: instance.description, - langs: instance.langs, - tosUrl: instance.termsOfServiceUrl, - repositoryUrl: instance.repositoryUrl, - feedbackUrl: instance.feedbackUrl, - impressumUrl: instance.impressumUrl, - privacyPolicyUrl: instance.privacyPolicyUrl, - disableRegistration: instance.disableRegistration, - emailRequiredForSignup: instance.emailRequiredForSignup, - enableHcaptcha: instance.enableHcaptcha, - hcaptchaSiteKey: instance.hcaptchaSiteKey, - enableMcaptcha: instance.enableMcaptcha, - mcaptchaSiteKey: instance.mcaptchaSitekey, - mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl, - enableRecaptcha: instance.enableRecaptcha, - recaptchaSiteKey: instance.recaptchaSiteKey, - enableTurnstile: instance.enableTurnstile, - turnstileSiteKey: instance.turnstileSiteKey, - swPublickey: instance.swPublicKey, - themeColor: instance.themeColor, - mascotImageUrl: instance.mascotImageUrl, - bannerUrl: instance.bannerUrl, - infoImageUrl: instance.infoImageUrl, - serverErrorImageUrl: instance.serverErrorImageUrl, - notFoundImageUrl: instance.notFoundImageUrl, - iconUrl: instance.iconUrl, - backgroundImageUrl: instance.backgroundImageUrl, - logoImageUrl: instance.logoImageUrl, - maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, - // クライアントの手間を減らすためあらかじめJSONに変換しておく - defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null, - defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null, - ads: ads.map(ad => ({ - id: ad.id, - url: ad.url, - place: ad.place, - ratio: ad.ratio, - imageUrl: ad.imageUrl, - dayOfWeek: ad.dayOfWeek, - })), - notesPerOneAd: instance.notesPerOneAd, - enableEmail: instance.enableEmail, - enableServiceWorker: instance.enableServiceWorker, - - translatorAvailable: instance.deeplAuthKey != null, - - serverRules: instance.serverRules, - - policies: { ...DEFAULT_POLICIES, ...instance.policies }, - - mediaProxy: this.config.mediaProxy, - - ...(ps.detail ? { - cacheRemoteFiles: instance.cacheRemoteFiles, - cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles, - requireSetup: (await this.usersRepository.countBy({ - host: IsNull(), - })) === 0, - } : {}), - }; - - if (ps.detail) { - const proxyAccount = instance.proxyAccountId ? await this.userEntityService.pack(instance.proxyAccountId).catch(() => null) : null; - - response.proxyAccountName = proxyAccount ? proxyAccount.username : null; - response.features = { - registration: !instance.disableRegistration, - emailRequiredForSignup: instance.emailRequiredForSignup, - hcaptcha: instance.enableHcaptcha, - recaptcha: instance.enableRecaptcha, - turnstile: instance.enableTurnstile, - objectStorage: instance.useObjectStorage, - serviceWorker: instance.enableServiceWorker, - miauth: true, - }; - } - - return response; + return ps.detail ? await this.metaEntityService.packDetailed() : await this.metaEntityService.pack(); }); } } diff --git a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts index cac8f41f8e..fc9a8f3ebe 100644 --- a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts +++ b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/mute/create.ts b/packages/backend/src/server/api/endpoints/mute/create.ts index 49c2b5707d..e39c133b43 100644 --- a/packages/backend/src/server/api/endpoints/mute/create.ts +++ b/packages/backend/src/server/api/endpoints/mute/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -83,7 +83,7 @@ export default class extends Endpoint { // eslint- }); // Check if already muting - const exist = await this.mutingsRepository.exist({ + const exist = await this.mutingsRepository.exists({ where: { muterId: muter.id, muteeId: mutee.id, diff --git a/packages/backend/src/server/api/endpoints/mute/delete.ts b/packages/backend/src/server/api/endpoints/mute/delete.ts index a3fd2dd82f..d11832858e 100644 --- a/packages/backend/src/server/api/endpoints/mute/delete.ts +++ b/packages/backend/src/server/api/endpoints/mute/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/mute/list.ts b/packages/backend/src/server/api/endpoints/mute/list.ts index 2a41182ebc..23204f2829 100644 --- a/packages/backend/src/server/api/endpoints/mute/list.ts +++ b/packages/backend/src/server/api/endpoints/mute/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/my/apps.ts b/packages/backend/src/server/api/endpoints/my/apps.ts index 1b70b85b07..c04a92626f 100644 --- a/packages/backend/src/server/api/endpoints/my/apps.ts +++ b/packages/backend/src/server/api/endpoints/my/apps.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes.ts b/packages/backend/src/server/api/endpoints/notes.ts index 95ba5e8b64..9938322a2a 100644 --- a/packages/backend/src/server/api/endpoints/notes.ts +++ b/packages/backend/src/server/api/endpoints/notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/children.ts b/packages/backend/src/server/api/endpoints/notes/children.ts index 1e569d9806..0c6533d336 100644 --- a/packages/backend/src/server/api/endpoints/notes/children.ts +++ b/packages/backend/src/server/api/endpoints/notes/children.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/clips.ts b/packages/backend/src/server/api/endpoints/notes/clips.ts index 677c0ea307..29cab9f212 100644 --- a/packages/backend/src/server/api/endpoints/notes/clips.ts +++ b/packages/backend/src/server/api/endpoints/notes/clips.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts index b94a019da4..d13fd5e82e 100644 --- a/packages/backend/src/server/api/endpoints/notes/conversation.ts +++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/create.test.ts b/packages/backend/src/server/api/endpoints/notes/create.test.ts index 3228bbd014..6097f9c562 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.test.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.test.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 29a0f7418c..bfb9214439 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -17,6 +17,9 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { NoteCreateService } from '@/core/NoteCreateService.js'; import { DI } from '@/di-symbols.js'; import { isPureRenote } from '@/misc/is-pure-renote.js'; +import { MetaService } from '@/core/MetaService.js'; +import { UtilityService } from '@/core/UtilityService.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -82,6 +85,12 @@ export const meta = { id: '3ac74a84-8fd5-4bb0-870f-01804f82ce15', }, + cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility: { + message: 'You cannot reply to a specified visibility note with extended visibility.', + code: 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY', + id: 'ed940410-535c-4d5e-bfa3-af798671e93c', + }, + cannotCreateAlreadyExpiredPoll: { message: 'Poll is already expired.', code: 'CANNOT_CREATE_ALREADY_EXPIRED_POLL', @@ -111,6 +120,18 @@ export const meta = { code: 'CANNOT_RENOTE_OUTSIDE_OF_CHANNEL', id: '33510210-8452-094c-6227-4a6c05d99f00', }, + + containsProhibitedWords: { + message: 'Cannot post because it contains prohibited words.', + code: 'CONTAINS_PROHIBITED_WORDS', + id: 'aa6e01d3-a85c-669d-758a-76aab43af334', + }, + + containsTooManyMentions: { + message: 'Cannot post because it exceeds the allowed number of mentions.', + code: 'CONTAINS_TOO_MANY_MENTIONS', + id: '4de0363a-3046-481b-9b0f-feff3e211025', + }, }, } as const; @@ -260,7 +281,7 @@ export default class extends Endpoint { // eslint- // Check blocking if (renote.userId !== me.id) { - const blockExist = await this.blockingsRepository.exist({ + const blockExist = await this.blockingsRepository.exists({ where: { blockerId: renote.userId, blockeeId: me.id, @@ -304,11 +325,13 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.cannotReplyToPureRenote); } else if (!await this.noteEntityService.isVisibleForMe(reply, me.id)) { throw new ApiError(meta.errors.cannotReplyToInvisibleNote); + } else if (reply.visibility === 'specified' && ps.visibility !== 'specified') { + throw new ApiError(meta.errors.cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility); } // Check blocking if (reply.userId !== me.id) { - const blockExist = await this.blockingsRepository.exist({ + const blockExist = await this.blockingsRepository.exists({ where: { blockerId: reply.userId, blockeeId: me.id, @@ -340,31 +363,43 @@ export default class extends Endpoint { // eslint- } // 投稿を作成 - const note = await this.noteCreateService.create(me, { - createdAt: new Date(), - files: files, - poll: ps.poll ? { - choices: ps.poll.choices, - multiple: ps.poll.multiple ?? false, - expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null, - } : undefined, - text: ps.text ?? undefined, - reply, - renote, - cw: ps.cw, - localOnly: ps.localOnly, - reactionAcceptance: ps.reactionAcceptance, - visibility: ps.visibility, - visibleUsers, - channel, - apMentions: ps.noExtractMentions ? [] : undefined, - apHashtags: ps.noExtractHashtags ? [] : undefined, - apEmojis: ps.noExtractEmojis ? [] : undefined, - }); + try { + const note = await this.noteCreateService.create(me, { + createdAt: new Date(), + files: files, + poll: ps.poll ? { + choices: ps.poll.choices, + multiple: ps.poll.multiple ?? false, + expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null, + } : undefined, + text: ps.text ?? undefined, + reply, + renote, + cw: ps.cw, + localOnly: ps.localOnly, + reactionAcceptance: ps.reactionAcceptance, + visibility: ps.visibility, + visibleUsers, + channel, + apMentions: ps.noExtractMentions ? [] : undefined, + apHashtags: ps.noExtractHashtags ? [] : undefined, + apEmojis: ps.noExtractEmojis ? [] : undefined, + }); - return { - createdNote: await this.noteEntityService.pack(note, me), - }; + return { + createdNote: await this.noteEntityService.pack(note, me), + }; + } catch (e) { + // TODO: 他のErrorもここでキャッチしてエラーメッセージを当てるようにしたい + if (e instanceof IdentifiableError) { + if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') { + throw new ApiError(meta.errors.containsProhibitedWords); + } else if (e.id === '9f466dab-c856-48cd-9e65-ff90ff750580') { + throw new ApiError(meta.errors.containsTooManyMentions); + } + } + throw e; + } }); } } diff --git a/packages/backend/src/server/api/endpoints/notes/delete.ts b/packages/backend/src/server/api/endpoints/notes/delete.ts index 55aaaf4f78..9d7c9a9081 100644 --- a/packages/backend/src/server/api/endpoints/notes/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts index ed3dce7f35..804071b3d4 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -67,7 +67,7 @@ export default class extends Endpoint { // eslint- }); // if already favorited - const exist = await this.noteFavoritesRepository.exist({ + const exist = await this.noteFavoritesRepository.exists({ where: { noteId: note.id, userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts index 8ab9775a2c..2036facdba 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/featured.ts b/packages/backend/src/server/api/endpoints/notes/featured.ts index 31b8d1ad2d..dcd971360d 100644 --- a/packages/backend/src/server/api/endpoints/notes/featured.ts +++ b/packages/backend/src/server/api/endpoints/notes/featured.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index 68fefa5b58..258a0bfb8f 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 01adfec7d3..5acc9706d3 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index 3fd4dc83fb..be82b5a8a7 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/mentions.ts b/packages/backend/src/server/api/endpoints/notes/mentions.ts index 323c6c946b..5558dd3a8b 100644 --- a/packages/backend/src/server/api/endpoints/notes/mentions.ts +++ b/packages/backend/src/server/api/endpoints/notes/mentions.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts index 90af29a695..ba38573065 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts index 734c3f0e63..a91c506afd 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/reactions.ts b/packages/backend/src/server/api/endpoints/notes/reactions.ts index a2c1778199..a0a1fd9728 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts index ff22ef1322..b9899608bf 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts b/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts index b43ab044fa..e6c3bbbcf5 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/renotes.ts b/packages/backend/src/server/api/endpoints/notes/renotes.ts index 9f16181a30..ffe1ee6eb8 100644 --- a/packages/backend/src/server/api/endpoints/notes/renotes.ts +++ b/packages/backend/src/server/api/endpoints/notes/renotes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/replies.ts b/packages/backend/src/server/api/endpoints/notes/replies.ts index 70142c9818..5f32332a6a 100644 --- a/packages/backend/src/server/api/endpoints/notes/replies.ts +++ b/packages/backend/src/server/api/endpoints/notes/replies.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts index 0d7aca6621..626ff080c7 100644 --- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts +++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index 4425d4593c..3fe19806e3 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts index 5bb8196543..adcda30a7d 100644 --- a/packages/backend/src/server/api/endpoints/notes/show.ts +++ b/packages/backend/src/server/api/endpoints/notes/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/state.ts b/packages/backend/src/server/api/endpoints/notes/state.ts index 20faea566d..4c1eb86542 100644 --- a/packages/backend/src/server/api/endpoints/notes/state.ts +++ b/packages/backend/src/server/api/endpoints/notes/state.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts index b2cdaa00ac..732d644a29 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts index d3f1787ee4..d94d6cd652 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index e90d6ec198..8b87908bd3 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index 698c37b616..78812351f4 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/unrenote.ts b/packages/backend/src/server/api/endpoints/notes/unrenote.ts index f67e9365fc..73e70cfde4 100644 --- a/packages/backend/src/server/api/endpoints/notes/unrenote.ts +++ b/packages/backend/src/server/api/endpoints/notes/unrenote.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index 71c2b8054e..43877e61ef 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notifications/create.ts b/packages/backend/src/server/api/endpoints/notifications/create.ts index 7c6a979160..7671b58e6b 100644 --- a/packages/backend/src/server/api/endpoints/notifications/create.ts +++ b/packages/backend/src/server/api/endpoints/notifications/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notifications/flush.ts b/packages/backend/src/server/api/endpoints/notifications/flush.ts new file mode 100644 index 0000000000..47c0642fd1 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/notifications/flush.ts @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { NotificationService } from '@/core/NotificationService.js'; + +export const meta = { + tags: ['notifications', 'account'], + + requireCredential: true, + + kind: 'write:notifications', +} as const; + +export const paramDef = { + type: 'object', + properties: {}, + required: [], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private notificationService: NotificationService, + ) { + super(meta, paramDef, async (ps, me) => { + this.notificationService.flushAllNotifications(me.id); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts b/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts index dc092c1f3a..6565125c00 100644 --- a/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts +++ b/packages/backend/src/server/api/endpoints/notifications/mark-all-as-read.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/notifications/test-notification.ts b/packages/backend/src/server/api/endpoints/notifications/test-notification.ts index 8f5f8485c3..50b850a519 100644 --- a/packages/backend/src/server/api/endpoints/notifications/test-notification.ts +++ b/packages/backend/src/server/api/endpoints/notifications/test-notification.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/page-push.ts b/packages/backend/src/server/api/endpoints/page-push.ts index 0a68516586..ce454ab24a 100644 --- a/packages/backend/src/server/api/endpoints/page-push.ts +++ b/packages/backend/src/server/api/endpoints/page-push.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -55,7 +55,7 @@ export default class extends Endpoint { // eslint- var: ps.var, userId: me.id, user: await this.userEntityService.pack(me.id, { id: page.userId }, { - detail: true, + schema: 'UserDetailed', }), }); }); diff --git a/packages/backend/src/server/api/endpoints/pages/create.ts b/packages/backend/src/server/api/endpoints/pages/create.ts index 4c2ef516e5..3a02d359f8 100644 --- a/packages/backend/src/server/api/endpoints/pages/create.ts +++ b/packages/backend/src/server/api/endpoints/pages/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/pages/delete.ts b/packages/backend/src/server/api/endpoints/pages/delete.ts index 1291c0d209..aa2ba75a41 100644 --- a/packages/backend/src/server/api/endpoints/pages/delete.ts +++ b/packages/backend/src/server/api/endpoints/pages/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/pages/featured.ts b/packages/backend/src/server/api/endpoints/pages/featured.ts index 1f43d6606c..a47b69e56e 100644 --- a/packages/backend/src/server/api/endpoints/pages/featured.ts +++ b/packages/backend/src/server/api/endpoints/pages/featured.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/pages/like.ts b/packages/backend/src/server/api/endpoints/pages/like.ts index 8c18982b50..11eed693ad 100644 --- a/packages/backend/src/server/api/endpoints/pages/like.ts +++ b/packages/backend/src/server/api/endpoints/pages/like.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -70,7 +70,7 @@ export default class extends Endpoint { // eslint- } // if already liked - const exist = await this.pageLikesRepository.exist({ + const exist = await this.pageLikesRepository.exists({ where: { pageId: page.id, userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/pages/show.ts b/packages/backend/src/server/api/endpoints/pages/show.ts index efb0bd0677..e08b832a3f 100644 --- a/packages/backend/src/server/api/endpoints/pages/show.ts +++ b/packages/backend/src/server/api/endpoints/pages/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/pages/unlike.ts b/packages/backend/src/server/api/endpoints/pages/unlike.ts index 7a76cd7408..70c965e0ad 100644 --- a/packages/backend/src/server/api/endpoints/pages/unlike.ts +++ b/packages/backend/src/server/api/endpoints/pages/unlike.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/pages/update.ts b/packages/backend/src/server/api/endpoints/pages/update.ts index aaea1efa87..b8e5e70a25 100644 --- a/packages/backend/src/server/api/endpoints/pages/update.ts +++ b/packages/backend/src/server/api/endpoints/pages/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/ping.ts b/packages/backend/src/server/api/endpoints/ping.ts index ee2fe48834..e218a8f755 100644 --- a/packages/backend/src/server/api/endpoints/ping.ts +++ b/packages/backend/src/server/api/endpoints/ping.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts index 390042c815..784766bcb5 100644 --- a/packages/backend/src/server/api/endpoints/pinned-users.ts +++ b/packages/backend/src/server/api/endpoints/pinned-users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -12,6 +12,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { MetaService } from '@/core/MetaService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DI } from '@/di-symbols.js'; +import { isNotNull } from '@/misc/is-not-null.js'; export const meta = { tags: ['users'], @@ -52,7 +53,7 @@ export default class extends Endpoint { // eslint- host: acct.host ?? IsNull(), }))); - return await this.userEntityService.packMany(users.filter(x => x !== null) as MiUser[], me, { detail: true }); + return await this.userEntityService.packMany(users.filter(isNotNull), me, { schema: 'UserDetailed' }); }); } } diff --git a/packages/backend/src/server/api/endpoints/promo/read.ts b/packages/backend/src/server/api/endpoints/promo/read.ts index f427939a7a..9f7d078014 100644 --- a/packages/backend/src/server/api/endpoints/promo/read.ts +++ b/packages/backend/src/server/api/endpoints/promo/read.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -49,7 +49,7 @@ export default class extends Endpoint { // eslint- throw err; }); - const exist = await this.promoReadsRepository.exist({ + const exist = await this.promoReadsRepository.exists({ where: { noteId: note.id, userId: me.id, diff --git a/packages/backend/src/server/api/endpoints/renote-mute/create.ts b/packages/backend/src/server/api/endpoints/renote-mute/create.ts index 2d853b94f3..39bf0cc428 100644 --- a/packages/backend/src/server/api/endpoints/renote-mute/create.ts +++ b/packages/backend/src/server/api/endpoints/renote-mute/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/renote-mute/delete.ts b/packages/backend/src/server/api/endpoints/renote-mute/delete.ts index f4969896d9..6e037cc07e 100644 --- a/packages/backend/src/server/api/endpoints/renote-mute/delete.ts +++ b/packages/backend/src/server/api/endpoints/renote-mute/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/renote-mute/list.ts b/packages/backend/src/server/api/endpoints/renote-mute/list.ts index 493593ae2d..3be01f989a 100644 --- a/packages/backend/src/server/api/endpoints/renote-mute/list.ts +++ b/packages/backend/src/server/api/endpoints/renote-mute/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/request-reset-password.ts b/packages/backend/src/server/api/endpoints/request-reset-password.ts index f13710e1dd..86fe6a2e6e 100644 --- a/packages/backend/src/server/api/endpoints/request-reset-password.ts +++ b/packages/backend/src/server/api/endpoints/request-reset-password.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/reset-db.ts b/packages/backend/src/server/api/endpoints/reset-db.ts index 0eeee81580..67d5fabd86 100644 --- a/packages/backend/src/server/api/endpoints/reset-db.ts +++ b/packages/backend/src/server/api/endpoints/reset-db.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/reset-password.ts b/packages/backend/src/server/api/endpoints/reset-password.ts index 3a6dc14bcd..9693892637 100644 --- a/packages/backend/src/server/api/endpoints/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/reset-password.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/retention.ts b/packages/backend/src/server/api/endpoints/retention.ts index dac6d65407..4695f32042 100644 --- a/packages/backend/src/server/api/endpoints/retention.ts +++ b/packages/backend/src/server/api/endpoints/retention.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -14,6 +14,32 @@ export const meta = { requireCredential: false, res: { + type: 'array', + items: { + type: 'object', + properties: { + createdAt: { + type: 'string', + format: 'date-time', + }, + users: { + type: 'number', + }, + data: { + type: 'object', + additionalProperties: { + anyOf: [{ + type: 'number', + }], + }, + }, + }, + required: [ + 'createdAt', + 'users', + 'data', + ], + }, }, allowGet: true, diff --git a/packages/backend/src/server/api/endpoints/reversi/cancel-match.ts b/packages/backend/src/server/api/endpoints/reversi/cancel-match.ts index 8edc049500..dd6f273e01 100644 --- a/packages/backend/src/server/api/endpoints/reversi/cancel-match.ts +++ b/packages/backend/src/server/api/endpoints/reversi/cancel-match.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -14,9 +14,6 @@ export const meta = { errors: { }, - - res: { - }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/reversi/games.ts b/packages/backend/src/server/api/endpoints/reversi/games.ts index c1b2ff1702..6b06068727 100644 --- a/packages/backend/src/server/api/endpoints/reversi/games.ts +++ b/packages/backend/src/server/api/endpoints/reversi/games.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/reversi/invitations.ts b/packages/backend/src/server/api/endpoints/reversi/invitations.ts index 0b7107bb0d..5b3b9da75b 100644 --- a/packages/backend/src/server/api/endpoints/reversi/invitations.ts +++ b/packages/backend/src/server/api/endpoints/reversi/invitations.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/reversi/match.ts b/packages/backend/src/server/api/endpoints/reversi/match.ts index f8dee21c4c..aa8b8a7d72 100644 --- a/packages/backend/src/server/api/endpoints/reversi/match.ts +++ b/packages/backend/src/server/api/endpoints/reversi/match.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -30,6 +30,9 @@ export const meta = { }, res: { + type: 'object', + optional: true, + ref: 'ReversiGameDetailed', }, } as const; diff --git a/packages/backend/src/server/api/endpoints/reversi/show-game.ts b/packages/backend/src/server/api/endpoints/reversi/show-game.ts index 86645ea4b4..fc3b96eb51 100644 --- a/packages/backend/src/server/api/endpoints/reversi/show-game.ts +++ b/packages/backend/src/server/api/endpoints/reversi/show-game.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/reversi/surrender.ts b/packages/backend/src/server/api/endpoints/reversi/surrender.ts index c809142e07..75e5372862 100644 --- a/packages/backend/src/server/api/endpoints/reversi/surrender.ts +++ b/packages/backend/src/server/api/endpoints/reversi/surrender.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/reversi/verify.ts b/packages/backend/src/server/api/endpoints/reversi/verify.ts index 5f5af6ce67..981735a3d7 100644 --- a/packages/backend/src/server/api/endpoints/reversi/verify.ts +++ b/packages/backend/src/server/api/endpoints/reversi/verify.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/roles/list.ts b/packages/backend/src/server/api/endpoints/roles/list.ts index d40e937d4e..b087aa242b 100644 --- a/packages/backend/src/server/api/endpoints/roles/list.ts +++ b/packages/backend/src/server/api/endpoints/roles/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/roles/notes.ts b/packages/backend/src/server/api/endpoints/roles/notes.ts index 4ce3fc8908..71f2782a5d 100644 --- a/packages/backend/src/server/api/endpoints/roles/notes.ts +++ b/packages/backend/src/server/api/endpoints/roles/notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/roles/show.ts b/packages/backend/src/server/api/endpoints/roles/show.ts index 6bfe52bb1a..38477c5e8e 100644 --- a/packages/backend/src/server/api/endpoints/roles/show.ts +++ b/packages/backend/src/server/api/endpoints/roles/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/roles/users.ts b/packages/backend/src/server/api/endpoints/roles/users.ts index d304d075b2..85d100ce1c 100644 --- a/packages/backend/src/server/api/endpoints/roles/users.ts +++ b/packages/backend/src/server/api/endpoints/roles/users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -33,11 +33,11 @@ export const meta = { properties: { id: { type: 'string', - format: 'misskey:id' + format: 'misskey:id', }, user: { type: 'object', - ref: 'User' + ref: 'UserDetailed', }, }, required: ['id', 'user'], @@ -94,7 +94,7 @@ export default class extends Endpoint { // eslint- return await Promise.all(assigns.map(async assign => ({ id: assign.id, - user: await this.userEntityService.pack(assign.user!, me, { detail: true }), + user: await this.userEntityService.pack(assign.user!, me, { schema: 'UserDetailed' }), }))); }); } diff --git a/packages/backend/src/server/api/endpoints/server-info.ts b/packages/backend/src/server/api/endpoints/server-info.ts index 079f2d7f1d..c13802eb06 100644 --- a/packages/backend/src/server/api/endpoints/server-info.ts +++ b/packages/backend/src/server/api/endpoints/server-info.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/stats.ts b/packages/backend/src/server/api/endpoints/stats.ts index 05468240d3..1e6983177f 100644 --- a/packages/backend/src/server/api/endpoints/stats.ts +++ b/packages/backend/src/server/api/endpoints/stats.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/sw/register.ts b/packages/backend/src/server/api/endpoints/sw/register.ts index bb50048d94..a9a33149f9 100644 --- a/packages/backend/src/server/api/endpoints/sw/register.ts +++ b/packages/backend/src/server/api/endpoints/sw/register.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -9,6 +9,7 @@ import type { SwSubscriptionsRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { MetaService } from '@/core/MetaService.js'; import { DI } from '@/di-symbols.js'; +import { PushNotificationService } from '@/core/PushNotificationService.js'; export const meta = { tags: ['account'], @@ -66,6 +67,7 @@ export default class extends Endpoint { // eslint- private idService: IdService, private metaService: MetaService, + private pushNotificationService: PushNotificationService, ) { super(meta, paramDef, async (ps, me) => { // if already subscribed @@ -97,6 +99,8 @@ export default class extends Endpoint { // eslint- sendReadMessage: ps.sendReadMessage, }); + this.pushNotificationService.refreshCache(me.id); + return { state: 'subscribed' as const, key: instance.swPublicKey, diff --git a/packages/backend/src/server/api/endpoints/sw/show-registration.ts b/packages/backend/src/server/api/endpoints/sw/show-registration.ts index 15d3df8587..797e4fd34d 100644 --- a/packages/backend/src/server/api/endpoints/sw/show-registration.ts +++ b/packages/backend/src/server/api/endpoints/sw/show-registration.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/sw/unregister.ts b/packages/backend/src/server/api/endpoints/sw/unregister.ts index f00fdd6697..2edf7fab1b 100644 --- a/packages/backend/src/server/api/endpoints/sw/unregister.ts +++ b/packages/backend/src/server/api/endpoints/sw/unregister.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common'; import type { SwSubscriptionsRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { DI } from '@/di-symbols.js'; +import { PushNotificationService } from '@/core/PushNotificationService.js'; export const meta = { tags: ['account'], @@ -29,12 +30,18 @@ export default class extends Endpoint { // eslint- constructor( @Inject(DI.swSubscriptionsRepository) private swSubscriptionsRepository: SwSubscriptionsRepository, + + private pushNotificationService: PushNotificationService, ) { super(meta, paramDef, async (ps, me) => { await this.swSubscriptionsRepository.delete({ ...(me ? { userId: me.id } : {}), endpoint: ps.endpoint, }); + + if (me) { + this.pushNotificationService.refreshCache(me.id); + } }); } } diff --git a/packages/backend/src/server/api/endpoints/sw/update-registration.ts b/packages/backend/src/server/api/endpoints/sw/update-registration.ts index 7bf59784a2..839a07c770 100644 --- a/packages/backend/src/server/api/endpoints/sw/update-registration.ts +++ b/packages/backend/src/server/api/endpoints/sw/update-registration.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common'; import type { SwSubscriptionsRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { DI } from '@/di-symbols.js'; +import { PushNotificationService } from '@/core/PushNotificationService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -58,6 +59,8 @@ export default class extends Endpoint { // eslint- constructor( @Inject(DI.swSubscriptionsRepository) private swSubscriptionsRepository: SwSubscriptionsRepository, + + private pushNotificationService: PushNotificationService, ) { super(meta, paramDef, async (ps, me) => { const swSubscription = await this.swSubscriptionsRepository.findOneBy({ @@ -77,6 +80,8 @@ export default class extends Endpoint { // eslint- sendReadMessage: swSubscription.sendReadMessage, }); + this.pushNotificationService.refreshCache(me.id); + return { userId: swSubscription.userId, endpoint: swSubscription.endpoint, diff --git a/packages/backend/src/server/api/endpoints/test.ts b/packages/backend/src/server/api/endpoints/test.ts index 949867c572..9231f0ab94 100644 --- a/packages/backend/src/server/api/endpoints/test.ts +++ b/packages/backend/src/server/api/endpoints/test.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -18,24 +18,28 @@ export const meta = { properties: { id: { type: 'string', - format: 'misskey:id' + format: 'misskey:id', + optional: true, nullable: false, }, required: { type: 'boolean', + optional: false, nullable: false, }, string: { type: 'string', + optional: true, nullable: false, }, default: { type: 'string', + optional: true, nullable: false, }, nullableDefault: { type: 'string', default: 'hello', - nullable: true, + optional: true, nullable: true, }, - } - } + }, + }, } as const; export const paramDef = { diff --git a/packages/backend/src/server/api/endpoints/username/available.ts b/packages/backend/src/server/api/endpoints/username/available.ts index e37df62c0c..affb0996f1 100644 --- a/packages/backend/src/server/api/endpoints/username/available.ts +++ b/packages/backend/src/server/api/endpoints/username/available.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users.ts b/packages/backend/src/server/api/endpoints/users.ts index 8dc5841314..e845853017 100644 --- a/packages/backend/src/server/api/endpoints/users.ts +++ b/packages/backend/src/server/api/endpoints/users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -89,7 +89,7 @@ export default class extends Endpoint { // eslint- const users = await query.getMany(); - return await this.userEntityService.packMany(users, me, { detail: true }); + return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' }); }); } } diff --git a/packages/backend/src/server/api/endpoints/users/achievements.ts b/packages/backend/src/server/api/endpoints/users/achievements.ts index 3a584a819a..f7139b3684 100644 --- a/packages/backend/src/server/api/endpoints/users/achievements.ts +++ b/packages/backend/src/server/api/endpoints/users/achievements.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/clips.ts b/packages/backend/src/server/api/endpoints/users/clips.ts index 725e07db39..7f7d2ea8cc 100644 --- a/packages/backend/src/server/api/endpoints/users/clips.ts +++ b/packages/backend/src/server/api/endpoints/users/clips.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/featured-notes.ts b/packages/backend/src/server/api/endpoints/users/featured-notes.ts index 7243aa3b3e..e01f19ba7a 100644 --- a/packages/backend/src/server/api/endpoints/users/featured-notes.ts +++ b/packages/backend/src/server/api/endpoints/users/featured-notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/flashs.ts b/packages/backend/src/server/api/endpoints/users/flashs.ts index 18026dcefb..e5ea450215 100644 --- a/packages/backend/src/server/api/endpoints/users/flashs.ts +++ b/packages/backend/src/server/api/endpoints/users/flashs.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts index 5706e46b96..7ce7734f53 100644 --- a/packages/backend/src/server/api/endpoints/users/followers.ts +++ b/packages/backend/src/server/api/endpoints/users/followers.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -101,7 +101,7 @@ export default class extends Endpoint { // eslint- if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { - const isFollowing = await this.followingsRepository.exist({ + const isFollowing = await this.followingsRepository.exists({ where: { followeeId: user.id, followerId: me.id, diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts index 794fb04f10..5d52ebba76 100644 --- a/packages/backend/src/server/api/endpoints/users/following.ts +++ b/packages/backend/src/server/api/endpoints/users/following.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -109,7 +109,7 @@ export default class extends Endpoint { // eslint- if (me == null) { throw new ApiError(meta.errors.forbidden); } else if (me.id !== user.id) { - const isFollowing = await this.followingsRepository.exist({ + const isFollowing = await this.followingsRepository.exists({ where: { followeeId: user.id, followerId: me.id, diff --git a/packages/backend/src/server/api/endpoints/users/gallery/posts.ts b/packages/backend/src/server/api/endpoints/users/gallery/posts.ts index 757af98e00..553886374c 100644 --- a/packages/backend/src/server/api/endpoints/users/gallery/posts.ts +++ b/packages/backend/src/server/api/endpoints/users/gallery/posts.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts index d6fb65cecb..02aa037466 100644 --- a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts +++ b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -122,7 +122,7 @@ export default class extends Endpoint { // eslint- // Make replies object (includes weights) const repliesObj = await Promise.all(topRepliedUsers.map(async (user) => ({ - user: await this.userEntityService.pack(user, me, { detail: true }), + user: await this.userEntityService.pack(user, me, { schema: 'UserDetailed' }), weight: repliedUsers[user] / peak, }))); diff --git a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts index fa2e3338b8..e2db71c5c7 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -90,7 +90,7 @@ export default class extends Endpoint { // eslint- private roleService: RoleService, ) { super(meta, paramDef, async (ps, me) => { - const listExist = await this.userListsRepository.exist({ + const listExist = await this.userListsRepository.exists({ where: { id: ps.listId, isPublic: true, @@ -121,7 +121,7 @@ export default class extends Endpoint { // eslint- }); if (currentUser.id !== me.id) { - const blockExist = await this.blockingsRepository.exist({ + const blockExist = await this.blockingsRepository.exists({ where: { blockerId: currentUser.id, blockeeId: me.id, @@ -132,7 +132,7 @@ export default class extends Endpoint { // eslint- } } - const exist = await this.userListMembershipsRepository.exist({ + const exist = await this.userListMembershipsRepository.exists({ where: { userListId: userList.id, userId: currentUser.id, diff --git a/packages/backend/src/server/api/endpoints/users/lists/create.ts b/packages/backend/src/server/api/endpoints/users/lists/create.ts index e86e4c0ded..952580e639 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/create.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/create.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/lists/delete.ts b/packages/backend/src/server/api/endpoints/users/lists/delete.ts index 763f5afd9d..dc0d28a0eb 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/delete.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/delete.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/lists/favorite.ts b/packages/backend/src/server/api/endpoints/users/lists/favorite.ts index 864cdc2ee0..fd142d5a01 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/favorite.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/favorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -47,7 +47,7 @@ export default class extends Endpoint { private idService: IdService, ) { super(meta, paramDef, async (ps, me) => { - const userListExist = await this.userListsRepository.exist({ + const userListExist = await this.userListsRepository.exists({ where: { id: ps.listId, isPublic: true, @@ -58,7 +58,7 @@ export default class extends Endpoint { throw new ApiError(meta.errors.noSuchList); } - const exist = await this.userListFavoritesRepository.exist({ + const exist = await this.userListFavoritesRepository.exists({ where: { userId: me.id, userListId: ps.listId, diff --git a/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts b/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts index 985141515e..6d6e8d34ea 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -46,7 +46,7 @@ export const meta = { }, user: { type: 'object', - ref: 'User', + ref: 'UserLite', }, withReplies: { type: 'boolean', diff --git a/packages/backend/src/server/api/endpoints/users/lists/list.ts b/packages/backend/src/server/api/endpoints/users/lists/list.ts index 0e86dd3a68..4241ef1cd0 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/list.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/lists/pull.ts b/packages/backend/src/server/api/endpoints/users/lists/pull.ts index e90122224c..94f06f3bea 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/pull.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/pull.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/lists/push.ts b/packages/backend/src/server/api/endpoints/users/lists/push.ts index c4ceec575b..c717b3959c 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/push.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/push.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -104,7 +104,7 @@ export default class extends Endpoint { // eslint- // Check blocking if (user.id !== me.id) { - const blockExist = await this.blockingsRepository.exist({ + const blockExist = await this.blockingsRepository.exists({ where: { blockerId: user.id, blockeeId: me.id, @@ -115,7 +115,7 @@ export default class extends Endpoint { // eslint- } } - const exist = await this.userListMembershipsRepository.exist({ + const exist = await this.userListMembershipsRepository.exists({ where: { userListId: userList.id, userId: user.id, diff --git a/packages/backend/src/server/api/endpoints/users/lists/show.ts b/packages/backend/src/server/api/endpoints/users/lists/show.ts index df44870b04..8756801fe4 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/show.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -74,7 +74,7 @@ export default class extends Endpoint { userListId: ps.listId, }); if (me !== null) { - additionalProperties.isLiked = await this.userListFavoritesRepository.exist({ + additionalProperties.isLiked = await this.userListFavoritesRepository.exists({ where: { userId: me.id, userListId: ps.listId, diff --git a/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts b/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts index d51d57343e..3f4bd5af8c 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -45,7 +45,7 @@ export default class extends Endpoint { private userListFavoritesRepository: UserListFavoritesRepository, ) { super(meta, paramDef, async (ps, me) => { - const userListExist = await this.userListsRepository.exist({ + const userListExist = await this.userListsRepository.exists({ where: { id: ps.listId, isPublic: true, diff --git a/packages/backend/src/server/api/endpoints/users/lists/update-membership.ts b/packages/backend/src/server/api/endpoints/users/lists/update-membership.ts index b69465b940..3948ae1685 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/update-membership.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/update-membership.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/lists/update.ts b/packages/backend/src/server/api/endpoints/users/lists/update.ts index eb6cfbaf26..a38f84d7b0 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/update.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/update.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index b485126ed8..cc76c12f1d 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/pages.ts b/packages/backend/src/server/api/endpoints/users/pages.ts index cf2f274c70..bb7de0e0b5 100644 --- a/packages/backend/src/server/api/endpoints/users/pages.ts +++ b/packages/backend/src/server/api/endpoints/users/pages.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index 372ab80c4c..aca883a052 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -9,6 +9,9 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { QueryService } from '@/core/QueryService.js'; import { NoteReactionEntityService } from '@/core/entities/NoteReactionEntityService.js'; import { DI } from '@/di-symbols.js'; +import { CacheService } from '@/core/CacheService.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { RoleService } from '@/core/RoleService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -34,6 +37,11 @@ export const meta = { code: 'REACTIONS_NOT_PUBLIC', id: '673a7dd2-6924-1093-e0c0-e68456ceae5c', }, + isRemoteUser: { + message: 'Currently unavailable to display reactions of remote users. See https://github.com/misskey-dev/misskey/issues/12964', + code: 'IS_REMOTE_USER', + id: '6b95fa98-8cf9-2350-e284-f0ffdb54a805', + }, }, } as const; @@ -59,14 +67,24 @@ export default class extends Endpoint { // eslint- @Inject(DI.noteReactionsRepository) private noteReactionsRepository: NoteReactionsRepository, + private cacheService: CacheService, + private userEntityService: UserEntityService, private noteReactionEntityService: NoteReactionEntityService, private queryService: QueryService, + private roleService: RoleService, ) { super(meta, paramDef, async (ps, me) => { - const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId }); + const iAmModerator = me ? await this.roleService.isModerator(me) : false; // Moderators can see reactions of all users + if (!iAmModerator) { + const user = await this.cacheService.findUserById(ps.userId); + if (this.userEntityService.isRemoteUser(user)) { + throw new ApiError(meta.errors.isRemoteUser); + } - if ((me == null || me.id !== ps.userId) && !profile.publicReactions) { - throw new ApiError(meta.errors.reactionsNotPublic); + const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId }); + if ((me == null || me.id !== ps.userId) && !profile.publicReactions) { + throw new ApiError(meta.errors.reactionsNotPublic); + } } const query = this.queryService.makePaginationQuery(this.noteReactionsRepository.createQueryBuilder('reaction'), @@ -80,7 +98,7 @@ export default class extends Endpoint { // eslint- .limit(ps.limit) .getMany(); - return await Promise.all(reactions.map(reaction => this.noteReactionEntityService.pack(reaction, me, { withNote: true }))); + return await this.noteReactionEntityService.packMany(reactions, me, { withNote: true }); }); } } diff --git a/packages/backend/src/server/api/endpoints/users/recommendation.ts b/packages/backend/src/server/api/endpoints/users/recommendation.ts index 1b30e99b15..5b3b4527f7 100644 --- a/packages/backend/src/server/api/endpoints/users/recommendation.ts +++ b/packages/backend/src/server/api/endpoints/users/recommendation.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -76,7 +76,7 @@ export default class extends Endpoint { // eslint- const users = await query.limit(ps.limit).offset(ps.offset).getMany(); - return await this.userEntityService.packMany(users, me, { detail: true }); + return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' }); }); } } diff --git a/packages/backend/src/server/api/endpoints/users/relation.ts b/packages/backend/src/server/api/endpoints/users/relation.ts index 26b61c9fb2..6a5b2262fa 100644 --- a/packages/backend/src/server/api/endpoints/users/relation.ts +++ b/packages/backend/src/server/api/endpoints/users/relation.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts index 508497ccfb..1750dd6206 100644 --- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts +++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts index 4bf25d9fbb..7b3bdab327 100644 --- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -131,7 +131,7 @@ export default class extends Endpoint { // eslint- .getMany(); } - return await this.userEntityService.packMany(users, me, { detail: !!ps.detail }); + return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' }); }); } } diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts index 32b5c12372..df9d9f6312 100644 --- a/packages/backend/src/server/api/endpoints/users/search.ts +++ b/packages/backend/src/server/api/endpoints/users/search.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -141,7 +141,7 @@ export default class extends Endpoint { // eslint- } } - return await this.userEntityService.packMany(users, me, { detail: ps.detail }); + return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' }); }); } } diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts index 389497301d..bd81989cb9 100644 --- a/packages/backend/src/server/api/endpoints/users/show.ts +++ b/packages/backend/src/server/api/endpoints/users/show.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -116,7 +116,7 @@ export default class extends Endpoint { // eslint- } return await Promise.all(_users.map(u => this.userEntityService.pack(u, me, { - detail: true, + schema: 'UserDetailed', }))); } else { // Lookup user @@ -146,7 +146,7 @@ export default class extends Endpoint { // eslint- } return await this.userEntityService.pack(user, me, { - detail: true, + schema: 'UserDetailed', }); } }); diff --git a/packages/backend/src/server/api/endpoints/users/update-memo.ts b/packages/backend/src/server/api/endpoints/users/update-memo.ts index b3f67815ef..5a10de0c40 100644 --- a/packages/backend/src/server/api/endpoints/users/update-memo.ts +++ b/packages/backend/src/server/api/endpoints/users/update-memo.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/error.ts b/packages/backend/src/server/api/error.ts index 6506565a0d..2f8322a568 100644 --- a/packages/backend/src/server/api/error.ts +++ b/packages/backend/src/server/api/error.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/openapi/OpenApiServerService.ts b/packages/backend/src/server/api/openapi/OpenApiServerService.ts index cb22d0f7c9..5210e4d2bc 100644 --- a/packages/backend/src/server/api/openapi/OpenApiServerService.ts +++ b/packages/backend/src/server/api/openapi/OpenApiServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/openapi/errors.ts b/packages/backend/src/server/api/openapi/errors.ts index 84c3c638fa..7c50122f90 100644 --- a/packages/backend/src/server/api/openapi/errors.ts +++ b/packages/backend/src/server/api/openapi/errors.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 971a6116bf..7679a9b464 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -1,14 +1,14 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ import type { Config } from '@/config.js'; import endpoints, { IEndpoint } from '../endpoints.js'; import { errors as basicErrors } from './errors.js'; -import { schemas, convertSchemaToOpenApiSchema } from './schemas.js'; +import { getSchemas, convertSchemaToOpenApiSchema } from './schemas.js'; -export function genOpenapiSpec(config: Config) { +export function genOpenapiSpec(config: Config, includeSelfRef = false) { const spec = { openapi: '3.1.0', @@ -30,7 +30,7 @@ export function genOpenapiSpec(config: Config) { paths: {} as any, components: { - schemas: schemas, + schemas: getSchemas(includeSelfRef), securitySchemes: { bearerAuth: { @@ -56,7 +56,7 @@ export function genOpenapiSpec(config: Config) { } } - const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res') : {}; + const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res', includeSelfRef) : {}; let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n'; @@ -71,7 +71,7 @@ export function genOpenapiSpec(config: Config) { } const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json'; - const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param') }; + const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param', false) }; if (endpoint.meta.requireFile) { schema.properties = { diff --git a/packages/backend/src/server/api/openapi/schemas.ts b/packages/backend/src/server/api/openapi/schemas.ts index a862a7b742..eb854a7141 100644 --- a/packages/backend/src/server/api/openapi/schemas.ts +++ b/packages/backend/src/server/api/openapi/schemas.ts @@ -1,15 +1,15 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ import type { Schema } from '@/misc/json-schema.js'; import { refs } from '@/misc/json-schema.js'; -export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res') { +export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res', includeSelfRef: boolean): any { // optional, nullable, refはスキーマ定義に含まれないので分離しておく // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { optional, nullable, ref, ...res }: any = schema; + const { optional, nullable, ref, selfRef, ...res }: any = schema; if (schema.type === 'object' && schema.properties) { if (type === 'res') { @@ -21,20 +21,20 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're } for (const k of Object.keys(schema.properties)) { - res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type); + res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type, includeSelfRef); } } if (schema.type === 'array' && schema.items) { - res.items = convertSchemaToOpenApiSchema(schema.items, type); + res.items = convertSchemaToOpenApiSchema(schema.items, type, includeSelfRef); } for (const o of ['anyOf', 'oneOf', 'allOf'] as const) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type)); + if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type, includeSelfRef)); } - if (type === 'res' && schema.ref) { + if (type === 'res' && schema.ref && (!schema.selfRef || includeSelfRef)) { const $ref = `#/components/schemas/${schema.ref}`; if (schema.nullable || schema.optional) { res.allOf = [{ $ref }]; @@ -54,35 +54,37 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're return res; } -export const schemas = { - Error: { - type: 'object', - properties: { - error: { - type: 'object', - description: 'An error object.', - properties: { - code: { - type: 'string', - description: 'An error code. Unique within the endpoint.', - }, - message: { - type: 'string', - description: 'An error message.', - }, - id: { - type: 'string', - format: 'uuid', - description: 'An error ID. This ID is static.', +export function getSchemas(includeSelfRef: boolean) { + return { + Error: { + type: 'object', + properties: { + error: { + type: 'object', + description: 'An error object.', + properties: { + code: { + type: 'string', + description: 'An error code. Unique within the endpoint.', + }, + message: { + type: 'string', + description: 'An error message.', + }, + id: { + type: 'string', + format: 'uuid', + description: 'An error ID. This ID is static.', + }, }, + required: ['code', 'id', 'message'], }, - required: ['code', 'id', 'message'], }, + required: ['error'], }, - required: ['error'], - }, - ...Object.fromEntries( - Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res')]), - ), -}; + ...Object.fromEntries( + Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res', includeSelfRef)]), + ), + }; +} diff --git a/packages/backend/src/server/api/stream/ChannelsService.ts b/packages/backend/src/server/api/stream/ChannelsService.ts index 998429dd0a..253409259f 100644 --- a/packages/backend/src/server/api/stream/ChannelsService.ts +++ b/packages/backend/src/server/api/stream/ChannelsService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts index a89fbcc5e5..41c0feccc7 100644 --- a/packages/backend/src/server/api/stream/Connection.ts +++ b/packages/backend/src/server/api/stream/Connection.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts index 80df3803eb..44a143538b 100644 --- a/packages/backend/src/server/api/stream/channel.ts +++ b/packages/backend/src/server/api/stream/channel.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/admin.ts b/packages/backend/src/server/api/stream/channels/admin.ts index b8f369ce84..92b6d2ac04 100644 --- a/packages/backend/src/server/api/stream/channels/admin.ts +++ b/packages/backend/src/server/api/stream/channels/admin.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts index 200db8eb0e..135d162e63 100644 --- a/packages/backend/src/server/api/stream/channels/antenna.ts +++ b/packages/backend/src/server/api/stream/channels/antenna.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/channel.ts b/packages/backend/src/server/api/stream/channels/channel.ts index 20275249b8..90ee1ecda5 100644 --- a/packages/backend/src/server/api/stream/channels/channel.ts +++ b/packages/backend/src/server/api/stream/channels/channel.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/drive.ts b/packages/backend/src/server/api/stream/channels/drive.ts index 4bf34a72c9..0d9b486305 100644 --- a/packages/backend/src/server/api/stream/channels/drive.ts +++ b/packages/backend/src/server/api/stream/channels/drive.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index 8df13da8a9..723b89c908 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/hashtag.ts b/packages/backend/src/server/api/stream/channels/hashtag.ts index 3d4f2fc528..377b1a0162 100644 --- a/packages/backend/src/server/api/stream/channels/hashtag.ts +++ b/packages/backend/src/server/api/stream/channels/hashtag.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index 6c9f52ba70..f45bf8622e 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -71,7 +71,15 @@ class HomeTimelineChannel extends Channel { } } - if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && !this.withRenotes) return; + // 純粋なリノート(引用リノートでないリノート)の場合 + if (note.renote && note.text == null && (note.fileIds == null || note.fileIds.length === 0) && note.poll == null) { + if (!this.withRenotes) return; + if (note.renote.reply) { + const reply = note.renote.reply; + // 自分のフォローしていないユーザーの visibility: followers な投稿への返信のリノートは弾く + if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return; + } + } // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isUserRelated(note, this.userIdsWhoMeMuting)) return; diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index 957d8b6d41..d67da6f565 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index 888d268d56..43d26124ef 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/main.ts b/packages/backend/src/server/api/stream/channels/main.ts index ab605e3ec5..a12976d69d 100644 --- a/packages/backend/src/server/api/stream/channels/main.ts +++ b/packages/backend/src/server/api/stream/channels/main.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/queue-stats.ts b/packages/backend/src/server/api/stream/channels/queue-stats.ts index 5ceb2c3bbc..061aa76904 100644 --- a/packages/backend/src/server/api/stream/channels/queue-stats.ts +++ b/packages/backend/src/server/api/stream/channels/queue-stats.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/reversi-game.ts b/packages/backend/src/server/api/stream/channels/reversi-game.ts index fb24a29b75..f4a3a09367 100644 --- a/packages/backend/src/server/api/stream/channels/reversi-game.ts +++ b/packages/backend/src/server/api/stream/channels/reversi-game.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/reversi.ts b/packages/backend/src/server/api/stream/channels/reversi.ts index cb4b1b8d5a..3998a0fd36 100644 --- a/packages/backend/src/server/api/stream/channels/reversi.ts +++ b/packages/backend/src/server/api/stream/channels/reversi.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/role-timeline.ts b/packages/backend/src/server/api/stream/channels/role-timeline.ts index b3bbb77dbf..80aab4b35e 100644 --- a/packages/backend/src/server/api/stream/channels/role-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/role-timeline.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/server-stats.ts b/packages/backend/src/server/api/stream/channels/server-stats.ts index 615b6946cc..eb4d8c9992 100644 --- a/packages/backend/src/server/api/stream/channels/server-stats.ts +++ b/packages/backend/src/server/api/stream/channels/server-stats.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts index e0245814c4..f7bb106c03 100644 --- a/packages/backend/src/server/api/stream/channels/user-list.ts +++ b/packages/backend/src/server/api/stream/channels/user-list.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -43,7 +43,7 @@ class UserListChannel extends Channel { this.withRenotes = params.withRenotes ?? true; // Check existence and owner - const listExist = await this.userListsRepository.exist({ + const listExist = await this.userListsRepository.exists({ where: { id: this.listId, userId: this.user!.id, diff --git a/packages/backend/src/server/oauth/OAuth2ProviderService.ts b/packages/backend/src/server/oauth/OAuth2ProviderService.ts index 2253078582..e065c451f1 100644 --- a/packages/backend/src/server/oauth/OAuth2ProviderService.ts +++ b/packages/backend/src/server/oauth/OAuth2ProviderService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/web/ClientLoggerService.ts b/packages/backend/src/server/web/ClientLoggerService.ts index 213266f59c..83d8b5bc38 100644 --- a/packages/backend/src/server/web/ClientLoggerService.ts +++ b/packages/backend/src/server/web/ClientLoggerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index 8e1a89d55f..b1af0c3df6 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -19,6 +19,7 @@ import fastifyView from '@fastify/view'; import fastifyCookie from '@fastify/cookie'; import fastifyProxy from '@fastify/http-proxy'; import vary from 'vary'; +import htmlSafeJsonStringify from 'htmlescape'; import type { Config } from '@/config.js'; import { getNoteSummary } from '@/misc/get-note-summary.js'; import { DI } from '@/di-symbols.js'; @@ -28,12 +29,13 @@ import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, Obj import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { PageEntityService } from '@/core/entities/PageEntityService.js'; +import { MetaEntityService } from '@/core/entities/MetaEntityService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { ClipEntityService } from '@/core/entities/ClipEntityService.js'; import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, MiMeta, NotesRepository, PagesRepository, ReversiGamesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; import type Logger from '@/logger.js'; -import { deepClone } from '@/misc/clone.js'; +import { handleRequestRedirectToOmitSearch } from '@/misc/fastify-hook-handlers.js'; import { bindThis } from '@/decorators.js'; import { FlashEntityService } from '@/core/entities/FlashEntityService.js'; import { RoleService } from '@/core/RoleService.js'; @@ -51,6 +53,7 @@ const clientAssets = `${_dirname}/../../../../frontend/assets/`; const assets = `${_dirname}/../../../../../built/_frontend_dist_/`; const swAssets = `${_dirname}/../../../../../built/_sw_dist_/`; const viteOut = `${_dirname}/../../../../../built/_vite_/`; +const tarball = `${_dirname}/../../../../../built/tarball/`; @Injectable() export class ClientServerService { @@ -91,6 +94,7 @@ export class ClientServerService { private userEntityService: UserEntityService, private noteEntityService: NoteEntityService, private pageEntityService: PageEntityService, + private metaEntityService: MetaEntityService, private galleryPostEntityService: GalleryPostEntityService, private clipEntityService: ClipEntityService, private channelEntityService: ChannelEntityService, @@ -171,7 +175,7 @@ export class ClientServerService { } @bindThis - private generateCommonPugData(meta: MiMeta) { + private async generateCommonPugData(meta: MiMeta) { return { instanceName: meta.name ?? 'Misskey', icon: meta.iconUrl, @@ -181,6 +185,8 @@ export class ClientServerService { infoImageUrl: meta.infoImageUrl ?? 'https://xn--931a.moe/assets/info.jpg', notFoundImageUrl: meta.notFoundImageUrl ?? 'https://xn--931a.moe/assets/not-found.jpg', instanceUrl: this.config.url, + metaJson: htmlSafeJsonStringify(await this.metaEntityService.packDetailed(meta)), + now: Date.now(), }; } @@ -252,11 +258,16 @@ export class ClientServerService { //#region vite assets if (this.config.clientManifestExists) { - fastify.register(fastifyStatic, { - root: viteOut, - prefix: '/vite/', - maxAge: ms('30 days'), - decorateReply: false, + fastify.register((fastify, options, done) => { + fastify.register(fastifyStatic, { + root: viteOut, + prefix: '/vite/', + maxAge: ms('30 days'), + immutable: true, + decorateReply: false, + }); + fastify.addHook('onRequest', handleRequestRedirectToOmitSearch); + done(); }); } else { const port = (process.env.VITE_PORT ?? '5173'); @@ -291,6 +302,18 @@ export class ClientServerService { decorateReply: false, }); + fastify.register((fastify, options, done) => { + fastify.register(fastifyStatic, { + root: tarball, + prefix: '/tarball/', + maxAge: ms('30 days'), + immutable: true, + decorateReply: false, + }); + fastify.addHook('onRequest', handleRequestRedirectToOmitSearch); + done(); + }); + fastify.get('/favicon.ico', async (request, reply) => { return reply.sendFile('/favicon.ico', staticAssets); }); @@ -414,7 +437,7 @@ export class ClientServerService { url: this.config.url, title: meta.name ?? 'Misskey', desc: meta.description, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); }; @@ -501,7 +524,7 @@ export class ClientServerService { user, profile, me, avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user), sub: request.params.sub, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { // リモートユーザーなので @@ -551,7 +574,7 @@ export class ClientServerService { avatarUrl: _note.user.avatarUrl, // TODO: Let locale changeable by instance setting summary: getNoteSummary(_note), - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -590,7 +613,7 @@ export class ClientServerService { page: _page, profile, avatarUrl: _page.user.avatarUrl, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -616,7 +639,7 @@ export class ClientServerService { flash: _flash, profile, avatarUrl: _flash.user.avatarUrl, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -642,7 +665,7 @@ export class ClientServerService { clip: _clip, profile, avatarUrl: _clip.user.avatarUrl, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -666,7 +689,7 @@ export class ClientServerService { post: _post, profile, avatarUrl: _post.user.avatarUrl, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -685,7 +708,7 @@ export class ClientServerService { reply.header('Cache-Control', 'public, max-age=15'); return await reply.view('channel', { channel: _channel, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -704,7 +727,7 @@ export class ClientServerService { reply.header('Cache-Control', 'public, max-age=3600'); return await reply.view('reversi-game', { game: _game, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); diff --git a/packages/backend/src/server/web/FeedService.ts b/packages/backend/src/server/web/FeedService.ts index dfda85aac9..10e3ed2682 100644 --- a/packages/backend/src/server/web/FeedService.ts +++ b/packages/backend/src/server/web/FeedService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/web/UrlPreviewService.ts b/packages/backend/src/server/web/UrlPreviewService.ts index 3fd88355dd..c6a96e94cb 100644 --- a/packages/backend/src/server/web/UrlPreviewService.ts +++ b/packages/backend/src/server/web/UrlPreviewService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/web/bios.css b/packages/backend/src/server/web/bios.css index c934a55fa9..91d1af10b4 100644 --- a/packages/backend/src/server/web/bios.css +++ b/packages/backend/src/server/web/bios.css @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/web/bios.js b/packages/backend/src/server/web/bios.js index 029eb92aad..9ff5dca72a 100644 --- a/packages/backend/src/server/web/bios.js +++ b/packages/backend/src/server/web/bios.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js index c6b52a7a6b..59441826b0 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/backend/src/server/web/boot.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/web/cli.css b/packages/backend/src/server/web/cli.css index b7737c3f21..4e6136d59c 100644 --- a/packages/backend/src/server/web/cli.css +++ b/packages/backend/src/server/web/cli.css @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/web/cli.js b/packages/backend/src/server/web/cli.js index e63a80327c..30ee77f4d9 100644 --- a/packages/backend/src/server/web/cli.js +++ b/packages/backend/src/server/web/cli.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/web/error.css b/packages/backend/src/server/web/error.css index ea3056bdaf..f2b63296eb 100644 --- a/packages/backend/src/server/web/error.css +++ b/packages/backend/src/server/web/error.css @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -113,4 +113,4 @@ summary > * { details { width: 50%; } -} \ No newline at end of file +} diff --git a/packages/backend/src/server/web/style.css b/packages/backend/src/server/web/style.css index 952be9bf0b..e4723c24fd 100644 --- a/packages/backend/src/server/web/style.css +++ b/packages/backend/src/server/web/style.css @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index d167afe1e8..123336809b 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -68,6 +68,9 @@ html var VERSION = "#{version}"; var CLIENT_ENTRY = "#{clientEntry.file}"; + script(type='application/json' id='misskey_meta' data-generated-at=now) + != metaJson + script include ../boot.js diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index cfac5cd9d4..929070d0d2 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -33,7 +33,15 @@ export const notificationTypes = [ 'roleAssigned', 'achievementEarned', 'app', - 'test'] as const; + 'test', +] as const; + +export const groupedNotificationTypes = [ + ...notificationTypes, + 'reaction:grouped', + 'renote:grouped', +] as const; + export const obsoleteNotificationTypes = ['pollVote', 'groupInvited'] as const; export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const; @@ -69,6 +77,7 @@ export const moderationLogTypes = [ 'resetPassword', 'suspendRemoteInstance', 'unsuspendRemoteInstance', + 'updateRemoteInstanceNote', 'markSensitiveDriveFile', 'unmarkSensitiveDriveFile', 'resolveAbuseReport', @@ -209,6 +218,12 @@ export type ModerationLogPayloads = { id: string; host: string; }; + updateRemoteInstanceNote: { + id: string; + host: string; + before: string | null; + after: string | null; + }; markSensitiveDriveFile: { fileId: string; fileUserId: string | null; diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts index 165a1055c9..13c56b88a6 100644 --- a/packages/backend/test/e2e/2fa.ts +++ b/packages/backend/test/e2e/2fa.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -18,7 +18,7 @@ import type { PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON, -} from '@simplewebauthn/typescript-types'; +} from '@simplewebauthn/types'; import type * as misskey from 'misskey-js'; describe('2要素認証', () => { @@ -187,7 +187,7 @@ describe('2要素認証', () => { }, 1000 * 60 * 2); test('が設定でき、OTPでログインできる。', async () => { - const registerResponse = await api('/i/2fa/register', { + const registerResponse = await api('i/2fa/register', { password, }, alice); assert.strictEqual(registerResponse.status, 200); @@ -197,18 +197,18 @@ describe('2要素認証', () => { assert.strictEqual(registerResponse.body.label, username); assert.strictEqual(registerResponse.body.issuer, config.host); - const doneResponse = await api('/i/2fa/done', { + const doneResponse = await api('i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); assert.strictEqual(doneResponse.status, 200); - const usersShowResponse = await api('/users/show', { + const usersShowResponse = await api('users/show', { username, }, alice); assert.strictEqual(usersShowResponse.status, 200); assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true); - const signinResponse = await api('/signin', { + const signinResponse = await api('signin', { ...signinParam(), token: otpToken(registerResponse.body.secret), }); @@ -216,24 +216,24 @@ describe('2要素認証', () => { assert.notEqual(signinResponse.body.i, undefined); // 後片付け - await api('/i/2fa/unregister', { + await api('i/2fa/unregister', { password, token: otpToken(registerResponse.body.secret), }, alice); }); test('が設定でき、セキュリティキーでログインできる。', async () => { - const registerResponse = await api('/i/2fa/register', { + const registerResponse = await api('i/2fa/register', { password, }, alice); assert.strictEqual(registerResponse.status, 200); - const doneResponse = await api('/i/2fa/done', { + const doneResponse = await api('i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); assert.strictEqual(doneResponse.status, 200); - const registerKeyResponse = await api('/i/2fa/register-key', { + const registerKeyResponse = await api('i/2fa/register-key', { password, token: otpToken(registerResponse.body.secret), }, alice); @@ -243,23 +243,23 @@ describe('2要素認証', () => { const keyName = 'example-key'; const credentialId = crypto.randomBytes(0x41); - const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({ + const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({ token: otpToken(registerResponse.body.secret), keyName, credentialId, creationOptions: registerKeyResponse.body, - }), alice); + }) as any, alice); assert.strictEqual(keyDoneResponse.status, 200); assert.strictEqual(keyDoneResponse.body.id, credentialId.toString('base64url')); assert.strictEqual(keyDoneResponse.body.name, keyName); - const usersShowResponse = await api('/users/show', { + const usersShowResponse = await api('users/show', { username, }); assert.strictEqual(usersShowResponse.status, 200); assert.strictEqual(usersShowResponse.body.securityKeys, true); - const signinResponse = await api('/signin', { + const signinResponse = await api('signin', { ...signinParam(), }); assert.strictEqual(signinResponse.status, 200); @@ -268,7 +268,7 @@ describe('2要素認証', () => { assert.notEqual(signinResponse.body.allowCredentials, undefined); assert.strictEqual(signinResponse.body.allowCredentials[0].id, credentialId.toString('base64url')); - const signinResponse2 = await api('/signin', signinWithSecurityKeyParam({ + const signinResponse2 = await api('signin', signinWithSecurityKeyParam({ keyName, credentialId, requestOptions: signinResponse.body, @@ -277,24 +277,24 @@ describe('2要素認証', () => { assert.notEqual(signinResponse2.body.i, undefined); // 後片付け - await api('/i/2fa/unregister', { + await api('i/2fa/unregister', { password, token: otpToken(registerResponse.body.secret), }, alice); }); test('が設定でき、セキュリティキーでパスワードレスログインできる。', async () => { - const registerResponse = await api('/i/2fa/register', { + const registerResponse = await api('i/2fa/register', { password, }, alice); assert.strictEqual(registerResponse.status, 200); - const doneResponse = await api('/i/2fa/done', { + const doneResponse = await api('i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); assert.strictEqual(doneResponse.status, 200); - const registerKeyResponse = await api('/i/2fa/register-key', { + const registerKeyResponse = await api('i/2fa/register-key', { token: otpToken(registerResponse.body.secret), password, }, alice); @@ -302,33 +302,33 @@ describe('2要素認証', () => { const keyName = 'example-key'; const credentialId = crypto.randomBytes(0x41); - const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({ + const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({ token: otpToken(registerResponse.body.secret), keyName, credentialId, creationOptions: registerKeyResponse.body, - }), alice); + }) as any, alice); assert.strictEqual(keyDoneResponse.status, 200); - const passwordLessResponse = await api('/i/2fa/password-less', { + const passwordLessResponse = await api('i/2fa/password-less', { value: true, }, alice); assert.strictEqual(passwordLessResponse.status, 204); - const usersShowResponse = await api('/users/show', { + const usersShowResponse = await api('users/show', { username, }); assert.strictEqual(usersShowResponse.status, 200); assert.strictEqual(usersShowResponse.body.usePasswordLessLogin, true); - const signinResponse = await api('/signin', { + const signinResponse = await api('signin', { ...signinParam(), password: '', }); assert.strictEqual(signinResponse.status, 200); assert.strictEqual(signinResponse.body.i, undefined); - const signinResponse2 = await api('/signin', { + const signinResponse2 = await api('signin', { ...signinWithSecurityKeyParam({ keyName, credentialId, @@ -340,24 +340,24 @@ describe('2要素認証', () => { assert.notEqual(signinResponse2.body.i, undefined); // 後片付け - await api('/i/2fa/unregister', { + await api('i/2fa/unregister', { password, token: otpToken(registerResponse.body.secret), }, alice); }); test('が設定でき、設定したセキュリティキーの名前を変更できる。', async () => { - const registerResponse = await api('/i/2fa/register', { + const registerResponse = await api('i/2fa/register', { password, }, alice); assert.strictEqual(registerResponse.status, 200); - const doneResponse = await api('/i/2fa/done', { + const doneResponse = await api('i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); assert.strictEqual(doneResponse.status, 200); - const registerKeyResponse = await api('/i/2fa/register-key', { + const registerKeyResponse = await api('i/2fa/register-key', { token: otpToken(registerResponse.body.secret), password, }, alice); @@ -365,22 +365,22 @@ describe('2要素認証', () => { const keyName = 'example-key'; const credentialId = crypto.randomBytes(0x41); - const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({ + const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({ token: otpToken(registerResponse.body.secret), keyName, credentialId, creationOptions: registerKeyResponse.body, - }), alice); + }) as any, alice); assert.strictEqual(keyDoneResponse.status, 200); const renamedKey = 'other-key'; - const updateKeyResponse = await api('/i/2fa/update-key', { + const updateKeyResponse = await api('i/2fa/update-key', { name: renamedKey, credentialId: credentialId.toString('base64url'), }, alice); assert.strictEqual(updateKeyResponse.status, 200); - const iResponse = await api('/i', { + const iResponse = await api('i', { }, alice); assert.strictEqual(iResponse.status, 200); const securityKeys = iResponse.body.securityKeysList.filter((s: { id: string; }) => s.id === credentialId.toString('base64url')); @@ -389,24 +389,24 @@ describe('2要素認証', () => { assert.notEqual(securityKeys[0].lastUsed, undefined); // 後片付け - await api('/i/2fa/unregister', { + await api('i/2fa/unregister', { password, token: otpToken(registerResponse.body.secret), }, alice); }); test('が設定でき、設定したセキュリティキーを削除できる。', async () => { - const registerResponse = await api('/i/2fa/register', { + const registerResponse = await api('i/2fa/register', { password, }, alice); assert.strictEqual(registerResponse.status, 200); - const doneResponse = await api('/i/2fa/done', { + const doneResponse = await api('i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); assert.strictEqual(doneResponse.status, 200); - const registerKeyResponse = await api('/i/2fa/register-key', { + const registerKeyResponse = await api('i/2fa/register-key', { token: otpToken(registerResponse.body.secret), password, }, alice); @@ -414,20 +414,20 @@ describe('2要素認証', () => { const keyName = 'example-key'; const credentialId = crypto.randomBytes(0x41); - const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({ + const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({ token: otpToken(registerResponse.body.secret), keyName, credentialId, creationOptions: registerKeyResponse.body, - }), alice); + }) as any, alice); assert.strictEqual(keyDoneResponse.status, 200); // テストの実行順によっては複数残ってるので全部消す - const iResponse = await api('/i', { + const iResponse = await api('i', { }, alice); assert.strictEqual(iResponse.status, 200); for (const key of iResponse.body.securityKeysList) { - const removeKeyResponse = await api('/i/2fa/remove-key', { + const removeKeyResponse = await api('i/2fa/remove-key', { token: otpToken(registerResponse.body.secret), password, credentialId: key.id, @@ -435,13 +435,13 @@ describe('2要素認証', () => { assert.strictEqual(removeKeyResponse.status, 200); } - const usersShowResponse = await api('/users/show', { + const usersShowResponse = await api('users/show', { username, }); assert.strictEqual(usersShowResponse.status, 200); assert.strictEqual(usersShowResponse.body.securityKeys, false); - const signinResponse = await api('/signin', { + const signinResponse = await api('signin', { ...signinParam(), token: otpToken(registerResponse.body.secret), }); @@ -449,43 +449,43 @@ describe('2要素認証', () => { assert.notEqual(signinResponse.body.i, undefined); // 後片付け - await api('/i/2fa/unregister', { + await api('i/2fa/unregister', { password, token: otpToken(registerResponse.body.secret), }, alice); }); test('が設定でき、設定解除できる。(パスワードのみでログインできる。)', async () => { - const registerResponse = await api('/i/2fa/register', { + const registerResponse = await api('i/2fa/register', { password, }, alice); assert.strictEqual(registerResponse.status, 200); - const doneResponse = await api('/i/2fa/done', { + const doneResponse = await api('i/2fa/done', { token: otpToken(registerResponse.body.secret), }, alice); assert.strictEqual(doneResponse.status, 200); - const usersShowResponse = await api('/users/show', { + const usersShowResponse = await api('users/show', { username, }); assert.strictEqual(usersShowResponse.status, 200); assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true); - const unregisterResponse = await api('/i/2fa/unregister', { + const unregisterResponse = await api('i/2fa/unregister', { token: otpToken(registerResponse.body.secret), password, }, alice); assert.strictEqual(unregisterResponse.status, 204); - const signinResponse = await api('/signin', { + const signinResponse = await api('signin', { ...signinParam(), }); assert.strictEqual(signinResponse.status, 200); assert.notEqual(signinResponse.body.i, undefined); // 後片付け - await api('/i/2fa/unregister', { + await api('i/2fa/unregister', { password, token: otpToken(registerResponse.body.secret), }, alice); diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts index e63722b246..7370b1963c 100644 --- a/packages/backend/test/e2e/antennas.ts +++ b/packages/backend/test/e2e/antennas.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -7,7 +7,6 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; -import type { Packed } from '@/misc/json-schema.js'; import { api, failedApiCall, @@ -29,10 +28,7 @@ describe('アンテナ', () => { // エンティティとしてのアンテナを主眼においたテストを記述する // (Antennaを返すエンドポイント、Antennaエンティティを書き換えるエンドポイント、Antennaからノートを取得するエンドポイントをテストする) - // BUG misskey-jsとjson-schemaが一致していない。 - // - srcのenumにgroupが残っている - // - userGroupIdが残っている, isActiveがない - type Antenna = misskey.entities.Antenna | Packed<'Antenna'>; + type Antenna = misskey.entities.Antenna; type User = misskey.entities.SignupResponse; type Note = misskey.entities.Note; @@ -80,7 +76,7 @@ describe('アンテナ', () => { aliceList = await userList(alice, {}); bob = await signup({ username: 'bob' }); aliceList = await userList(alice, {}); - bobFile = (await uploadFile(bob)).body; + bobFile = (await uploadFile(bob)).body!; bobList = await userList(bob); carol = await signup({ username: 'carol' }); await api('users/lists/push', { listId: aliceList.id, userId: bob.id }, alice); @@ -129,9 +125,9 @@ describe('アンテナ', () => { beforeEach(async () => { // テスト間で影響し合わないように毎回全部消す。 for (const user of [alice, bob]) { - const list = await api('/antennas/list', {}, user); + const list = await api('antennas/list', {}, user); for (const antenna of list.body) { - await api('/antennas/delete', { antennaId: antenna.id }, user); + await api('antennas/delete', { antennaId: antenna.id }, user); } } }); @@ -141,11 +137,11 @@ describe('アンテナ', () => { test('が作成できること、キーが過不足なく入っていること。', async () => { const response = await successfulApiCall({ endpoint: 'antennas/create', - parameters: { ...defaultParam }, + parameters: defaultParam, user: alice, }); assert.match(response.id, /[0-9a-z]{10}/); - const expected = { + const expected: Antenna = { id: response.id, caseSensitive: false, createdAt: new Date(response.createdAt).toISOString(), @@ -161,7 +157,7 @@ describe('アンテナ', () => { withFile: false, withReplies: false, localOnly: false, - } as Antenna; + }; assert.deepStrictEqual(response, expected); }); @@ -202,27 +198,27 @@ describe('アンテナ', () => { }); const antennaParamPattern = [ - { parameters: (): object => ({ name: 'x'.repeat(100) }) }, - { parameters: (): object => ({ name: 'x' }) }, - { parameters: (): object => ({ src: 'home' }) }, - { parameters: (): object => ({ src: 'all' }) }, - { parameters: (): object => ({ src: 'users' }) }, - { parameters: (): object => ({ src: 'list' }) }, - { parameters: (): object => ({ userListId: null }) }, - { parameters: (): object => ({ src: 'list', userListId: aliceList.id }) }, - { parameters: (): object => ({ keywords: [['x']] }) }, - { parameters: (): object => ({ keywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) }, - { parameters: (): object => ({ excludeKeywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) }, - { parameters: (): object => ({ users: [alice.username] }) }, - { parameters: (): object => ({ users: [alice.username, bob.username, carol.username] }) }, - { parameters: (): object => ({ caseSensitive: false }) }, - { parameters: (): object => ({ caseSensitive: true }) }, - { parameters: (): object => ({ withReplies: false }) }, - { parameters: (): object => ({ withReplies: true }) }, - { parameters: (): object => ({ withFile: false }) }, - { parameters: (): object => ({ withFile: true }) }, - { parameters: (): object => ({ notify: false }) }, - { parameters: (): object => ({ notify: true }) }, + { parameters: () => ({ name: 'x'.repeat(100) }) }, + { parameters: () => ({ name: 'x' }) }, + { parameters: () => ({ src: 'home' as const }) }, + { parameters: () => ({ src: 'all' as const }) }, + { parameters: () => ({ src: 'users' as const }) }, + { parameters: () => ({ src: 'list' as const }) }, + { parameters: () => ({ userListId: null }) }, + { parameters: () => ({ src: 'list' as const, userListId: aliceList.id }) }, + { parameters: () => ({ keywords: [['x']] }) }, + { parameters: () => ({ keywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) }, + { parameters: () => ({ excludeKeywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) }, + { parameters: () => ({ users: [alice.username] }) }, + { parameters: () => ({ users: [alice.username, bob.username, carol.username] }) }, + { parameters: () => ({ caseSensitive: false }) }, + { parameters: () => ({ caseSensitive: true }) }, + { parameters: () => ({ withReplies: false }) }, + { parameters: () => ({ withReplies: true }) }, + { parameters: () => ({ withFile: false }) }, + { parameters: () => ({ withFile: true }) }, + { parameters: () => ({ notify: false }) }, + { parameters: () => ({ notify: true }) }, ]; test.each(antennaParamPattern)('を作成できること($#)', async ({ parameters }) => { const response = await successfulApiCall({ @@ -335,7 +331,7 @@ describe('アンテナ', () => { test.each([ { label: '全体から', - parameters: (): object => ({ src: 'all' }), + parameters: () => ({ src: 'all' }), posts: [ { note: (): Promise => post(alice, { text: `${keyword}` }), included: true }, { note: (): Promise => post(userFollowedByAlice, { text: `${keyword}` }), included: true }, @@ -346,7 +342,7 @@ describe('アンテナ', () => { { // BUG e4144a1 以降home指定は壊れている(allと同じ) label: 'ホーム指定はallと同じ', - parameters: (): object => ({ src: 'home' }), + parameters: () => ({ src: 'home' }), posts: [ { note: (): Promise => post(alice, { text: `${keyword}` }), included: true }, { note: (): Promise => post(userFollowedByAlice, { text: `${keyword}` }), included: true }, @@ -357,7 +353,7 @@ describe('アンテナ', () => { { // https://github.com/misskey-dev/misskey/issues/9025 label: 'ただし、フォロワー限定投稿とDM投稿を含まない。フォロワーであっても。', - parameters: (): object => ({}), + parameters: () => ({}), posts: [ { note: (): Promise => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'public' }), included: true }, { note: (): Promise => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'home' }), included: true }, @@ -367,56 +363,56 @@ describe('アンテナ', () => { }, { label: 'ブロックしているユーザーのノートは含む', - parameters: (): object => ({}), + parameters: () => ({}), posts: [ { note: (): Promise => post(userBlockedByAlice, { text: `${keyword}` }), included: true }, ], }, { label: 'ブロックされているユーザーのノートは含まない', - parameters: (): object => ({}), + parameters: () => ({}), posts: [ { note: (): Promise => post(userBlockingAlice, { text: `${keyword}` }) }, ], }, { label: 'ミュートしているユーザーのノートは含まない', - parameters: (): object => ({}), + parameters: () => ({}), posts: [ { note: (): Promise => post(userMutedByAlice, { text: `${keyword}` }) }, ], }, { label: 'ミュートされているユーザーのノートは含む', - parameters: (): object => ({}), + parameters: () => ({}), posts: [ { note: (): Promise => post(userMutingAlice, { text: `${keyword}` }), included: true }, ], }, { label: '「見つけやすくする」がOFFのユーザーのノートも含まれる', - parameters: (): object => ({}), + parameters: () => ({}), posts: [ { note: (): Promise => post(userNotExplorable, { text: `${keyword}` }), included: true }, ], }, { label: '鍵付きユーザーのノートも含まれる', - parameters: (): object => ({}), + parameters: () => ({}), posts: [ { note: (): Promise => post(userLocking, { text: `${keyword}` }), included: true }, ], }, { label: 'サイレンスのノートも含まれる', - parameters: (): object => ({}), + parameters: () => ({}), posts: [ { note: (): Promise => post(userSilenced, { text: `${keyword}` }), included: true }, ], }, { label: '削除ユーザーのノートも含まれる', - parameters: (): object => ({}), + parameters: () => ({}), posts: [ { note: (): Promise => post(userDeletedBySelf, { text: `${keyword}` }), included: true }, { note: (): Promise => post(userDeletedByAdmin, { text: `${keyword}` }), included: true }, @@ -424,7 +420,7 @@ describe('アンテナ', () => { }, { label: 'ユーザー指定で', - parameters: (): object => ({ src: 'users', users: [`@${bob.username}`, `@${carol.username}`] }), + parameters: () => ({ src: 'users', users: [`@${bob.username}`, `@${carol.username}`] }), posts: [ { note: (): Promise => post(alice, { text: `test ${keyword}` }) }, { note: (): Promise => post(bob, { text: `test ${keyword}` }), included: true }, @@ -433,7 +429,7 @@ describe('アンテナ', () => { }, { label: 'リスト指定で', - parameters: (): object => ({ src: 'list', userListId: aliceList.id }), + parameters: () => ({ src: 'list', userListId: aliceList.id }), posts: [ { note: (): Promise => post(alice, { text: `test ${keyword}` }) }, { note: (): Promise => post(bob, { text: `test ${keyword}` }), included: true }, @@ -442,14 +438,14 @@ describe('アンテナ', () => { }, { label: 'CWにもマッチする', - parameters: (): object => ({ keywords: [[keyword]] }), + parameters: () => ({ keywords: [[keyword]] }), posts: [ { note: (): Promise => post(bob, { text: 'test', cw: `cw ${keyword}` }), included: true }, ], }, { label: 'キーワード1つ', - parameters: (): object => ({ keywords: [[keyword]] }), + parameters: () => ({ keywords: [[keyword]] }), posts: [ { note: (): Promise => post(alice, { text: 'test' }) }, { note: (): Promise => post(bob, { text: `test ${keyword}` }), included: true }, @@ -458,7 +454,7 @@ describe('アンテナ', () => { }, { label: 'キーワード3つ(AND)', - parameters: (): object => ({ keywords: [['A', 'B', 'C']] }), + parameters: () => ({ keywords: [['A', 'B', 'C']] }), posts: [ { note: (): Promise => post(bob, { text: 'test A' }) }, { note: (): Promise => post(bob, { text: 'test A B' }) }, @@ -469,7 +465,7 @@ describe('アンテナ', () => { }, { label: 'キーワード3つ(OR)', - parameters: (): object => ({ keywords: [['A'], ['B'], ['C']] }), + parameters: () => ({ keywords: [['A'], ['B'], ['C']] }), posts: [ { note: (): Promise => post(bob, { text: 'test' }) }, { note: (): Promise => post(bob, { text: 'test A' }), included: true }, @@ -482,7 +478,7 @@ describe('アンテナ', () => { }, { label: '除外ワード3つ(AND)', - parameters: (): object => ({ excludeKeywords: [['A', 'B', 'C']] }), + parameters: () => ({ excludeKeywords: [['A', 'B', 'C']] }), posts: [ { note: (): Promise => post(bob, { text: `test ${keyword}` }), included: true }, { note: (): Promise => post(bob, { text: `test ${keyword} A` }), included: true }, @@ -495,7 +491,7 @@ describe('アンテナ', () => { }, { label: '除外ワード3つ(OR)', - parameters: (): object => ({ excludeKeywords: [['A'], ['B'], ['C']] }), + parameters: () => ({ excludeKeywords: [['A'], ['B'], ['C']] }), posts: [ { note: (): Promise => post(bob, { text: `test ${keyword}` }), included: true }, { note: (): Promise => post(bob, { text: `test ${keyword} A` }) }, @@ -508,7 +504,7 @@ describe('アンテナ', () => { }, { label: 'キーワード1つ(大文字小文字区別する)', - parameters: (): object => ({ keywords: [['KEYWORD']], caseSensitive: true }), + parameters: () => ({ keywords: [['KEYWORD']], caseSensitive: true }), posts: [ { note: (): Promise => post(bob, { text: 'keyword' }) }, { note: (): Promise => post(bob, { text: 'kEyWoRd' }) }, @@ -517,7 +513,7 @@ describe('アンテナ', () => { }, { label: 'キーワード1つ(大文字小文字区別しない)', - parameters: (): object => ({ keywords: [['KEYWORD']], caseSensitive: false }), + parameters: () => ({ keywords: [['KEYWORD']], caseSensitive: false }), posts: [ { note: (): Promise => post(bob, { text: 'keyword' }), included: true }, { note: (): Promise => post(bob, { text: 'kEyWoRd' }), included: true }, @@ -526,7 +522,7 @@ describe('アンテナ', () => { }, { label: '除外ワード1つ(大文字小文字区別する)', - parameters: (): object => ({ excludeKeywords: [['KEYWORD']], caseSensitive: true }), + parameters: () => ({ excludeKeywords: [['KEYWORD']], caseSensitive: true }), posts: [ { note: (): Promise => post(bob, { text: `${keyword}` }), included: true }, { note: (): Promise => post(bob, { text: `${keyword} keyword` }), included: true }, @@ -536,7 +532,7 @@ describe('アンテナ', () => { }, { label: '除外ワード1つ(大文字小文字区別しない)', - parameters: (): object => ({ excludeKeywords: [['KEYWORD']], caseSensitive: false }), + parameters: () => ({ excludeKeywords: [['KEYWORD']], caseSensitive: false }), posts: [ { note: (): Promise => post(bob, { text: `${keyword}` }), included: true }, { note: (): Promise => post(bob, { text: `${keyword} keyword` }) }, @@ -546,7 +542,7 @@ describe('アンテナ', () => { }, { label: '添付ファイルを問わない', - parameters: (): object => ({ withFile: false }), + parameters: () => ({ withFile: false }), posts: [ { note: (): Promise => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true }, { note: (): Promise => post(bob, { text: `${keyword}` }), included: true }, @@ -554,7 +550,7 @@ describe('アンテナ', () => { }, { label: '添付ファイル付きのみ', - parameters: (): object => ({ withFile: true }), + parameters: () => ({ withFile: true }), posts: [ { note: (): Promise => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true }, { note: (): Promise => post(bob, { text: `${keyword}` }) }, @@ -562,7 +558,7 @@ describe('アンテナ', () => { }, { label: 'リプライ以外', - parameters: (): object => ({ withReplies: false }), + parameters: () => ({ withReplies: false }), posts: [ { note: (): Promise => post(bob, { text: `${keyword}`, replyId: alicePost.id }) }, { note: (): Promise => post(bob, { text: `${keyword}` }), included: true }, @@ -570,7 +566,7 @@ describe('アンテナ', () => { }, { label: 'リプライも含む', - parameters: (): object => ({ withReplies: true }), + parameters: () => ({ withReplies: true }), posts: [ { note: (): Promise => post(bob, { text: `${keyword}`, replyId: alicePost.id }), included: true }, { note: (): Promise => post(bob, { text: `${keyword}` }), included: true }, @@ -633,7 +629,7 @@ describe('アンテナ', () => { endpoint: 'antennas/notes', parameters: { antennaId: antenna.id, ...paginationParam }, user: alice, - }) as any as Note[]; + }); }, offsetBy, 'desc'); }); diff --git a/packages/backend/test/e2e/api-visibility.ts b/packages/backend/test/e2e/api-visibility.ts index 89d8b42271..c61b0c2a86 100644 --- a/packages/backend/test/e2e/api-visibility.ts +++ b/packages/backend/test/e2e/api-visibility.ts @@ -1,12 +1,12 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { api, post, signup } from '../utils.js'; +import { UserToken, api, post, signup } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('API visibility', () => { @@ -24,38 +24,38 @@ describe('API visibility', () => { let target2: misskey.entities.SignupResponse; /** public-post */ - let pub: any; + let pub: misskey.entities.Note; /** home-post */ - let home: any; + let home: misskey.entities.Note; /** followers-post */ - let fol: any; + let fol: misskey.entities.Note; /** specified-post */ - let spe: any; + let spe: misskey.entities.Note; /** public-reply to target's post */ - let pubR: any; + let pubR: misskey.entities.Note; /** home-reply to target's post */ - let homeR: any; + let homeR: misskey.entities.Note; /** followers-reply to target's post */ - let folR: any; + let folR: misskey.entities.Note; /** specified-reply to target's post */ - let speR: any; + let speR: misskey.entities.Note; /** public-mention to target */ - let pubM: any; + let pubM: misskey.entities.Note; /** home-mention to target */ - let homeM: any; + let homeM: misskey.entities.Note; /** followers-mention to target */ - let folM: any; + let folM: misskey.entities.Note; /** specified-mention to target */ - let speM: any; + let speM: misskey.entities.Note; /** reply target post */ - let tgt: any; + let tgt: misskey.entities.Note; //#endregion - const show = async (noteId: any, by: any) => { - return await api('/notes/show', { + const show = async (noteId: misskey.entities.Note['id'], by?: UserToken) => { + return await api('notes/show', { noteId, }, by); }; @@ -70,7 +70,7 @@ describe('API visibility', () => { target2 = await signup({ username: 'target2' }); // follow alice <= follower - await api('/following/create', { userId: alice.id }, follower); + await api('following/create', { userId: alice.id }, follower); // normal posts pub = await post(alice, { text: 'x', visibility: 'public' }); @@ -111,7 +111,7 @@ describe('API visibility', () => { }); test('[show] public-postを未認証が見れる', async () => { - const res = await show(pub.id, null); + const res = await show(pub.id); assert.strictEqual(res.body.text, 'x'); }); @@ -132,7 +132,7 @@ describe('API visibility', () => { }); test('[show] home-postを未認証が見れる', async () => { - const res = await show(home.id, null); + const res = await show(home.id); assert.strictEqual(res.body.text, 'x'); }); @@ -153,7 +153,7 @@ describe('API visibility', () => { }); test('[show] followers-postを未認証が見れない', async () => { - const res = await show(fol.id, null); + const res = await show(fol.id); assert.strictEqual(res.body.isHidden, true); }); @@ -179,7 +179,7 @@ describe('API visibility', () => { }); test('[show] specified-postを未認証が見れない', async () => { - const res = await show(spe.id, null); + const res = await show(spe.id); assert.strictEqual(res.body.isHidden, true); }); //#endregion @@ -207,7 +207,7 @@ describe('API visibility', () => { }); test('[show] public-replyを未認証が見れる', async () => { - const res = await show(pubR.id, null); + const res = await show(pubR.id); assert.strictEqual(res.body.text, 'x'); }); @@ -233,7 +233,7 @@ describe('API visibility', () => { }); test('[show] home-replyを未認証が見れる', async () => { - const res = await show(homeR.id, null); + const res = await show(homeR.id); assert.strictEqual(res.body.text, 'x'); }); @@ -259,7 +259,7 @@ describe('API visibility', () => { }); test('[show] followers-replyを未認証が見れない', async () => { - const res = await show(folR.id, null); + const res = await show(folR.id); assert.strictEqual(res.body.isHidden, true); }); @@ -290,7 +290,7 @@ describe('API visibility', () => { }); test('[show] specified-replyを未認証が見れない', async () => { - const res = await show(speR.id, null); + const res = await show(speR.id); assert.strictEqual(res.body.isHidden, true); }); //#endregion @@ -318,7 +318,7 @@ describe('API visibility', () => { }); test('[show] public-mentionを未認証が見れる', async () => { - const res = await show(pubM.id, null); + const res = await show(pubM.id); assert.strictEqual(res.body.text, '@target x'); }); @@ -344,7 +344,7 @@ describe('API visibility', () => { }); test('[show] home-mentionを未認証が見れる', async () => { - const res = await show(homeM.id, null); + const res = await show(homeM.id); assert.strictEqual(res.body.text, '@target x'); }); @@ -370,7 +370,7 @@ describe('API visibility', () => { }); test('[show] followers-mentionを未認証が見れない', async () => { - const res = await show(folM.id, null); + const res = await show(folM.id); assert.strictEqual(res.body.isHidden, true); }); @@ -401,28 +401,28 @@ describe('API visibility', () => { }); test('[show] specified-mentionを未認証が見れない', async () => { - const res = await show(speM.id, null); + const res = await show(speM.id); assert.strictEqual(res.body.isHidden, true); }); //#endregion //#region HTL test('[HTL] public-post が 自分が見れる', async () => { - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.status, 200); const notes = res.body.filter((n: any) => n.id === pub.id); assert.strictEqual(notes[0].text, 'x'); }); test('[HTL] public-post が 非フォロワーから見れない', async () => { - const res = await api('/notes/timeline', { limit: 100 }, other); + const res = await api('notes/timeline', { limit: 100 }, other); assert.strictEqual(res.status, 200); const notes = res.body.filter((n: any) => n.id === pub.id); assert.strictEqual(notes.length, 0); }); test('[HTL] followers-post が フォロワーから見れる', async () => { - const res = await api('/notes/timeline', { limit: 100 }, follower); + const res = await api('notes/timeline', { limit: 100 }, follower); assert.strictEqual(res.status, 200); const notes = res.body.filter((n: any) => n.id === fol.id); assert.strictEqual(notes[0].text, 'x'); @@ -431,21 +431,21 @@ describe('API visibility', () => { //#region RTL test('[replies] followers-reply が フォロワーから見れる', async () => { - const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, follower); + const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, follower); assert.strictEqual(res.status, 200); const notes = res.body.filter((n: any) => n.id === folR.id); assert.strictEqual(notes[0].text, 'x'); }); test('[replies] followers-reply が 非フォロワー (リプライ先ではない) から見れない', async () => { - const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, other); + const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, other); assert.strictEqual(res.status, 200); const notes = res.body.filter((n: any) => n.id === folR.id); assert.strictEqual(notes.length, 0); }); test('[replies] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => { - const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, target); + const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, target); assert.strictEqual(res.status, 200); const notes = res.body.filter((n: any) => n.id === folR.id); assert.strictEqual(notes[0].text, 'x'); @@ -454,14 +454,14 @@ describe('API visibility', () => { //#region MTL test('[mentions] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => { - const res = await api('/notes/mentions', { limit: 100 }, target); + const res = await api('notes/mentions', { limit: 100 }, target); assert.strictEqual(res.status, 200); const notes = res.body.filter((n: any) => n.id === folR.id); assert.strictEqual(notes[0].text, 'x'); }); test('[mentions] followers-mention が 非フォロワー (メンション先である) から見れる', async () => { - const res = await api('/notes/mentions', { limit: 100 }, target); + const res = await api('notes/mentions', { limit: 100 }, target); assert.strictEqual(res.status, 200); const notes = res.body.filter((n: any) => n.id === folM.id); assert.strictEqual(notes[0].text, '@target x'); diff --git a/packages/backend/test/e2e/api.ts b/packages/backend/test/e2e/api.ts index 25d5bdb175..49c6a0636b 100644 --- a/packages/backend/test/e2e/api.ts +++ b/packages/backend/test/e2e/api.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -23,32 +23,32 @@ import type * as misskey from 'misskey-js'; describe('API', () => { let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; - let carol: misskey.entities.SignupResponse; beforeAll(async () => { alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); - carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); describe('General validation', () => { test('wrong type', async () => { - const res = await api('/test', { + const res = await api('test', { required: true, + // @ts-expect-error string must be string string: 42, }); assert.strictEqual(res.status, 400); }); test('missing require param', async () => { - const res = await api('/test', { + // @ts-expect-error required is required + const res = await api('test', { string: 'a', }); assert.strictEqual(res.status, 400); }); test('invalid misskey:id (empty string)', async () => { - const res = await api('/test', { + const res = await api('test', { required: true, id: '', }); @@ -56,7 +56,7 @@ describe('API', () => { }); test('valid misskey:id', async () => { - const res = await api('/test', { + const res = await api('test', { required: true, id: '8wvhjghbxu', }); @@ -64,7 +64,7 @@ describe('API', () => { }); test('default value', async () => { - const res = await api('/test', { + const res = await api('test', { required: true, string: 'a', }); @@ -73,7 +73,7 @@ describe('API', () => { }); test('can set null even if it has default value', async () => { - const res = await api('/test', { + const res = await api('test', { required: true, nullableDefault: null, }); @@ -82,7 +82,7 @@ describe('API', () => { }); test('cannot set undefined if it has default value', async () => { - const res = await api('/test', { + const res = await api('test', { required: true, nullableDefault: undefined, }); @@ -99,14 +99,14 @@ describe('API', () => { // aliceは管理者、APIを使える await successfulApiCall({ - endpoint: '/admin/get-index-stats', + endpoint: 'admin/get-index-stats', parameters: {}, user: alice, }); // bobは一般ユーザーだからダメ await failedApiCall({ - endpoint: '/admin/get-index-stats', + endpoint: 'admin/get-index-stats', parameters: {}, user: bob, }, { @@ -117,7 +117,7 @@ describe('API', () => { // publicアクセスももちろんダメ await failedApiCall({ - endpoint: '/admin/get-index-stats', + endpoint: 'admin/get-index-stats', parameters: {}, user: undefined, }, { @@ -128,7 +128,7 @@ describe('API', () => { // ごまがしもダメ await failedApiCall({ - endpoint: '/admin/get-index-stats', + endpoint: 'admin/get-index-stats', parameters: {}, user: { token: 'tsukawasete' }, }, { @@ -138,13 +138,13 @@ describe('API', () => { }); await successfulApiCall({ - endpoint: '/admin/get-index-stats', + endpoint: 'admin/get-index-stats', parameters: {}, user: { token: application2 }, }); await failedApiCall({ - endpoint: '/admin/get-index-stats', + endpoint: 'admin/get-index-stats', parameters: {}, user: { token: application }, }, { @@ -154,7 +154,7 @@ describe('API', () => { }); await failedApiCall({ - endpoint: '/admin/get-index-stats', + endpoint: 'admin/get-index-stats', parameters: {}, user: { token: application3 }, }, { @@ -164,7 +164,7 @@ describe('API', () => { }); await failedApiCall({ - endpoint: '/admin/get-index-stats', + endpoint: 'admin/get-index-stats', parameters: {}, user: { token: application4 }, }, { @@ -177,7 +177,7 @@ describe('API', () => { describe('Authentication header', () => { test('一般リクエスト', async () => { await successfulApiCall({ - endpoint: '/admin/get-index-stats', + endpoint: 'admin/get-index-stats', parameters: {}, user: { token: alice.token, @@ -211,7 +211,7 @@ describe('API', () => { describe('tokenエラー応答でWWW-Authenticate headerを送る', () => { describe('invalid_token', () => { test('一般リクエスト', async () => { - const result = await api('/admin/get-index-stats', {}, { + const result = await api('admin/get-index-stats', {}, { token: 'syuilo', bearer: true, }); @@ -246,7 +246,7 @@ describe('API', () => { describe('tokenがないとrealmだけおくる', () => { test('一般リクエスト', async () => { - const result = await api('/admin/get-index-stats', {}); + const result = await api('admin/get-index-stats', {}); assert.strictEqual(result.status, 401); assert.strictEqual(result.headers.get('WWW-Authenticate'), 'Bearer realm="Misskey"'); }); @@ -259,7 +259,8 @@ describe('API', () => { }); test('invalid_request', async () => { - const result = await api('/notes/create', { text: true }, { + // @ts-expect-error text must be string + const result = await api('notes/create', { text: true }, { token: alice.token, bearer: true, }); diff --git a/packages/backend/test/e2e/block.ts b/packages/backend/test/e2e/block.ts index 1dfc87c64f..e4f798498f 100644 --- a/packages/backend/test/e2e/block.ts +++ b/packages/backend/test/e2e/block.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -22,7 +22,7 @@ describe('Block', () => { }, 1000 * 60 * 2); test('Block作成', async () => { - const res = await api('/blocking/create', { + const res = await api('blocking/create', { userId: bob.id, }, alice); @@ -30,7 +30,7 @@ describe('Block', () => { }); test('ブロックされているユーザーをフォローできない', async () => { - const res = await api('/following/create', { userId: alice.id }, bob); + const res = await api('following/create', { userId: alice.id }, bob); assert.strictEqual(res.status, 400); assert.strictEqual(res.body.error.id, 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0'); @@ -39,7 +39,7 @@ describe('Block', () => { test('ブロックされているユーザーにリアクションできない', async () => { const note = await post(alice, { text: 'hello' }); - const res = await api('/notes/reactions/create', { noteId: note.id, reaction: '👍' }, bob); + const res = await api('notes/reactions/create', { noteId: note.id, reaction: '👍' }, bob); assert.strictEqual(res.status, 400); assert.strictEqual(res.body.error.id, '20ef5475-9f38-4e4c-bd33-de6d979498ec'); @@ -48,7 +48,7 @@ describe('Block', () => { test('ブロックされているユーザーに返信できない', async () => { const note = await post(alice, { text: 'hello' }); - const res = await api('/notes/create', { replyId: note.id, text: 'yo' }, bob); + const res = await api('notes/create', { replyId: note.id, text: 'yo' }, bob); assert.strictEqual(res.status, 400); assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3'); @@ -57,7 +57,7 @@ describe('Block', () => { test('ブロックされているユーザーのノートをRenoteできない', async () => { const note = await post(alice, { text: 'hello' }); - const res = await api('/notes/create', { renoteId: note.id, text: 'yo' }, bob); + const res = await api('notes/create', { renoteId: note.id, text: 'yo' }, bob); assert.strictEqual(res.status, 400); assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3'); @@ -72,12 +72,13 @@ describe('Block', () => { const bobNote = await post(bob, { text: 'hi' }); const carolNote = await post(carol, { text: 'hi' }); - const res = await api('/notes/local-timeline', {}, bob); + const res = await api('notes/local-timeline', {}, bob); + const body = res.body as misskey.entities.Note[]; assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); + assert.strictEqual(body.some(note => note.id === aliceNote.id), false); + assert.strictEqual(body.some(note => note.id === bobNote.id), true); + assert.strictEqual(body.some(note => note.id === carolNote.id), true); }); }); diff --git a/packages/backend/test/e2e/clips.ts b/packages/backend/test/e2e/clips.ts index b679eea8cf..ba6f9d6a65 100644 --- a/packages/backend/test/e2e/clips.ts +++ b/packages/backend/test/e2e/clips.ts @@ -1,52 +1,39 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { JTDDataType } from 'ajv/dist/jtd'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; -import type { Packed } from '@/misc/json-schema.js'; -import { paramDef as CreateParamDef } from '@/server/api/endpoints/clips/create.js'; -import { paramDef as UpdateParamDef } from '@/server/api/endpoints/clips/update.js'; -import { paramDef as DeleteParamDef } from '@/server/api/endpoints/clips/delete.js'; -import { paramDef as ShowParamDef } from '@/server/api/endpoints/clips/show.js'; -import { paramDef as FavoriteParamDef } from '@/server/api/endpoints/clips/favorite.js'; -import { paramDef as UnfavoriteParamDef } from '@/server/api/endpoints/clips/unfavorite.js'; -import { paramDef as AddNoteParamDef } from '@/server/api/endpoints/clips/add-note.js'; -import { paramDef as RemoveNoteParamDef } from '@/server/api/endpoints/clips/remove-note.js'; -import { paramDef as NotesParamDef } from '@/server/api/endpoints/clips/notes.js'; import { api, ApiRequest, failedApiCall, hiddenNote, post, signup, successfulApiCall } from '../utils.js'; +import type * as Misskey from 'misskey-js'; + +type Optional = Pick, K> & Omit; describe('クリップ', () => { - type User = Packed<'User'>; - type Note = Packed<'Note'>; - type Clip = Packed<'Clip'>; - - let alice: User; - let bob: User; - let aliceNote: Note; - let aliceHomeNote: Note; - let aliceFollowersNote: Note; - let aliceSpecifiedNote: Note; - let bobNote: Note; - let bobHomeNote: Note; - let bobFollowersNote: Note; - let bobSpecifiedNote: Note; + let alice: Misskey.entities.SignupResponse; + let bob: Misskey.entities.SignupResponse; + let aliceNote: Misskey.entities.Note; + let aliceHomeNote: Misskey.entities.Note; + let aliceFollowersNote: Misskey.entities.Note; + let aliceSpecifiedNote: Misskey.entities.Note; + let bobNote: Misskey.entities.Note; + let bobHomeNote: Misskey.entities.Note; + let bobFollowersNote: Misskey.entities.Note; + let bobSpecifiedNote: Misskey.entities.Note; const compareBy = (selector: (s: T) => string = (s: T): string => s.id) => (a: T, b: T): number => { return selector(a).localeCompare(selector(b)); }; - type CreateParam = JTDDataType; - const defaultCreate = (): Partial => ({ + const defaultCreate = (): Pick => ({ name: 'test', }); - const create = async (parameters: Partial = {}, request: Partial = {}): Promise => { - const clip = await successfulApiCall({ - endpoint: '/clips/create', + const create = async (parameters: Partial = {}, request: Partial> = {}): Promise => { + const clip = await successfulApiCall({ + endpoint: 'clips/create', parameters: { ...defaultCreate(), ...parameters, @@ -64,17 +51,16 @@ describe('クリップ', () => { return clip; }; - const createMany = async (parameters: Partial, count = 10, user = alice): Promise => { + const createMany = async (parameters: Partial, count = 10, user = alice): Promise => { return await Promise.all([...Array(count)].map((_, i) => create({ name: `test${i}`, ...parameters, }, { user }))); }; - type UpdateParam = JTDDataType; - const update = async (parameters: Partial, request: Partial = {}): Promise => { - const clip = await successfulApiCall({ - endpoint: '/clips/update', + const update = async (parameters: Optional, request: Partial> = {}): Promise => { + const clip = await successfulApiCall({ + endpoint: 'clips/update', parameters: { name: 'updated', ...parameters, @@ -92,41 +78,39 @@ describe('クリップ', () => { return clip; }; - type DeleteParam = JTDDataType; - const deleteClip = async (parameters: DeleteParam, request: Partial = {}): Promise => { - return await successfulApiCall({ - endpoint: '/clips/delete', + const deleteClip = async (parameters: Misskey.entities.ClipsDeleteRequest, request: Partial> = {}): Promise => { + return await successfulApiCall({ + endpoint: 'clips/delete', parameters, user: alice, ...request, }, { status: 204, - }); + }) as any as void; }; - type ShowParam = JTDDataType; - const show = async (parameters: ShowParam, request: Partial = {}): Promise => { - return await successfulApiCall({ - endpoint: '/clips/show', + const show = async (parameters: Misskey.entities.ClipsShowRequest, request: Partial> = {}): Promise => { + return await successfulApiCall({ + endpoint: 'clips/show', parameters, user: alice, ...request, }); }; - const list = async (request: Partial): Promise => { - return successfulApiCall({ - endpoint: '/clips/list', + const list = async (request: Partial>): Promise => { + return successfulApiCall({ + endpoint: 'clips/list', parameters: {}, user: alice, ...request, }); }; - const usersClips = async (request: Partial): Promise => { - return await successfulApiCall({ - endpoint: '/users/clips', - parameters: {}, + const usersClips = async (parameters: Misskey.entities.UsersClipsRequest, request: Partial> = {}): Promise => { + return await successfulApiCall({ + endpoint: 'users/clips', + parameters, user: alice, ...request, }); @@ -136,23 +120,22 @@ describe('クリップ', () => { alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); - // FIXME: misskey-jsのNoteはoutdatedなので直接変換できない - aliceNote = await post(alice, { text: 'test' }) as any; - aliceHomeNote = await post(alice, { text: 'home only', visibility: 'home' }) as any; - aliceFollowersNote = await post(alice, { text: 'followers only', visibility: 'followers' }) as any; - aliceSpecifiedNote = await post(alice, { text: 'specified only', visibility: 'specified' }) as any; - bobNote = await post(bob, { text: 'test' }) as any; - bobHomeNote = await post(bob, { text: 'home only', visibility: 'home' }) as any; - bobFollowersNote = await post(bob, { text: 'followers only', visibility: 'followers' }) as any; - bobSpecifiedNote = await post(bob, { text: 'specified only', visibility: 'specified' }) as any; + aliceNote = await post(alice, { text: 'test' }); + aliceHomeNote = await post(alice, { text: 'home only', visibility: 'home' }); + aliceFollowersNote = await post(alice, { text: 'followers only', visibility: 'followers' }); + aliceSpecifiedNote = await post(alice, { text: 'specified only', visibility: 'specified' }); + bobNote = await post(bob, { text: 'test' }); + bobHomeNote = await post(bob, { text: 'home only', visibility: 'home' }); + bobFollowersNote = await post(bob, { text: 'followers only', visibility: 'followers' }); + bobSpecifiedNote = await post(bob, { text: 'specified only', visibility: 'specified' }); }, 1000 * 60 * 2); afterEach(async () => { // テスト間で影響し合わないように毎回全部消す。 for (const user of [alice, bob]) { - const list = await api('/clips/list', { limit: 11 }, user); + const list = await api('clips/list', { limit: 11 }, user); for (const clip of list.body) { - await api('/clips/delete', { clipId: clip.id }, user); + await api('clips/delete', { clipId: clip.id }, user); } } }); @@ -177,7 +160,7 @@ describe('クリップ', () => { } await failedApiCall({ - endpoint: '/clips/create', + endpoint: 'clips/create', parameters: defaultCreate(), user: alice, }, { @@ -204,7 +187,8 @@ describe('クリップ', () => { { label: 'descriptionが最大長+1', parameters: { description: 'a'.repeat(2049) } }, ]; test.each(createClipDenyPattern)('の作成は$labelならできない', async ({ parameters }) => failedApiCall({ - endpoint: '/clips/create', + endpoint: 'clips/create', + // @ts-expect-error invalid params parameters: { ...defaultCreate(), ...parameters, @@ -246,15 +230,15 @@ describe('クリップ', () => { code: 'NO_SUCH_CLIP', id: 'b4d92d70-b216-46fa-9a3f-a8c811699257', } }, - { label: '他人のクリップ', user: (): User => bob, assertion: { + { label: '他人のクリップ', user: () => bob, assertion: { code: 'NO_SUCH_CLIP', id: 'b4d92d70-b216-46fa-9a3f-a8c811699257', } }, ...createClipDenyPattern as any, ])('の更新は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({ - endpoint: '/clips/update', + endpoint: 'clips/update', parameters: { - clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id, + clipId: (await create({}, { user: (user ?? (() => alice))() })).id, name: 'updated', ...parameters, }, @@ -279,14 +263,15 @@ describe('クリップ', () => { code: 'NO_SUCH_CLIP', id: '70ca08ba-6865-4630-b6fb-8494759aa754', } }, - { label: '他人のクリップ', user: (): User => bob, assertion: { + { label: '他人のクリップ', user: () => bob, assertion: { code: 'NO_SUCH_CLIP', id: '70ca08ba-6865-4630-b6fb-8494759aa754', } }, ])('の削除は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({ - endpoint: '/clips/delete', + endpoint: 'clips/delete', parameters: { - clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id, + // @ts-expect-error clipId must not be null + clipId: (await create({}, { user: (user ?? (() => alice))() })).id, ...parameters, }, user: alice, @@ -306,7 +291,7 @@ describe('クリップ', () => { test('のID指定取得は他人のPrivateなクリップは取得できない', async () => { const clip = await create({ isPublic: false }, { user: bob } ); failedApiCall({ - endpoint: '/clips/show', + endpoint: 'clips/show', parameters: { clipId: clip.id }, user: alice, }, { @@ -323,7 +308,8 @@ describe('クリップ', () => { id: 'c3c5fe33-d62c-44d2-9ea5-d997703f5c20', } }, ])('のID指定取得は$labelならできない', async ({ parameters, assetion }) => failedApiCall({ - endpoint: '/clips/show', + endpoint: 'clips/show', + // @ts-expect-error clipId must not be undefined parameters: { ...parameters, }, @@ -356,27 +342,23 @@ describe('クリップ', () => { test('の一覧が取得できる(空)', async () => { const res = await usersClips({ - parameters: { - userId: alice.id, - }, + userId: alice.id, }); assert.deepStrictEqual(res, []); }); test.each([ { label: '' }, - { label: '他人アカウントから', user: (): User => bob }, + { label: '他人アカウントから', user: () => bob }, ])('の一覧が$label取得できる', async () => { const clips = await createMany({ isPublic: true }); const res = await usersClips({ - parameters: { - userId: alice.id, - }, + userId: alice.id, }); // 返ってくる配列には順序保障がないのでidでソートして厳密比較 assert.deepStrictEqual( - res.sort(compareBy(s => s.id)), + res.sort(compareBy(s => s.id)), clips.sort(compareBy(s => s.id))); // 認証状態で見たときだけisFavoritedが入っている @@ -386,17 +368,16 @@ describe('クリップ', () => { }); test.each([ - { label: '未認証', user: (): undefined => undefined }, + { label: '未認証', user: () => undefined }, { label: '存在しないユーザーのもの', parameters: { userId: 'xxxxxxx' } }, ])('の一覧は$labelでも取得できる', async ({ parameters, user }) => { const clips = await createMany({ isPublic: true }); const res = await usersClips({ - parameters: { - userId: alice.id, - limit: clips.length, - ...parameters, - }, - user: (user ?? ((): User => alice))(), + userId: alice.id, + limit: clips.length, + ...parameters, + }, { + user: (user ?? (() => alice))(), }); // 未認証で見たときはisFavoritedは入らない @@ -409,10 +390,8 @@ describe('クリップ', () => { await create({ isPublic: false }); const aliceClip = await create({ isPublic: true }); const res = await usersClips({ - parameters: { - userId: alice.id, - limit: 2, - }, + userId: alice.id, + limit: 2, }); assert.deepStrictEqual(res, [aliceClip]); }); @@ -421,17 +400,15 @@ describe('クリップ', () => { const clips = await createMany({ isPublic: true }, 7); clips.sort(compareBy(s => s.id)); const res = await usersClips({ - parameters: { - userId: alice.id, - sinceId: clips[1].id, - untilId: clips[5].id, - limit: 4, - }, + userId: alice.id, + sinceId: clips[1].id, + untilId: clips[5].id, + limit: 4, }); // Promise.allで返ってくる配列には順序保障がないのでidでソートして厳密比較 assert.deepStrictEqual( - res.sort(compareBy(s => s.id)), + res.sort(compareBy(s => s.id)), [clips[2], clips[3], clips[4]], // sinceIdとuntilId自体は結果に含まれない clips[1].id + ' ... ' + clips[3].id + ' with ' + clips.map(s => s.id) + ' vs. ' + res.map(s => s.id)); }); @@ -441,8 +418,9 @@ describe('クリップ', () => { { label: 'limitゼロ', parameters: { limit: 0 } }, { label: 'limit最大+1', parameters: { limit: 101 } }, ])('の一覧は$labelだと取得できない', async ({ parameters }) => failedApiCall({ - endpoint: '/users/clips', + endpoint: 'users/clips', parameters: { + // @ts-expect-error userId must not be undefined userId: alice.id, ...parameters, }, @@ -454,15 +432,15 @@ describe('クリップ', () => { })); test.each([ - { label: '作成', endpoint: '/clips/create' }, - { label: '更新', endpoint: '/clips/update' }, - { label: '削除', endpoint: '/clips/delete' }, - { label: '取得', endpoint: '/clips/list' }, - { label: 'お気に入り設定', endpoint: '/clips/favorite' }, - { label: 'お気に入り解除', endpoint: '/clips/unfavorite' }, - { label: 'お気に入り取得', endpoint: '/clips/my-favorites' }, - { label: 'ノート追加', endpoint: '/clips/add-note' }, - { label: 'ノート削除', endpoint: '/clips/remove-note' }, + { label: '作成', endpoint: 'clips/create' as const }, + { label: '更新', endpoint: 'clips/update' as const }, + { label: '削除', endpoint: 'clips/delete' as const }, + { label: '取得', endpoint: 'clips/list' as const }, + { label: 'お気に入り設定', endpoint: 'clips/favorite' as const }, + { label: 'お気に入り解除', endpoint: 'clips/unfavorite' as const }, + { label: 'お気に入り取得', endpoint: 'clips/my-favorites' as const }, + { label: 'ノート追加', endpoint: 'clips/add-note' as const }, + { label: 'ノート削除', endpoint: 'clips/remove-note' as const }, ])('の$labelは未認証ではできない', async ({ endpoint }) => await failedApiCall({ endpoint: endpoint, parameters: {}, @@ -474,35 +452,33 @@ describe('クリップ', () => { })); describe('のお気に入り', () => { - let aliceClip: Clip; + let aliceClip: Misskey.entities.Clip; - type FavoriteParam = JTDDataType; - const favorite = async (parameters: FavoriteParam, request: Partial = {}): Promise => { - return successfulApiCall({ - endpoint: '/clips/favorite', + const favorite = async (parameters: Misskey.entities.ClipsFavoriteRequest, request: Partial> = {}): Promise => { + return successfulApiCall({ + endpoint: 'clips/favorite', parameters, user: alice, ...request, }, { status: 204, - }); + }) as any as void; }; - type UnfavoriteParam = JTDDataType; - const unfavorite = async (parameters: UnfavoriteParam, request: Partial = {}): Promise => { - return successfulApiCall({ - endpoint: '/clips/unfavorite', + const unfavorite = async (parameters: Misskey.entities.ClipsUnfavoriteRequest, request: Partial> = {}): Promise => { + return successfulApiCall({ + endpoint: 'clips/unfavorite', parameters, user: alice, ...request, }, { status: 204, - }); + }) as any as void; }; - const myFavorites = async (request: Partial = {}): Promise => { - return successfulApiCall({ - endpoint: '/clips/my-favorites', + const myFavorites = async (request: Partial> = {}): Promise => { + return successfulApiCall({ + endpoint: 'clips/my-favorites', parameters: {}, user: alice, ...request, @@ -568,7 +544,7 @@ describe('クリップ', () => { test('は同じクリップに対して二回設定できない。', async () => { await favorite({ clipId: aliceClip.id }); await failedApiCall({ - endpoint: '/clips/favorite', + endpoint: 'clips/favorite', parameters: { clipId: aliceClip.id, }, @@ -586,14 +562,15 @@ describe('クリップ', () => { code: 'NO_SUCH_CLIP', id: '4c2aaeae-80d8-4250-9606-26cb1fdb77a5', } }, - { label: '他人のクリップ', user: (): User => bob, assertion: { + { label: '他人のクリップ', user: () => bob, assertion: { code: 'NO_SUCH_CLIP', id: '4c2aaeae-80d8-4250-9606-26cb1fdb77a5', } }, ])('の設定は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({ - endpoint: '/clips/favorite', + endpoint: 'clips/favorite', parameters: { - clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id, + // @ts-expect-error clipId must not be null + clipId: (await create({}, { user: (user ?? (() => alice))() })).id, ...parameters, }, user: alice, @@ -619,7 +596,7 @@ describe('クリップ', () => { code: 'NO_SUCH_CLIP', id: '2603966e-b865-426c-94a7-af4a01241dc1', } }, - { label: '他人のクリップ', user: (): User => bob, assertion: { + { label: '他人のクリップ', user: () => bob, assertion: { code: 'NOT_FAVORITED', id: '90c3a9e8-b321-4dae-bf57-2bf79bbcc187', } }, @@ -628,9 +605,10 @@ describe('クリップ', () => { id: '90c3a9e8-b321-4dae-bf57-2bf79bbcc187', } }, ])('の設定解除は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({ - endpoint: '/clips/unfavorite', + endpoint: 'clips/unfavorite', parameters: { - clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id, + // @ts-expect-error clipId must not be null + clipId: (await create({}, { user: (user ?? (() => alice))() })).id, ...parameters, }, user: alice, @@ -655,41 +633,38 @@ describe('クリップ', () => { }); describe('に紐づくノート', () => { - let aliceClip: Clip; + let aliceClip: Misskey.entities.Clip; - const sampleNotes = (): Note[] => [ + const sampleNotes = (): Misskey.entities.Note[] => [ aliceNote, aliceHomeNote, aliceFollowersNote, aliceSpecifiedNote, bobNote, bobHomeNote, bobFollowersNote, bobSpecifiedNote, ]; - type AddNoteParam = JTDDataType; - const addNote = async (parameters: AddNoteParam, request: Partial = {}): Promise => { - return successfulApiCall({ - endpoint: '/clips/add-note', + const addNote = async (parameters: Misskey.entities.ClipsAddNoteRequest, request: Partial> = {}): Promise => { + return successfulApiCall({ + endpoint: 'clips/add-note', parameters, user: alice, ...request, }, { status: 204, - }); + }) as any as void; }; - type RemoveNoteParam = JTDDataType; - const removeNote = async (parameters: RemoveNoteParam, request: Partial = {}): Promise => { - return successfulApiCall({ - endpoint: '/clips/remove-note', + const removeNote = async (parameters: Misskey.entities.ClipsRemoveNoteRequest, request: Partial> = {}): Promise => { + return successfulApiCall({ + endpoint: 'clips/remove-note', parameters, user: alice, ...request, }, { status: 204, - }); + }) as any as void; }; - type NotesParam = JTDDataType; - const notes = async (parameters: Partial, request: Partial = {}): Promise => { - return successfulApiCall({ - endpoint: '/clips/notes', + const notes = async (parameters: Misskey.entities.ClipsNotesRequest, request: Partial> = {}): Promise => { + return successfulApiCall({ + endpoint: 'clips/notes', parameters, user: alice, ...request, @@ -715,7 +690,7 @@ describe('クリップ', () => { test('として同じノートを二回紐づけることはできない', async () => { await addNote({ clipId: aliceClip.id, noteId: aliceNote.id }); await failedApiCall({ - endpoint: '/clips/add-note', + endpoint: 'clips/add-note', parameters: { clipId: aliceClip.id, noteId: aliceNote.id, @@ -733,11 +708,11 @@ describe('クリップ', () => { const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit + 1; const noteList = await Promise.all([...Array(noteLimit)].map((_, i) => post(alice, { text: `test ${i}`, - }) as unknown)) as Note[]; + }) as unknown)) as Misskey.entities.Note[]; await Promise.all(noteList.map(s => addNote({ clipId: aliceClip.id, noteId: s.id }))); await failedApiCall({ - endpoint: '/clips/add-note', + endpoint: 'clips/add-note', parameters: { clipId: aliceClip.id, noteId: aliceNote.id, @@ -751,7 +726,7 @@ describe('クリップ', () => { }); test('は他人のクリップへ追加できない。', async () => await failedApiCall({ - endpoint: '/clips/add-note', + endpoint: 'clips/add-note', parameters: { clipId: aliceClip.id, noteId: aliceNote.id, @@ -774,18 +749,20 @@ describe('クリップ', () => { code: 'NO_SUCH_NOTE', id: 'fc8c0b49-c7a3-4664-a0a6-b418d386bb8b', } }, - { label: '他人のクリップ', user: (): object => bob, assetion: { + { label: '他人のクリップ', user: () => bob, assetion: { code: 'NO_SUCH_CLIP', id: 'd6e76cc0-a1b5-4c7c-a287-73fa9c716dcf', } }, ])('の追加は$labelだとできない', async ({ parameters, user, assetion }) => failedApiCall({ - endpoint: '/clips/add-note', + endpoint: 'clips/add-note', parameters: { + // @ts-expect-error clipId must not be undefined clipId: aliceClip.id, + // @ts-expect-error noteId must not be undefined noteId: aliceNote.id, ...parameters, }, - user: (user ?? ((): User => alice))(), + user: (user ?? (() => alice))(), }, { status: 400, code: 'INVALID_PARAM', @@ -810,18 +787,20 @@ describe('クリップ', () => { code: 'NO_SUCH_NOTE', id: 'aff017de-190e-434b-893e-33a9ff5049d8', // add-noteと異なる } }, - { label: '他人のクリップ', user: (): object => bob, assetion: { + { label: '他人のクリップ', user: () => bob, assetion: { code: 'NO_SUCH_CLIP', id: 'b80525c6-97f7-49d7-a42d-ebccd49cfd52', // add-noteと異なる } }, ])('の削除は$labelだとできない', async ({ parameters, user, assetion }) => failedApiCall({ - endpoint: '/clips/remove-note', + endpoint: 'clips/remove-note', parameters: { + // @ts-expect-error clipId must not be undefined clipId: aliceClip.id, + // @ts-expect-error noteId must not be undefined noteId: aliceNote.id, ...parameters, }, - user: (user ?? ((): User => alice))(), + user: (user ?? (() => alice))(), }, { status: 400, code: 'INVALID_PARAM', @@ -925,21 +904,22 @@ describe('クリップ', () => { code: 'NO_SUCH_CLIP', id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00', } }, - { label: '他人のPrivateなクリップから', user: (): object => bob, assertion: { + { label: '他人のPrivateなクリップから', user: () => bob, assertion: { code: 'NO_SUCH_CLIP', id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00', } }, - { label: '未認証でPrivateなクリップから', user: (): undefined => undefined, assertion: { + { label: '未認証でPrivateなクリップから', user: () => undefined, assertion: { code: 'NO_SUCH_CLIP', id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00', } }, ])('は$labelだと取得できない', async ({ parameters, user, assertion }) => failedApiCall({ - endpoint: '/clips/notes', + endpoint: 'clips/notes', parameters: { + // @ts-expect-error clipId must not be undefined clipId: aliceClip.id, ...parameters, }, - user: (user ?? ((): User => alice))(), + user: (user ?? (() => alice))(), }, { status: 400, code: 'INVALID_PARAM', diff --git a/packages/backend/test/e2e/drive.ts b/packages/backend/test/e2e/drive.ts index 3a84961fc7..828c5200ef 100644 --- a/packages/backend/test/e2e/drive.ts +++ b/packages/backend/test/e2e/drive.ts @@ -1,27 +1,19 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { MiNote } from '@/models/Note.js'; -import { api, initTestDb, makeStreamCatcher, post, signup, uploadFile } from '../utils.js'; +import { api, makeStreamCatcher, post, signup, uploadFile } from '../utils.js'; import type * as misskey from 'misskey-js'; -import type{ Repository } from 'typeorm' -import type { Packed } from '@/misc/json-schema.js'; - describe('Drive', () => { - let Notes: Repository; - let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; beforeAll(async () => { - const connection = await initTestDb(true); - Notes = connection.getRepository(MiNote); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); }, 1000 * 60 * 2); @@ -31,13 +23,13 @@ describe('Drive', () => { const marker = Math.random().toString(); - const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg' + const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'; const catcher = makeStreamCatcher( alice, 'main', (msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker, - (msg) => msg.body.file as Packed<'DriveFile'>, + (msg) => msg.body.file, 10 * 1000); const res = await api('drive/files/upload-from-url', { @@ -51,7 +43,7 @@ describe('Drive', () => { assert.strictEqual(res.status, 204); assert.strictEqual(file.name, 'Lenna.jpg'); assert.strictEqual(file.type, 'image/jpeg'); - }) + }); test('ローカルからアップロードできる', async () => { // APIレスポンスを直接使用するので utils.js uploadFile が通過することで成功とする @@ -59,27 +51,27 @@ describe('Drive', () => { const res = await uploadFile(alice, { path: 'Lenna.jpg', name: 'テスト画像' }); assert.strictEqual(res.body?.name, 'テスト画像.jpg'); - assert.strictEqual(res.body?.type, 'image/jpeg'); - }) + assert.strictEqual(res.body.type, 'image/jpeg'); + }); test('添付ノート一覧を取得できる', async () => { - const ids = (await Promise.all([uploadFile(alice), uploadFile(alice), uploadFile(alice)])).map(elm => elm.body!.id) + const ids = (await Promise.all([uploadFile(alice), uploadFile(alice), uploadFile(alice)])).map(elm => elm.body!.id); const note0 = await post(alice, { fileIds: [ids[0]] }); const note1 = await post(alice, { fileIds: [ids[0], ids[1]] }); const attached0 = await api('drive/files/attached-notes', { fileId: ids[0] }, alice); assert.strictEqual(attached0.body.length, 2); - assert.strictEqual(attached0.body[0].id, note1.id) - assert.strictEqual(attached0.body[1].id, note0.id) + assert.strictEqual(attached0.body[0].id, note1.id); + assert.strictEqual(attached0.body[1].id, note0.id); const attached1 = await api('drive/files/attached-notes', { fileId: ids[1] }, alice); assert.strictEqual(attached1.body.length, 1); - assert.strictEqual(attached1.body[0].id, note1.id) + assert.strictEqual(attached1.body[0].id, note1.id); const attached2 = await api('drive/files/attached-notes', { fileId: ids[2] }, alice); - assert.strictEqual(attached2.body.length, 0) - }) + assert.strictEqual(attached2.body.length, 0); + }); test('添付ノート一覧は他の人から見えない', async () => { const file = await uploadFile(alice); @@ -89,7 +81,5 @@ describe('Drive', () => { const res = await api('drive/files/attached-notes', { fileId: file.body!.id }, bob); assert.strictEqual(res.status, 400); assert.strictEqual('error' in res.body, true); - - }) + }); }); - diff --git a/packages/backend/test/e2e/endpoints.ts b/packages/backend/test/e2e/endpoints.ts index b12b062a63..bc89dc37f4 100644 --- a/packages/backend/test/e2e/endpoints.ts +++ b/packages/backend/test/e2e/endpoints.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -79,6 +79,7 @@ describe('Endpoints', () => { test('クエリをインジェクションできない', async () => { const res = await api('signin', { username: 'test1', + // @ts-expect-error password must be string password: { $gt: '', }, @@ -103,7 +104,7 @@ describe('Endpoints', () => { const myLocation = '七森中'; const myBirthday = '2000-09-07'; - const res = await api('/i/update', { + const res = await api('i/update', { name: myName, location: myLocation, birthday: myBirthday, @@ -117,7 +118,7 @@ describe('Endpoints', () => { }); test('名前を空白にできる', async () => { - const res = await api('/i/update', { + const res = await api('i/update', { name: ' ', }, alice); assert.strictEqual(res.status, 200); @@ -125,11 +126,11 @@ describe('Endpoints', () => { }); test('誕生日の設定を削除できる', async () => { - await api('/i/update', { + await api('i/update', { birthday: '2000-09-07', }, alice); - const res = await api('/i/update', { + const res = await api('i/update', { birthday: null, }, alice); @@ -139,7 +140,7 @@ describe('Endpoints', () => { }); test('不正な誕生日の形式で怒られる', async () => { - const res = await api('/i/update', { + const res = await api('i/update', { birthday: '2000/09/07', }, alice); assert.strictEqual(res.status, 400); @@ -148,7 +149,7 @@ describe('Endpoints', () => { describe('users/show', () => { test('ユーザーが取得できる', async () => { - const res = await api('/users/show', { + const res = await api('users/show', { userId: alice.id, }, alice); @@ -158,14 +159,14 @@ describe('Endpoints', () => { }); test('ユーザーが存在しなかったら怒る', async () => { - const res = await api('/users/show', { + const res = await api('users/show', { userId: '000000000000000000000000', }); assert.strictEqual(res.status, 404); }); test('間違ったIDで怒られる', async () => { - const res = await api('/users/show', { + const res = await api('users/show', { userId: 'kyoppie', }); assert.strictEqual(res.status, 404); @@ -178,7 +179,7 @@ describe('Endpoints', () => { text: 'test', }); - const res = await api('/notes/show', { + const res = await api('notes/show', { noteId: myPost.id, }, alice); @@ -189,14 +190,14 @@ describe('Endpoints', () => { }); test('投稿が存在しなかったら怒る', async () => { - const res = await api('/notes/show', { + const res = await api('notes/show', { noteId: '000000000000000000000000', }); assert.strictEqual(res.status, 400); }); test('間違ったIDで怒られる', async () => { - const res = await api('/notes/show', { + const res = await api('notes/show', { noteId: 'kyoppie', }); assert.strictEqual(res.status, 400); @@ -207,14 +208,14 @@ describe('Endpoints', () => { test('リアクションできる', async () => { const bobPost = await post(bob, { text: 'hi' }); - const res = await api('/notes/reactions/create', { + const res = await api('notes/reactions/create', { noteId: bobPost.id, reaction: '🚀', }, alice); assert.strictEqual(res.status, 204); - const resNote = await api('/notes/show', { + const resNote = await api('notes/show', { noteId: bobPost.id, }, alice); @@ -225,7 +226,7 @@ describe('Endpoints', () => { test('自分の投稿にもリアクションできる', async () => { const myPost = await post(alice, { text: 'hi' }); - const res = await api('/notes/reactions/create', { + const res = await api('notes/reactions/create', { noteId: myPost.id, reaction: '🚀', }, alice); @@ -236,19 +237,19 @@ describe('Endpoints', () => { test('二重にリアクションすると上書きされる', async () => { const bobPost = await post(bob, { text: 'hi' }); - await api('/notes/reactions/create', { + await api('notes/reactions/create', { noteId: bobPost.id, reaction: '🥰', }, alice); - const res = await api('/notes/reactions/create', { + const res = await api('notes/reactions/create', { noteId: bobPost.id, reaction: '🚀', }, alice); assert.strictEqual(res.status, 204); - const resNote = await api('/notes/show', { + const resNote = await api('notes/show', { noteId: bobPost.id, }, alice); @@ -257,7 +258,7 @@ describe('Endpoints', () => { }); test('存在しない投稿にはリアクションできない', async () => { - const res = await api('/notes/reactions/create', { + const res = await api('notes/reactions/create', { noteId: '000000000000000000000000', reaction: '🚀', }, alice); @@ -266,13 +267,14 @@ describe('Endpoints', () => { }); test('空のパラメータで怒られる', async () => { - const res = await api('/notes/reactions/create', {}, alice); + // @ts-expect-error param must not be empty + const res = await api('notes/reactions/create', {}, alice); assert.strictEqual(res.status, 400); }); test('間違ったIDで怒られる', async () => { - const res = await api('/notes/reactions/create', { + const res = await api('notes/reactions/create', { noteId: 'kyoppie', reaction: '🚀', }, alice); @@ -283,7 +285,7 @@ describe('Endpoints', () => { describe('following/create', () => { test('フォローできる', async () => { - const res = await api('/following/create', { + const res = await api('following/create', { userId: alice.id, }, bob); @@ -301,7 +303,7 @@ describe('Endpoints', () => { }); test('既にフォローしている場合は怒る', async () => { - const res = await api('/following/create', { + const res = await api('following/create', { userId: alice.id, }, bob); @@ -309,7 +311,7 @@ describe('Endpoints', () => { }); test('存在しないユーザーはフォローできない', async () => { - const res = await api('/following/create', { + const res = await api('following/create', { userId: '000000000000000000000000', }, alice); @@ -317,7 +319,7 @@ describe('Endpoints', () => { }); test('自分自身はフォローできない', async () => { - const res = await api('/following/create', { + const res = await api('following/create', { userId: alice.id, }, alice); @@ -325,13 +327,14 @@ describe('Endpoints', () => { }); test('空のパラメータで怒られる', async () => { - const res = await api('/following/create', {}, alice); + // @ts-expect-error params must not be empty + const res = await api('following/create', {}, alice); assert.strictEqual(res.status, 400); }); test('間違ったIDで怒られる', async () => { - const res = await api('/following/create', { + const res = await api('following/create', { userId: 'foo', }, alice); @@ -341,11 +344,11 @@ describe('Endpoints', () => { describe('following/delete', () => { test('フォロー解除できる', async () => { - await api('/following/create', { + await api('following/create', { userId: alice.id, }, bob); - const res = await api('/following/delete', { + const res = await api('following/delete', { userId: alice.id, }, bob); @@ -363,7 +366,7 @@ describe('Endpoints', () => { }); test('フォローしていない場合は怒る', async () => { - const res = await api('/following/delete', { + const res = await api('following/delete', { userId: alice.id, }, bob); @@ -371,7 +374,7 @@ describe('Endpoints', () => { }); test('存在しないユーザーはフォロー解除できない', async () => { - const res = await api('/following/delete', { + const res = await api('following/delete', { userId: '000000000000000000000000', }, alice); @@ -379,7 +382,7 @@ describe('Endpoints', () => { }); test('自分自身はフォロー解除できない', async () => { - const res = await api('/following/delete', { + const res = await api('following/delete', { userId: alice.id, }, alice); @@ -387,13 +390,14 @@ describe('Endpoints', () => { }); test('空のパラメータで怒られる', async () => { - const res = await api('/following/delete', {}, alice); + // @ts-expect-error params must not be empty + const res = await api('following/delete', {}, alice); assert.strictEqual(res.status, 400); }); test('間違ったIDで怒られる', async () => { - const res = await api('/following/delete', { + const res = await api('following/delete', { userId: 'kyoppie', }, alice); @@ -403,20 +407,20 @@ describe('Endpoints', () => { describe('channels/search', () => { test('空白検索で一覧を取得できる', async () => { - await api('/channels/create', { + await api('channels/create', { name: 'aaa', description: 'bbb', }, bob); - await api('/channels/create', { + await api('channels/create', { name: 'ccc1', description: 'ddd1', }, bob); - await api('/channels/create', { + await api('channels/create', { name: 'ccc2', description: 'ddd2', }, bob); - const res = await api('/channels/search', { + const res = await api('channels/search', { query: '', }, bob); @@ -425,7 +429,7 @@ describe('Endpoints', () => { assert.strictEqual(res.body.length, 3); }); test('名前のみの検索で名前を検索できる', async () => { - const res = await api('/channels/search', { + const res = await api('channels/search', { query: 'aaa', type: 'nameOnly', }, bob); @@ -436,7 +440,7 @@ describe('Endpoints', () => { assert.strictEqual(res.body[0].name, 'aaa'); }); test('名前のみの検索で名前を複数検索できる', async () => { - const res = await api('/channels/search', { + const res = await api('channels/search', { query: 'ccc', type: 'nameOnly', }, bob); @@ -446,7 +450,7 @@ describe('Endpoints', () => { assert.strictEqual(res.body.length, 2); }); test('名前のみの検索で説明は検索できない', async () => { - const res = await api('/channels/search', { + const res = await api('channels/search', { query: 'bbb', type: 'nameOnly', }, bob); @@ -456,7 +460,7 @@ describe('Endpoints', () => { assert.strictEqual(res.body.length, 0); }); test('名前と説明の検索で名前を検索できる', async () => { - const res = await api('/channels/search', { + const res = await api('channels/search', { query: 'ccc1', }, bob); @@ -466,7 +470,7 @@ describe('Endpoints', () => { assert.strictEqual(res.body[0].name, 'ccc1'); }); test('名前と説明での検索で説明を検索できる', async () => { - const res = await api('/channels/search', { + const res = await api('channels/search', { query: 'ddd1', }, bob); @@ -476,7 +480,7 @@ describe('Endpoints', () => { assert.strictEqual(res.body[0].name, 'ccc1'); }); test('名前と説明の検索で名前を複数検索できる', async () => { - const res = await api('/channels/search', { + const res = await api('channels/search', { query: 'ccc', }, bob); @@ -485,7 +489,7 @@ describe('Endpoints', () => { assert.strictEqual(res.body.length, 2); }); test('名前と説明での検索で説明を複数検索できる', async () => { - const res = await api('/channels/search', { + const res = await api('channels/search', { query: 'ddd', }, bob); @@ -506,7 +510,7 @@ describe('Endpoints', () => { await uploadFile(alice, { blob: new Blob([new Uint8Array(1024)]), }); - const res = await api('/drive', {}, alice); + const res = await api('drive', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); expect(res.body).toHaveProperty('usage', 1792); @@ -519,7 +523,7 @@ describe('Endpoints', () => { assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.name, 'Lenna.jpg'); + assert.strictEqual(res.body!.name, 'Lenna.jpg'); }); test('ファイルに名前を付けられる', async () => { @@ -527,7 +531,7 @@ describe('Endpoints', () => { assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.name, 'Belmond.jpg'); + assert.strictEqual(res.body!.name, 'Belmond.jpg'); }); test('ファイルに名前を付けられるが、拡張子は正しいものになる', async () => { @@ -535,11 +539,12 @@ describe('Endpoints', () => { assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.name, 'Belmond.png.jpg'); + assert.strictEqual(res.body!.name, 'Belmond.png.jpg'); }); test('ファイル無しで怒られる', async () => { - const res = await api('/drive/files/create', {}, alice); + // @ts-expect-error params must not be empty + const res = await api('drive/files/create', {}, alice); assert.strictEqual(res.status, 400); }); @@ -549,14 +554,14 @@ describe('Endpoints', () => { assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.name, 'image.svg'); - assert.strictEqual(res.body.type, 'image/svg+xml'); + assert.strictEqual(res.body!.name, 'image.svg'); + assert.strictEqual(res.body!.type, 'image/svg+xml'); }); for (const type of ['webp', 'avif']) { const mediaType = `image/${type}`; - const getWebpublicType = async (user: any, fileId: string): Promise => { + const getWebpublicType = async (user: misskey.entities.SignupResponse, fileId: string): Promise => { // drive/files/create does not expose webpublicType directly, so get it by posting it const res = await post(user, { text: mediaType, @@ -573,10 +578,10 @@ describe('Endpoints', () => { const res = await uploadFile(alice, { path }); assert.strictEqual(res.status, 200); - assert.strictEqual(res.body.name, path); - assert.strictEqual(res.body.type, mediaType); + assert.strictEqual(res.body!.name, path); + assert.strictEqual(res.body!.type, mediaType); - const webpublicType = await getWebpublicType(alice, res.body.id); + const webpublicType = await getWebpublicType(alice, res.body!.id); assert.strictEqual(webpublicType, 'image/webp'); }); @@ -584,10 +589,10 @@ describe('Endpoints', () => { const path = `without-alpha.${type}`; const res = await uploadFile(alice, { path }); assert.strictEqual(res.status, 200); - assert.strictEqual(res.body.name, path); - assert.strictEqual(res.body.type, mediaType); + assert.strictEqual(res.body!.name, path); + assert.strictEqual(res.body!.type, mediaType); - const webpublicType = await getWebpublicType(alice, res.body.id); + const webpublicType = await getWebpublicType(alice, res.body!.id); assert.strictEqual(webpublicType, 'image/webp'); }); } @@ -598,8 +603,8 @@ describe('Endpoints', () => { const file = (await uploadFile(alice)).body; const newName = 'いちごパスタ.png'; - const res = await api('/drive/files/update', { - fileId: file.id, + const res = await api('drive/files/update', { + fileId: file!.id, name: newName, }, alice); @@ -611,8 +616,8 @@ describe('Endpoints', () => { test('他人のファイルは更新できない', async () => { const file = (await uploadFile(alice)).body; - const res = await api('/drive/files/update', { - fileId: file.id, + const res = await api('drive/files/update', { + fileId: file!.id, name: 'いちごパスタ.png', }, bob); @@ -621,12 +626,12 @@ describe('Endpoints', () => { test('親フォルダを更新できる', async () => { const file = (await uploadFile(alice)).body; - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const res = await api('/drive/files/update', { - fileId: file.id, + const res = await api('drive/files/update', { + fileId: file!.id, folderId: folder.id, }, alice); @@ -638,17 +643,17 @@ describe('Endpoints', () => { test('親フォルダを無しにできる', async () => { const file = (await uploadFile(alice)).body; - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, alice)).body; - await api('/drive/files/update', { - fileId: file.id, + await api('drive/files/update', { + fileId: file!.id, folderId: folder.id, }, alice); - const res = await api('/drive/files/update', { - fileId: file.id, + const res = await api('drive/files/update', { + fileId: file!.id, folderId: null, }, alice); @@ -659,12 +664,12 @@ describe('Endpoints', () => { test('他人のフォルダには入れられない', async () => { const file = (await uploadFile(alice)).body; - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, bob)).body; - const res = await api('/drive/files/update', { - fileId: file.id, + const res = await api('drive/files/update', { + fileId: file!.id, folderId: folder.id, }, alice); @@ -674,8 +679,8 @@ describe('Endpoints', () => { test('存在しないフォルダで怒られる', async () => { const file = (await uploadFile(alice)).body; - const res = await api('/drive/files/update', { - fileId: file.id, + const res = await api('drive/files/update', { + fileId: file!.id, folderId: '000000000000000000000000', }, alice); @@ -685,8 +690,8 @@ describe('Endpoints', () => { test('不正なフォルダIDで怒られる', async () => { const file = (await uploadFile(alice)).body; - const res = await api('/drive/files/update', { - fileId: file.id, + const res = await api('drive/files/update', { + fileId: file!.id, folderId: 'foo', }, alice); @@ -694,7 +699,7 @@ describe('Endpoints', () => { }); test('ファイルが存在しなかったら怒る', async () => { - const res = await api('/drive/files/update', { + const res = await api('drive/files/update', { fileId: '000000000000000000000000', name: 'いちごパスタ.png', }, alice); @@ -706,8 +711,8 @@ describe('Endpoints', () => { const file = (await uploadFile(alice)).body; const newName = ''; - const res = await api('/drive/files/update', { - fileId: file.id, + const res = await api('drive/files/update', { + fileId: file!.id, name: newName, }, alice); @@ -715,7 +720,7 @@ describe('Endpoints', () => { }); test('間違ったIDで怒られる', async () => { - const res = await api('/drive/files/update', { + const res = await api('drive/files/update', { fileId: 'kyoppie', name: 'いちごパスタ.png', }, alice); @@ -726,7 +731,7 @@ describe('Endpoints', () => { describe('drive/folders/create', () => { test('フォルダを作成できる', async () => { - const res = await api('/drive/folders/create', { + const res = await api('drive/folders/create', { name: 'test', }, alice); @@ -738,11 +743,11 @@ describe('Endpoints', () => { describe('drive/folders/update', () => { test('名前を更新できる', async () => { - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: folder.id, name: 'new name', }, alice); @@ -753,11 +758,11 @@ describe('Endpoints', () => { }); test('他人のフォルダを更新できない', async () => { - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, bob)).body; - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: folder.id, name: 'new name', }, alice); @@ -766,14 +771,14 @@ describe('Endpoints', () => { }); test('親フォルダを更新できる', async () => { - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const parentFolder = (await api('/drive/folders/create', { + const parentFolder = (await api('drive/folders/create', { name: 'parent', }, alice)).body; - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: folder.id, parentId: parentFolder.id, }, alice); @@ -784,18 +789,18 @@ describe('Endpoints', () => { }); test('親フォルダを無しに更新できる', async () => { - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const parentFolder = (await api('/drive/folders/create', { + const parentFolder = (await api('drive/folders/create', { name: 'parent', }, alice)).body; - await api('/drive/folders/update', { + await api('drive/folders/update', { folderId: folder.id, parentId: parentFolder.id, }, alice); - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: folder.id, parentId: null, }, alice); @@ -806,14 +811,14 @@ describe('Endpoints', () => { }); test('他人のフォルダを親フォルダに設定できない', async () => { - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const parentFolder = (await api('/drive/folders/create', { + const parentFolder = (await api('drive/folders/create', { name: 'parent', }, bob)).body; - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: folder.id, parentId: parentFolder.id, }, alice); @@ -822,18 +827,18 @@ describe('Endpoints', () => { }); test('フォルダが循環するような構造にできない', async () => { - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const parentFolder = (await api('/drive/folders/create', { + const parentFolder = (await api('drive/folders/create', { name: 'parent', }, alice)).body; - await api('/drive/folders/update', { + await api('drive/folders/update', { folderId: parentFolder.id, parentId: folder.id, }, alice); - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: folder.id, parentId: parentFolder.id, }, alice); @@ -842,25 +847,25 @@ describe('Endpoints', () => { }); test('フォルダが循環するような構造にできない(再帰的)', async () => { - const folderA = (await api('/drive/folders/create', { + const folderA = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const folderB = (await api('/drive/folders/create', { + const folderB = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const folderC = (await api('/drive/folders/create', { + const folderC = (await api('drive/folders/create', { name: 'test', }, alice)).body; - await api('/drive/folders/update', { + await api('drive/folders/update', { folderId: folderB.id, parentId: folderA.id, }, alice); - await api('/drive/folders/update', { + await api('drive/folders/update', { folderId: folderC.id, parentId: folderB.id, }, alice); - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: folderA.id, parentId: folderC.id, }, alice); @@ -869,11 +874,11 @@ describe('Endpoints', () => { }); test('フォルダが循環するような構造にできない(自身)', async () => { - const folderA = (await api('/drive/folders/create', { + const folderA = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: folderA.id, parentId: folderA.id, }, alice); @@ -882,11 +887,11 @@ describe('Endpoints', () => { }); test('存在しない親フォルダを設定できない', async () => { - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: folder.id, parentId: '000000000000000000000000', }, alice); @@ -895,11 +900,11 @@ describe('Endpoints', () => { }); test('不正な親フォルダIDで怒られる', async () => { - const folder = (await api('/drive/folders/create', { + const folder = (await api('drive/folders/create', { name: 'test', }, alice)).body; - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: folder.id, parentId: 'foo', }, alice); @@ -908,7 +913,7 @@ describe('Endpoints', () => { }); test('存在しないフォルダを更新できない', async () => { - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: '000000000000000000000000', }, alice); @@ -916,7 +921,7 @@ describe('Endpoints', () => { }); test('不正なフォルダIDで怒られる', async () => { - const res = await api('/drive/folders/update', { + const res = await api('drive/folders/update', { folderId: 'foo', }, alice); @@ -937,7 +942,7 @@ describe('Endpoints', () => { visibleUserIds: [alice.id], }); - const res = await api('/notes/replies', { + const res = await api('notes/replies', { noteId: alicePost.id, }, carol); @@ -949,7 +954,7 @@ describe('Endpoints', () => { describe('notes/timeline', () => { test('フォロワー限定投稿が含まれる', async () => { - await api('/following/create', { + await api('following/create', { userId: carol.id, }, dave); @@ -958,7 +963,7 @@ describe('Endpoints', () => { visibility: 'followers', }); - const res = await api('/notes/timeline', {}, dave); + const res = await api('notes/timeline', {}, dave); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); @@ -979,12 +984,12 @@ describe('Endpoints', () => { test('他者に関するメモを更新できる', async () => { const memo = '10月まで低浮上とのこと。'; - const res1 = await api('/users/update-memo', { + const res1 = await api('users/update-memo', { memo, userId: bob.id, }, alice); - const res2 = await api('/users/show', { + const res2 = await api('users/show', { userId: bob.id, }, alice); assert.strictEqual(res1.status, 204); @@ -994,12 +999,12 @@ describe('Endpoints', () => { test('自分に関するメモを更新できる', async () => { const memo = 'チケットを月末までに買う。'; - const res1 = await api('/users/update-memo', { + const res1 = await api('users/update-memo', { memo, userId: alice.id, }, alice); - const res2 = await api('/users/show', { + const res2 = await api('users/show', { userId: alice.id, }, alice); assert.strictEqual(res1.status, 204); @@ -1009,17 +1014,17 @@ describe('Endpoints', () => { test('メモを削除できる', async () => { const memo = '10月まで低浮上とのこと。'; - await api('/users/update-memo', { + await api('users/update-memo', { memo, userId: bob.id, }, alice); - await api('/users/update-memo', { + await api('users/update-memo', { memo: '', userId: bob.id, }, alice); - const res = await api('/users/show', { + const res = await api('users/show', { userId: bob.id, }, alice); @@ -1032,21 +1037,21 @@ describe('Endpoints', () => { const memoCarolToBob = '例の件について今度問いただす。'; await Promise.all([ - api('/users/update-memo', { + api('users/update-memo', { memo: memoAliceToBob, userId: bob.id, }, alice), - api('/users/update-memo', { + api('users/update-memo', { memo: memoCarolToBob, userId: bob.id, }, carol), ]); const [resAlice, resCarol] = await Promise.all([ - api('/users/show', { + api('users/show', { userId: bob.id, }, alice), - api('/users/show', { + api('users/show', { userId: bob.id, }, carol), ]); diff --git a/packages/backend/test/e2e/exports.ts b/packages/backend/test/e2e/exports.ts index f9b59144a3..80a5331a6d 100644 --- a/packages/backend/test/e2e/exports.ts +++ b/packages/backend/test/e2e/exports.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -18,7 +18,7 @@ describe('export-clips', () => { // XXX: Any better way to get the result? async function pollFirstDriveFile() { while (true) { - const files = (await api('/drive/files', {}, alice)).body; + const files = (await api('drive/files', {}, alice)).body; if (!files.length) { await new Promise(r => setTimeout(r, 100)); continue; @@ -26,7 +26,7 @@ describe('export-clips', () => { if (files.length > 1) { throw new Error('Too many files?'); } - const file = (await api('/drive/files/show', { fileId: files[0].id }, alice)).body; + const file = (await api('drive/files/show', { fileId: files[0].id }, alice)).body; const res = await fetch(new URL(new URL(file.url).pathname, `http://127.0.0.1:${port}`)); return await res.json(); } @@ -44,16 +44,16 @@ describe('export-clips', () => { beforeEach(async () => { // Clean all clips and files of alice - const clips = (await api('/clips/list', {}, alice)).body; + const clips = (await api('clips/list', {}, alice)).body; for (const clip of clips) { - const res = await api('/clips/delete', { clipId: clip.id }, alice); + const res = await api('clips/delete', { clipId: clip.id }, alice); if (res.status !== 204) { throw new Error('Failed to delete clip'); } } - const files = (await api('/drive/files', {}, alice)).body; + const files = (await api('drive/files', {}, alice)).body; for (const file of files) { - const res = await api('/drive/files/delete', { fileId: file.id }, alice); + const res = await api('drive/files/delete', { fileId: file.id }, alice); if (res.status !== 204) { throw new Error('Failed to delete file'); } @@ -61,13 +61,13 @@ describe('export-clips', () => { }); test('basic export', async () => { - let res = await api('/clips/create', { + let res = await api('clips/create', { name: 'foo', description: 'bar', }, alice); assert.strictEqual(res.status, 200); - res = await api('/i/export-clips', {}, alice); + res = await api('i/export-clips', {}, alice); assert.strictEqual(res.status, 204); const exported = await pollFirstDriveFile(); @@ -77,7 +77,7 @@ describe('export-clips', () => { }); test('export with notes', async () => { - let res = await api('/clips/create', { + let res = await api('clips/create', { name: 'foo', description: 'bar', }, alice); @@ -96,14 +96,14 @@ describe('export-clips', () => { }); for (const note of [note1, note2]) { - res = await api('/clips/add-note', { + res = await api('clips/add-note', { clipId: clip.id, noteId: note.id, }, alice); assert.strictEqual(res.status, 204); } - res = await api('/i/export-clips', {}, alice); + res = await api('i/export-clips', {}, alice); assert.strictEqual(res.status, 204); const exported = await pollFirstDriveFile(); @@ -116,14 +116,14 @@ describe('export-clips', () => { }); test('multiple clips', async () => { - let res = await api('/clips/create', { + let res = await api('clips/create', { name: 'kawaii', description: 'kawaii', }, alice); assert.strictEqual(res.status, 200); const clip1 = res.body; - res = await api('/clips/create', { + res = await api('clips/create', { name: 'yuri', description: 'yuri', }, alice); @@ -138,19 +138,19 @@ describe('export-clips', () => { text: 'baz2', }); - res = await api('/clips/add-note', { + res = await api('clips/add-note', { clipId: clip1.id, noteId: note1.id, }, alice); assert.strictEqual(res.status, 204); - res = await api('/clips/add-note', { + res = await api('clips/add-note', { clipId: clip2.id, noteId: note2.id, }, alice); assert.strictEqual(res.status, 204); - res = await api('/i/export-clips', {}, alice); + res = await api('i/export-clips', {}, alice); assert.strictEqual(res.status, 204); const exported = await pollFirstDriveFile(); @@ -163,7 +163,7 @@ describe('export-clips', () => { }); test('Clipping other user\'s note', async () => { - let res = await api('/clips/create', { + let res = await api('clips/create', { name: 'kawaii', description: 'kawaii', }, alice); @@ -175,13 +175,13 @@ describe('export-clips', () => { visibility: 'followers', }); - res = await api('/clips/add-note', { + res = await api('clips/add-note', { clipId: clip.id, noteId: note.id, }, alice); assert.strictEqual(res.status, 204); - res = await api('/i/export-clips', {}, alice); + res = await api('i/export-clips', {}, alice); assert.strictEqual(res.status, 204); const exported = await pollFirstDriveFile(); diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts index 0d23b4fe67..4851ed14be 100644 --- a/packages/backend/test/e2e/fetch-resource.ts +++ b/packages/backend/test/e2e/fetch-resource.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -23,13 +23,13 @@ const JSON_UTF8 = 'application/json; charset=utf-8'; describe('Webリソース', () => { let alice: misskey.entities.SignupResponse; - let aliceUploadedFile: any; - let alicesPost: any; - let alicePage: any; - let alicePlay: any; - let aliceClip: any; - let aliceGalleryPost: any; - let aliceChannel: any; + let aliceUploadedFile: misskey.entities.DriveFile | null; + let alicesPost: misskey.entities.Note; + let alicePage: misskey.entities.Page; + let alicePlay: misskey.entities.Flash; + let aliceClip: misskey.entities.Clip; + let aliceGalleryPost: misskey.entities.GalleryPost; + let aliceChannel: misskey.entities.Channel; let bob: misskey.entities.SignupResponse; @@ -77,7 +77,7 @@ describe('Webリソース', () => { beforeAll(async () => { alice = await signup({ username: 'alice' }); - aliceUploadedFile = await uploadFile(alice); + aliceUploadedFile = (await uploadFile(alice)).body; alicesPost = await post(alice, { text: 'test', }); @@ -85,7 +85,7 @@ describe('Webリソース', () => { alicePlay = await play(alice, {}); aliceClip = await clip(alice, {}); aliceGalleryPost = await galleryPost(alice, { - fileIds: [aliceUploadedFile.body.id], + fileIds: [aliceUploadedFile!.id], }); aliceChannel = await channel(alice, {}); diff --git a/packages/backend/test/e2e/fetch-validate-ap-deny.ts b/packages/backend/test/e2e/fetch-validate-ap-deny.ts new file mode 100644 index 0000000000..434a9fe209 --- /dev/null +++ b/packages/backend/test/e2e/fetch-validate-ap-deny.ts @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +process.env.NODE_ENV = 'test'; + +import { validateContentTypeSetAsActivityPub, validateContentTypeSetAsJsonLD } from '@/core/activitypub/misc/validator.js'; +import { signup, uploadFile, relativeFetch } from '../utils.js'; +import type * as misskey from 'misskey-js'; + +describe('validateContentTypeSetAsActivityPub/JsonLD (deny case)', () => { + let alice: misskey.entities.SignupResponse; + let aliceUploadedFile: any; + + beforeAll(async () => { + alice = await signup({ username: 'alice' }); + aliceUploadedFile = await uploadFile(alice); + }, 1000 * 60 * 2); + + test('ActivityStreams: ファイルはエラーになる', async () => { + const res = await relativeFetch(aliceUploadedFile.webpublicUrl); + + function doValidate() { + validateContentTypeSetAsActivityPub(res); + } + + expect(doValidate).toThrow('Content type is not'); + }); + + test('JSON-LD: ファイルはエラーになる', async () => { + const res = await relativeFetch(aliceUploadedFile.webpublicUrl); + + function doValidate() { + validateContentTypeSetAsJsonLD(res); + } + + expect(doValidate).toThrow('Content type is not'); + }); +}); diff --git a/packages/backend/test/e2e/ff-visibility.ts b/packages/backend/test/e2e/ff-visibility.ts index 1fe0478a18..5d0c70a3c2 100644 --- a/packages/backend/test/e2e/ff-visibility.ts +++ b/packages/backend/test/e2e/ff-visibility.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -19,15 +19,15 @@ describe('FF visibility', () => { }, 1000 * 60 * 2); test('followingVisibility, followersVisibility がともに public なユーザーのフォロー/フォロワーを誰でも見れる', async () => { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', followersVisibility: 'public', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); @@ -39,36 +39,36 @@ describe('FF visibility', () => { test('followingVisibility が public であれば followersVisibility の設定に関わらずユーザーのフォローを誰でも見れる', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', followersVisibility: 'public', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 200); assert.strictEqual(Array.isArray(followingRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', followersVisibility: 'followers', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 200); assert.strictEqual(Array.isArray(followingRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', followersVisibility: 'private', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 200); @@ -78,36 +78,36 @@ describe('FF visibility', () => { test('followersVisibility が public であれば followingVisibility の設定に関わらずユーザーのフォロワーを誰でも見れる', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', followersVisibility: 'public', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 200); assert.strictEqual(Array.isArray(followersRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'public', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 200); assert.strictEqual(Array.isArray(followersRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'public', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 200); @@ -116,15 +116,15 @@ describe('FF visibility', () => { }); test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを自分で見れる', async () => { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'followers', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, alice); @@ -136,36 +136,36 @@ describe('FF visibility', () => { test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'public', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, alice); assert.strictEqual(followingRes.status, 200); assert.strictEqual(Array.isArray(followingRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'followers', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, alice); assert.strictEqual(followingRes.status, 200); assert.strictEqual(Array.isArray(followingRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'private', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, alice); assert.strictEqual(followingRes.status, 200); @@ -175,36 +175,36 @@ describe('FF visibility', () => { test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', followersVisibility: 'followers', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, alice); assert.strictEqual(followersRes.status, 200); assert.strictEqual(Array.isArray(followersRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'followers', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, alice); assert.strictEqual(followersRes.status, 200); assert.strictEqual(Array.isArray(followersRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'followers', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, alice); assert.strictEqual(followersRes.status, 200); @@ -213,15 +213,15 @@ describe('FF visibility', () => { }); test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'followers', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); @@ -231,34 +231,34 @@ describe('FF visibility', () => { test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず非フォロワーが見れない', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'public', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 400); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'followers', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 400); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'private', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 400); @@ -267,34 +267,34 @@ describe('FF visibility', () => { test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず非フォロワーが見れない', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', followersVisibility: 'followers', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 400); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'followers', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 400); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'followers', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 400); @@ -302,19 +302,19 @@ describe('FF visibility', () => { }); test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'followers', }, alice); - await api('/following/create', { + await api('following/create', { userId: alice.id, }, bob); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); @@ -326,45 +326,45 @@ describe('FF visibility', () => { test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらずフォロワーが見れる', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'public', }, alice); - await api('/following/create', { + await api('following/create', { userId: alice.id, }, bob); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 200); assert.strictEqual(Array.isArray(followingRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'followers', }, alice); - await api('/following/create', { + await api('following/create', { userId: alice.id, }, bob); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 200); assert.strictEqual(Array.isArray(followingRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'private', }, alice); - await api('/following/create', { + await api('following/create', { userId: alice.id, }, bob); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 200); @@ -374,45 +374,45 @@ describe('FF visibility', () => { test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらずフォロワーが見れる', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', followersVisibility: 'followers', }, alice); - await api('/following/create', { + await api('following/create', { userId: alice.id, }, bob); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 200); assert.strictEqual(Array.isArray(followersRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'followers', }, alice); - await api('/following/create', { + await api('following/create', { userId: alice.id, }, bob); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 200); assert.strictEqual(Array.isArray(followersRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'followers', }, alice); - await api('/following/create', { + await api('following/create', { userId: alice.id, }, bob); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 200); @@ -421,15 +421,15 @@ describe('FF visibility', () => { }); test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを自分で見れる', async () => { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'private', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, alice); @@ -441,36 +441,36 @@ describe('FF visibility', () => { test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'public', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, alice); assert.strictEqual(followingRes.status, 200); assert.strictEqual(Array.isArray(followingRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'followers', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, alice); assert.strictEqual(followingRes.status, 200); assert.strictEqual(Array.isArray(followingRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'private', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, alice); assert.strictEqual(followingRes.status, 200); @@ -480,36 +480,36 @@ describe('FF visibility', () => { test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', followersVisibility: 'private', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, alice); assert.strictEqual(followersRes.status, 200); assert.strictEqual(Array.isArray(followersRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'private', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, alice); assert.strictEqual(followersRes.status, 200); assert.strictEqual(Array.isArray(followersRes.body), true); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'private', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, alice); assert.strictEqual(followersRes.status, 200); @@ -518,15 +518,15 @@ describe('FF visibility', () => { }); test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを他人が見れない', async () => { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'private', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); @@ -536,34 +536,34 @@ describe('FF visibility', () => { test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず他人が見れない', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'public', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 400); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'followers', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 400); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'private', }, alice); - const followingRes = await api('/users/following', { + const followingRes = await api('users/following', { userId: alice.id, }, bob); assert.strictEqual(followingRes.status, 400); @@ -572,34 +572,34 @@ describe('FF visibility', () => { test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず他人が見れない', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', followersVisibility: 'private', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 400); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', followersVisibility: 'private', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 400); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', followersVisibility: 'private', }, alice); - const followersRes = await api('/users/followers', { + const followersRes = await api('users/followers', { userId: alice.id, }, bob); assert.strictEqual(followersRes.status, 400); @@ -609,7 +609,7 @@ describe('FF visibility', () => { describe('AP', () => { test('followingVisibility が public 以外ならばAPからはフォローを取得できない', async () => { { - await api('/i/update', { + await api('i/update', { followingVisibility: 'public', }, alice); @@ -617,7 +617,7 @@ describe('FF visibility', () => { assert.strictEqual(followingRes.status, 200); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'followers', }, alice); @@ -625,7 +625,7 @@ describe('FF visibility', () => { assert.strictEqual(followingRes.status, 403); } { - await api('/i/update', { + await api('i/update', { followingVisibility: 'private', }, alice); @@ -636,7 +636,7 @@ describe('FF visibility', () => { test('followersVisibility が public 以外ならばAPからはフォロワーを取得できない', async () => { { - await api('/i/update', { + await api('i/update', { followersVisibility: 'public', }, alice); @@ -644,7 +644,7 @@ describe('FF visibility', () => { assert.strictEqual(followersRes.status, 200); } { - await api('/i/update', { + await api('i/update', { followersVisibility: 'followers', }, alice); @@ -652,7 +652,7 @@ describe('FF visibility', () => { assert.strictEqual(followersRes.status, 403); } { - await api('/i/update', { + await api('i/update', { followersVisibility: 'private', }, alice); diff --git a/packages/backend/test/e2e/move.ts b/packages/backend/test/e2e/move.ts index 3937203569..4e5306da97 100644 --- a/packages/backend/test/e2e/move.ts +++ b/packages/backend/test/e2e/move.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -55,7 +55,7 @@ describe('Account Move', () => { }, 1000 * 10); test('Able to create an alias', async () => { - const res = await api('/i/update', { + const res = await api('i/update', { alsoKnownAs: [`@alice@${url.hostname}`], }, bob); @@ -67,7 +67,7 @@ describe('Account Move', () => { }); test('Able to create a local alias without hostname', async () => { - await api('/i/update', { + await api('i/update', { alsoKnownAs: ['@alice'], }, bob); @@ -77,7 +77,7 @@ describe('Account Move', () => { }); test('Able to create a local alias without @', async () => { - await api('/i/update', { + await api('i/update', { alsoKnownAs: ['alice'], }, bob); @@ -87,7 +87,7 @@ describe('Account Move', () => { }); test('Able to set remote user (but may fail)', async () => { - const res = await api('/i/update', { + const res = await api('i/update', { alsoKnownAs: ['@syuilo@example.com'], }, bob); @@ -97,7 +97,7 @@ describe('Account Move', () => { }); test('Unable to add duplicated aliases to alsoKnownAs', async () => { - const res = await api('/i/update', { + const res = await api('i/update', { alsoKnownAs: [`@alice@${url.hostname}`, `@alice@${url.hostname}`], }, bob); @@ -107,7 +107,7 @@ describe('Account Move', () => { }); test('Unable to add itself', async () => { - const res = await api('/i/update', { + const res = await api('i/update', { alsoKnownAs: [`@bob@${url.hostname}`], }, bob); @@ -117,7 +117,7 @@ describe('Account Move', () => { }); test('Unable to add a nonexisting local account to alsoKnownAs', async () => { - const res1 = await api('/i/update', { + const res1 = await api('i/update', { alsoKnownAs: [`@nonexist@${url.hostname}`], }, bob); @@ -125,7 +125,7 @@ describe('Account Move', () => { assert.strictEqual(res1.body.error.code, 'NO_SUCH_USER'); assert.strictEqual(res1.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5'); - const res2 = await api('/i/update', { + const res2 = await api('i/update', { alsoKnownAs: ['@alice', 'nonexist'], }, bob); @@ -135,7 +135,7 @@ describe('Account Move', () => { }); test('Able to add two existing local account to alsoKnownAs', async () => { - await api('/i/update', { + await api('i/update', { alsoKnownAs: [`@alice@${url.hostname}`, `@carol@${url.hostname}`], }, bob); @@ -146,10 +146,10 @@ describe('Account Move', () => { }); test('Able to properly overwrite alsoKnownAs', async () => { - await api('/i/update', { + await api('i/update', { alsoKnownAs: [`@alice@${url.hostname}`], }, bob); - await api('/i/update', { + await api('i/update', { alsoKnownAs: [`@carol@${url.hostname}`, `@dave@${url.hostname}`], }, bob); @@ -164,27 +164,27 @@ describe('Account Move', () => { let antennaId = ''; beforeAll(async () => { - await api('/i/update', { + await api('i/update', { alsoKnownAs: [`@alice@${url.hostname}`], }, root); - const listRoot = await api('/users/lists/create', { + const listRoot = await api('users/lists/create', { name: secureRndstr(8), }, root); - await api('/users/lists/push', { + await api('users/lists/push', { listId: listRoot.body.id, userId: alice.id, }, root); - await api('/following/create', { + await api('following/create', { userId: root.id, }, alice); - await api('/following/create', { + await api('following/create', { userId: eve.id, }, alice); - const antenna = await api('/antennas/create', { + const antenna = await api('antennas/create', { name: secureRndstr(8), src: 'home', - keywords: [secureRndstr(8)], + keywords: [[secureRndstr(8)]], excludeKeywords: [], users: [], caseSensitive: false, @@ -195,48 +195,48 @@ describe('Account Move', () => { }, alice); antennaId = antenna.body.id; - await api('/i/update', { + await api('i/update', { alsoKnownAs: [`@alice@${url.hostname}`], }, bob); - await api('/following/create', { + await api('following/create', { userId: alice.id, }, carol); - await api('/mute/create', { + await api('mute/create', { userId: alice.id, }, dave); - await api('/blocking/create', { + await api('blocking/create', { userId: alice.id, }, dave); - await api('/following/create', { + await api('following/create', { userId: eve.id, }, dave); - await api('/following/create', { + await api('following/create', { userId: dave.id, }, eve); - const listEve = await api('/users/lists/create', { + const listEve = await api('users/lists/create', { name: secureRndstr(8), }, eve); - await api('/users/lists/push', { + await api('users/lists/push', { listId: listEve.body.id, userId: bob.id, }, eve); - await api('/i/update', { + await api('i/update', { isLocked: true, }, frank); - await api('/following/create', { + await api('following/create', { userId: frank.id, }, alice); - await api('/following/requests/accept', { + await api('following/requests/accept', { userId: alice.id, }, frank); }, 1000 * 10); test('Prohibit the root account from moving', async () => { - const res = await api('/i/move', { + const res = await api('i/move', { moveToAccount: `@bob@${url.hostname}`, }, root); @@ -246,7 +246,7 @@ describe('Account Move', () => { }); test('Unable to move to a nonexisting local account', async () => { - const res = await api('/i/move', { + const res = await api('i/move', { moveToAccount: `@nonexist@${url.hostname}`, }, alice); @@ -256,7 +256,7 @@ describe('Account Move', () => { }); test('Unable to move if alsoKnownAs is invalid', async () => { - const res = await api('/i/move', { + const res = await api('i/move', { moveToAccount: `@carol@${url.hostname}`, }, alice); @@ -266,7 +266,7 @@ describe('Account Move', () => { }); test('Relationships have been properly migrated', async () => { - const move = await api('/i/move', { + const move = await api('i/move', { moveToAccount: `@bob@${url.hostname}`, }, alice); @@ -275,13 +275,13 @@ describe('Account Move', () => { await sleep(1000 * 3); // wait for jobs to finish // Unfollow delayed? - const aliceFollowings = await api('/users/following', { + const aliceFollowings = await api('users/following', { userId: alice.id, }, alice); assert.strictEqual(aliceFollowings.status, 200); assert.strictEqual(aliceFollowings.body.length, 3); - const carolFollowings = await api('/users/following', { + const carolFollowings = await api('users/following', { userId: carol.id, }, carol); assert.strictEqual(carolFollowings.status, 200); @@ -289,25 +289,25 @@ describe('Account Move', () => { assert.strictEqual(carolFollowings.body[0].followeeId, bob.id); assert.strictEqual(carolFollowings.body[1].followeeId, alice.id); - const blockings = await api('/blocking/list', {}, dave); + const blockings = await api('blocking/list', {}, dave); assert.strictEqual(blockings.status, 200); assert.strictEqual(blockings.body.length, 2); assert.strictEqual(blockings.body[0].blockeeId, bob.id); assert.strictEqual(blockings.body[1].blockeeId, alice.id); - const mutings = await api('/mute/list', {}, dave); + const mutings = await api('mute/list', {}, dave); assert.strictEqual(mutings.status, 200); assert.strictEqual(mutings.body.length, 2); assert.strictEqual(mutings.body[0].muteeId, bob.id); assert.strictEqual(mutings.body[1].muteeId, alice.id); - const rootLists = await api('/users/lists/list', {}, root); + const rootLists = await api('users/lists/list', {}, root); assert.strictEqual(rootLists.status, 200); assert.strictEqual(rootLists.body[0].userIds.length, 2); assert.ok(rootLists.body[0].userIds.find((id: string) => id === bob.id)); assert.ok(rootLists.body[0].userIds.find((id: string) => id === alice.id)); - const eveLists = await api('/users/lists/list', {}, eve); + const eveLists = await api('users/lists/list', {}, eve); assert.strictEqual(eveLists.status, 200); assert.strictEqual(eveLists.body[0].userIds.length, 1); assert.ok(eveLists.body[0].userIds.find((id: string) => id === bob.id)); @@ -315,13 +315,13 @@ describe('Account Move', () => { test('A locked account automatically accept the follow request if it had already accepted the old account.', async () => { await successfulApiCall({ - endpoint: '/following/create', + endpoint: 'following/create', parameters: { userId: frank.id, }, user: bob, }); - const followers = await api('/users/followers', { + const followers = await api('users/followers', { userId: frank.id, }, frank); @@ -333,7 +333,7 @@ describe('Account Move', () => { test('Unfollowed after 10 sec (24 hours in production).', async () => { await sleep(1000 * 8); - const following = await api('/users/following', { + const following = await api('users/following', { userId: alice.id, }, alice); @@ -342,7 +342,7 @@ describe('Account Move', () => { }); test('Unable to move if the destination account has already moved.', async () => { - const res = await api('/i/move', { + const res = await api('i/move', { moveToAccount: `@alice@${url.hostname}`, }, bob); @@ -352,7 +352,7 @@ describe('Account Move', () => { }); test('Follow and follower counts are properly adjusted', async () => { - await api('/following/create', { + await api('following/create', { userId: alice.id, }, eve); const newAlice = await Users.findOneByOrFail({ id: alice.id }); @@ -365,7 +365,7 @@ describe('Account Move', () => { assert.strictEqual(newEve.followingCount, 1); assert.strictEqual(newEve.followersCount, 1); - await api('/following/delete', { + await api('following/delete', { userId: alice.id, }, eve); newEve = await Users.findOneByOrFail({ id: eve.id }); @@ -374,49 +374,49 @@ describe('Account Move', () => { }); test.each([ - '/antennas/create', - '/channels/create', - '/channels/favorite', - '/channels/follow', - '/channels/unfavorite', - '/channels/unfollow', - '/clips/add-note', - '/clips/create', - '/clips/favorite', - '/clips/remove-note', - '/clips/unfavorite', - '/clips/update', - '/drive/files/upload-from-url', - '/flash/create', - '/flash/like', - '/flash/unlike', - '/flash/update', - '/following/create', - '/gallery/posts/create', - '/gallery/posts/like', - '/gallery/posts/unlike', - '/gallery/posts/update', - '/i/claim-achievement', - '/i/move', - '/i/import-blocking', - '/i/import-following', - '/i/import-muting', - '/i/import-user-lists', - '/i/pin', - '/mute/create', - '/notes/create', - '/notes/favorites/create', - '/notes/polls/vote', - '/notes/reactions/create', - '/pages/create', - '/pages/like', - '/pages/unlike', - '/pages/update', - '/renote-mute/create', - '/users/lists/create', - '/users/lists/pull', - '/users/lists/push', - ])('Prohibit access after moving: %s', async (endpoint) => { + 'antennas/create', + 'channels/create', + 'channels/favorite', + 'channels/follow', + 'channels/unfavorite', + 'channels/unfollow', + 'clips/add-note', + 'clips/create', + 'clips/favorite', + 'clips/remove-note', + 'clips/unfavorite', + 'clips/update', + 'drive/files/upload-from-url', + 'flash/create', + 'flash/like', + 'flash/unlike', + 'flash/update', + 'following/create', + 'gallery/posts/create', + 'gallery/posts/like', + 'gallery/posts/unlike', + 'gallery/posts/update', + 'i/claim-achievement', + 'i/move', + 'i/import-blocking', + 'i/import-following', + 'i/import-muting', + 'i/import-user-lists', + 'i/pin', + 'mute/create', + 'notes/create', + 'notes/favorites/create', + 'notes/polls/vote', + 'notes/reactions/create', + 'pages/create', + 'pages/like', + 'pages/unlike', + 'pages/update', + 'renote-mute/create', + 'users/lists/create', + 'users/lists/pull', + 'users/lists/push', + ] as const)('Prohibit access after moving: %s', async (endpoint) => { const res = await api(endpoint, {}, alice); assert.strictEqual(res.status, 403); assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED'); @@ -424,11 +424,11 @@ describe('Account Move', () => { }); test('Prohibit access after moving: /antennas/update', async () => { - const res = await api('/antennas/update', { + const res = await api('antennas/update', { antennaId, name: secureRndstr(8), src: 'users', - keywords: [secureRndstr(8)], + keywords: [[secureRndstr(8)]], excludeKeywords: [], users: [eve.id], caseSensitive: false, @@ -447,12 +447,12 @@ describe('Account Move', () => { const res = await uploadFile(alice); assert.strictEqual(res.status, 403); - assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED'); - assert.strictEqual(res.body.error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31'); + assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.code, 'YOUR_ACCOUNT_MOVED'); + assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31'); }); test('Prohibit updating alsoKnownAs after moving', async () => { - const res = await api('/i/update', { + const res = await api('i/update', { alsoKnownAs: [`@eve@${url.hostname}`], }, alice); diff --git a/packages/backend/test/e2e/mute.ts b/packages/backend/test/e2e/mute.ts index 5144df5ebe..0e52c5decc 100644 --- a/packages/backend/test/e2e/mute.ts +++ b/packages/backend/test/e2e/mute.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -19,21 +19,31 @@ describe('Mute', () => { alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); + + // Mute: alice ==> carol + await api('mute/create', { + userId: carol.id, + }, alice); }, 1000 * 60 * 2); test('ミュート作成', async () => { - const res = await api('/mute/create', { - userId: carol.id, + const res = await api('mute/create', { + userId: bob.id, }, alice); assert.strictEqual(res.status, 204); + + // 単体でも走らせられるように副作用消す + await api('mute/delete', { + userId: bob.id, + }, alice); }); test('「自分宛ての投稿」にミュートしているユーザーの投稿が含まれない', async () => { const bobNote = await post(bob, { text: '@alice hi' }); const carolNote = await post(carol, { text: '@alice hi' }); - const res = await api('/notes/mentions', {}, alice); + const res = await api('notes/mentions', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); @@ -43,11 +53,11 @@ describe('Mute', () => { test('ミュートしているユーザーからメンションされても、hasUnreadMentions が true にならない', async () => { // 状態リセット - await api('/i/read-all-unread-notes', {}, alice); + await api('i/read-all-unread-notes', {}, alice); await post(carol, { text: '@alice hi' }); - const res = await api('/i', {}, alice); + const res = await api('i', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(res.body.hasUnreadMentions, false); @@ -55,7 +65,7 @@ describe('Mute', () => { test('ミュートしているユーザーからメンションされても、ストリームに unreadMention イベントが流れてこない', async () => { // 状態リセット - await api('/i/read-all-unread-notes', {}, alice); + await api('i/read-all-unread-notes', {}, alice); const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadMention'); @@ -64,8 +74,8 @@ describe('Mute', () => { test('ミュートしているユーザーからメンションされても、ストリームに unreadNotification イベントが流れてこない', async () => { // 状態リセット - await api('/i/read-all-unread-notes', {}, alice); - await api('/notifications/mark-all-as-read', {}, alice); + await api('i/read-all-unread-notes', {}, alice); + await api('notifications/mark-all-as-read', {}, alice); const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadNotification'); @@ -78,7 +88,7 @@ describe('Mute', () => { const bobNote = await post(bob, { text: 'hi' }); const carolNote = await post(carol, { text: 'hi' }); - const res = await api('/notes/local-timeline', {}, alice); + const res = await api('notes/local-timeline', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); @@ -94,7 +104,7 @@ describe('Mute', () => { renoteId: carolNote.id, }); - const res = await api('/notes/local-timeline', {}, alice); + const res = await api('notes/local-timeline', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); @@ -110,12 +120,201 @@ describe('Mute', () => { await react(bob, aliceNote, 'like'); await react(carol, aliceNote, 'like'); - const res = await api('/i/notifications', {}, alice); + const res = await api('i/notifications', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); }); + + test('通知にミュートしているユーザーからのリプライが含まれない', async () => { + const aliceNote = await post(alice, { text: 'hi' }); + await post(bob, { text: '@alice hi', replyId: aliceNote.id }); + await post(carol, { text: '@alice hi', replyId: aliceNote.id }); + + const res = await api('i/notifications', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + }); + + test('通知にミュートしているユーザーからのリプライが含まれない', async () => { + await post(alice, { text: 'hi' }); + await post(bob, { text: '@alice hi' }); + await post(carol, { text: '@alice hi' }); + + const res = await api('i/notifications', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + }); + + test('通知にミュートしているユーザーからの引用リノートが含まれない', async () => { + const aliceNote = await post(alice, { text: 'hi' }); + await post(bob, { text: 'hi', renoteId: aliceNote.id }); + await post(carol, { text: 'hi', renoteId: aliceNote.id }); + + const res = await api('i/notifications', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + }); + + test('通知にミュートしているユーザーからのリノートが含まれない', async () => { + const aliceNote = await post(alice, { text: 'hi' }); + await post(bob, { renoteId: aliceNote.id }); + await post(carol, { renoteId: aliceNote.id }); + + const res = await api('i/notifications', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + }); + + test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => { + await api('following/create', { userId: alice.id }, bob); + await api('following/create', { userId: alice.id }, carol); + + const res = await api('i/notifications', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + + await api('following/delete', { userId: alice.id }, bob); + await api('following/delete', { userId: alice.id }, carol); + }); + + test('通知にミュートしているユーザーからのフォローリクエストが含まれない', async () => { + await api('i/update', { isLocked: true }, alice); + await api('following/create', { userId: alice.id }, bob); + await api('following/create', { userId: alice.id }, carol); + + const res = await api('i/notifications', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + + await api('following/delete', { userId: alice.id }, bob); + await api('following/delete', { userId: alice.id }, carol); + }); + }); + + describe('Notification (Grouped)', () => { + test('通知にミュートしているユーザーの通知が含まれない(リアクション)', async () => { + const aliceNote = await post(alice, { text: 'hi' }); + await react(bob, aliceNote, 'like'); + await react(carol, aliceNote, 'like'); + + const res = await api('i/notifications-grouped', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + }); + test('通知にミュートしているユーザーからのリプライが含まれない', async () => { + const aliceNote = await post(alice, { text: 'hi' }); + await post(bob, { text: '@alice hi', replyId: aliceNote.id }); + await post(carol, { text: '@alice hi', replyId: aliceNote.id }); + + const res = await api('i/notifications-grouped', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + }); + + test('通知にミュートしているユーザーからのリプライが含まれない', async () => { + await post(alice, { text: 'hi' }); + await post(bob, { text: '@alice hi' }); + await post(carol, { text: '@alice hi' }); + + const res = await api('i/notifications-grouped', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + }); + + test('通知にミュートしているユーザーからの引用リノートが含まれない', async () => { + const aliceNote = await post(alice, { text: 'hi' }); + await post(bob, { text: 'hi', renoteId: aliceNote.id }); + await post(carol, { text: 'hi', renoteId: aliceNote.id }); + + const res = await api('i/notifications-grouped', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + }); + + test('通知にミュートしているユーザーからのリノートが含まれない', async () => { + const aliceNote = await post(alice, { text: 'hi' }); + await post(bob, { renoteId: aliceNote.id }); + await post(carol, { renoteId: aliceNote.id }); + + const res = await api('i/notifications-grouped', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + }); + + test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => { + await api('following/create', { userId: alice.id }, bob); + await api('following/create', { userId: alice.id }, carol); + + const res = await api('i/notifications-grouped', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + + await api('following/delete', { userId: alice.id }, bob); + await api('following/delete', { userId: alice.id }, carol); + }); + + test('通知にミュートしているユーザーからのフォローリクエストが含まれない', async () => { + await api('i/update', { isLocked: true }, alice); + await api('following/create', { userId: alice.id }, bob); + await api('following/create', { userId: alice.id }, carol); + + const res = await api('i/notifications-grouped', {}, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(Array.isArray(res.body), true); + + assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); + assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + }); }); }); diff --git a/packages/backend/test/e2e/nodeinfo.ts b/packages/backend/test/e2e/nodeinfo.ts index 934ef08507..28b96fe8c8 100644 --- a/packages/backend/test/e2e/nodeinfo.ts +++ b/packages/backend/test/e2e/nodeinfo.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts index 0280b051f5..973bcbd750 100644 --- a/packages/backend/test/e2e/note.ts +++ b/packages/backend/test/e2e/note.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -16,12 +16,14 @@ describe('Note', () => { let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; + let tom: misskey.entities.SignupResponse; beforeAll(async () => { const connection = await initTestDb(true); Notes = connection.getRepository(MiNote); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); + tom = await signup({ username: 'tom', host: 'example.com' }); }, 1000 * 60 * 2); test('投稿できる', async () => { @@ -29,7 +31,7 @@ describe('Note', () => { text: 'test', }; - const res = await api('/notes/create', post, alice); + const res = await api('notes/create', post, alice); assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); @@ -39,7 +41,7 @@ describe('Note', () => { test('ファイルを添付できる', async () => { const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'); - const res = await api('/notes/create', { + const res = await api('notes/create', { fileIds: [file.id], }, alice); @@ -51,7 +53,7 @@ describe('Note', () => { test('他人のファイルで怒られる', async () => { const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'); - const res = await api('/notes/create', { + const res = await api('notes/create', { text: 'test', fileIds: [file.id], }, alice); @@ -62,7 +64,7 @@ describe('Note', () => { }, 1000 * 10); test('存在しないファイルで怒られる', async () => { - const res = await api('/notes/create', { + const res = await api('notes/create', { text: 'test', fileIds: ['000000000000000000000000'], }, alice); @@ -73,7 +75,7 @@ describe('Note', () => { }); test('不正なファイルIDで怒られる', async () => { - const res = await api('/notes/create', { + const res = await api('notes/create', { fileIds: ['kyoppie'], }, alice); assert.strictEqual(res.status, 400); @@ -91,7 +93,7 @@ describe('Note', () => { replyId: bobPost.id, }; - const res = await api('/notes/create', alicePost, alice); + const res = await api('notes/create', alicePost, alice); assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); @@ -109,7 +111,7 @@ describe('Note', () => { renoteId: bobPost.id, }; - const res = await api('/notes/create', alicePost, alice); + const res = await api('notes/create', alicePost, alice); assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); @@ -127,7 +129,7 @@ describe('Note', () => { renoteId: bobPost.id, }; - const res = await api('/notes/create', alicePost, alice); + const res = await api('notes/create', alicePost, alice); assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); @@ -140,7 +142,7 @@ describe('Note', () => { const bobPost = await post(bob, { text: 'test', }); - const res = await api('/notes/create', { + const res = await api('notes/create', { text: ' ', renoteId: bobPost.id, }, alice); @@ -150,7 +152,7 @@ describe('Note', () => { }); test('visibility: followersでrenoteできる', async () => { - const createRes = await api('/notes/create', { + const createRes = await api('notes/create', { text: 'test', visibility: 'followers', }, alice); @@ -158,7 +160,7 @@ describe('Note', () => { assert.strictEqual(createRes.status, 200); const renoteId = createRes.body.createdNote.id; - const renoteRes = await api('/notes/create', { + const renoteRes = await api('notes/create', { visibility: 'followers', renoteId, }, alice); @@ -167,18 +169,99 @@ describe('Note', () => { assert.strictEqual(renoteRes.body.createdNote.renoteId, renoteId); assert.strictEqual(renoteRes.body.createdNote.visibility, 'followers'); - const deleteRes = await api('/notes/delete', { + const deleteRes = await api('notes/delete', { noteId: renoteRes.body.createdNote.id, }, alice); assert.strictEqual(deleteRes.status, 204); }); + test('visibility: followersなノートに対してフォロワーはリプライできる', async () => { + await api('following/create', { + userId: alice.id, + }, bob); + + const aliceNote = await api('notes/create', { + text: 'direct note to bob', + visibility: 'followers', + }, alice); + + assert.strictEqual(aliceNote.status, 200); + + const replyId = aliceNote.body.createdNote.id; + const bobReply = await api('notes/create', { + text: 'reply to alice note', + replyId, + }, bob); + + assert.strictEqual(bobReply.status, 200); + assert.strictEqual(bobReply.body.createdNote.replyId, replyId); + + await api('following/delete', { + userId: alice.id, + }, bob); + }); + + test('visibility: followersなノートに対してフォロワーでないユーザーがリプライしようとすると怒られる', async () => { + const aliceNote = await api('notes/create', { + text: 'direct note to bob', + visibility: 'followers', + }, alice); + + assert.strictEqual(aliceNote.status, 200); + + const bobReply = await api('notes/create', { + text: 'reply to alice note', + replyId: aliceNote.body.createdNote.id, + }, bob); + + assert.strictEqual(bobReply.status, 400); + assert.strictEqual(bobReply.body.error.code, 'CANNOT_REPLY_TO_AN_INVISIBLE_NOTE'); + }); + + test('visibility: specifiedなノートに対してvisibility: specifiedで返信できる', async () => { + const aliceNote = await api('notes/create', { + text: 'direct note to bob', + visibility: 'specified', + visibleUserIds: [bob.id], + }, alice); + + assert.strictEqual(aliceNote.status, 200); + + const bobReply = await api('notes/create', { + text: 'reply to alice note', + replyId: aliceNote.body.createdNote.id, + visibility: 'specified', + visibleUserIds: [alice.id], + }, bob); + + assert.strictEqual(bobReply.status, 200); + }); + + test('visibility: specifiedなノートに対してvisibility: follwersで返信しようとすると怒られる', async () => { + const aliceNote = await api('notes/create', { + text: 'direct note to bob', + visibility: 'specified', + visibleUserIds: [bob.id], + }, alice); + + assert.strictEqual(aliceNote.status, 200); + + const bobReply = await api('notes/create', { + text: 'reply to alice note with visibility: followers', + replyId: aliceNote.body.createdNote.id, + visibility: 'followers', + }, bob); + + assert.strictEqual(bobReply.status, 400); + assert.strictEqual(bobReply.body.error.code, 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY'); + }); + test('文字数ぎりぎりで怒られない', async () => { const post = { text: '!'.repeat(MAX_NOTE_TEXT_LENGTH), // 3000文字 }; - const res = await api('/notes/create', post, alice); + const res = await api('notes/create', post, alice); assert.strictEqual(res.status, 200); }); @@ -186,7 +269,7 @@ describe('Note', () => { const post = { text: '!'.repeat(MAX_NOTE_TEXT_LENGTH + 1), // 3001文字 }; - const res = await api('/notes/create', post, alice); + const res = await api('notes/create', post, alice); assert.strictEqual(res.status, 400); }); @@ -195,7 +278,7 @@ describe('Note', () => { text: 'test', replyId: '000000000000000000000000', }; - const res = await api('/notes/create', post, alice); + const res = await api('notes/create', post, alice); assert.strictEqual(res.status, 400); }); @@ -203,7 +286,7 @@ describe('Note', () => { const post = { renoteId: '000000000000000000000000', }; - const res = await api('/notes/create', post, alice); + const res = await api('notes/create', post, alice); assert.strictEqual(res.status, 400); }); @@ -212,7 +295,7 @@ describe('Note', () => { text: 'test', replyId: 'foo', }; - const res = await api('/notes/create', post, alice); + const res = await api('notes/create', post, alice); assert.strictEqual(res.status, 400); }); @@ -220,7 +303,7 @@ describe('Note', () => { const post = { renoteId: 'foo', }; - const res = await api('/notes/create', post, alice); + const res = await api('notes/create', post, alice); assert.strictEqual(res.status, 400); }); @@ -229,7 +312,7 @@ describe('Note', () => { text: '@ghost yo', }; - const res = await api('/notes/create', post, alice); + const res = await api('notes/create', post, alice); assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); @@ -241,7 +324,7 @@ describe('Note', () => { text: '@bob @bob @bob yo', }; - const res = await api('/notes/create', post, alice); + const res = await api('notes/create', post, alice); assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); @@ -254,25 +337,25 @@ describe('Note', () => { describe('添付ファイル情報', () => { test('ファイルを添付した場合、投稿成功時にファイル情報入りのレスポンスが帰ってくる', async () => { const file = await uploadFile(alice); - const res = await api('/notes/create', { - fileIds: [file.body.id], + const res = await api('notes/create', { + fileIds: [file.body!.id], }, alice); assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); assert.strictEqual(res.body.createdNote.files.length, 1); - assert.strictEqual(res.body.createdNote.files[0].id, file.body.id); + assert.strictEqual(res.body.createdNote.files[0].id, file.body!.id); }); test('ファイルを添付した場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => { const file = await uploadFile(alice); - const createdNote = await api('/notes/create', { - fileIds: [file.body.id], + const createdNote = await api('notes/create', { + fileIds: [file.body!.id], }, alice); assert.strictEqual(createdNote.status, 200); - const res = await api('/notes', { + const res = await api('notes', { withFiles: true, }, alice); @@ -281,23 +364,23 @@ describe('Note', () => { const myNote = res.body.find((note: { id: string; files: { id: string }[] }) => note.id === createdNote.body.createdNote.id); assert.notEqual(myNote, null); assert.strictEqual(myNote.files.length, 1); - assert.strictEqual(myNote.files[0].id, file.body.id); + assert.strictEqual(myNote.files[0].id, file.body!.id); }); test('ファイルが添付されたノートをリノートした場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => { const file = await uploadFile(alice); - const createdNote = await api('/notes/create', { - fileIds: [file.body.id], + const createdNote = await api('notes/create', { + fileIds: [file.body!.id], }, alice); assert.strictEqual(createdNote.status, 200); - const renoted = await api('/notes/create', { + const renoted = await api('notes/create', { renoteId: createdNote.body.createdNote.id, }, alice); assert.strictEqual(renoted.status, 200); - const res = await api('/notes', { + const res = await api('notes', { renote: true, }, alice); @@ -306,24 +389,24 @@ describe('Note', () => { const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id); assert.notEqual(myNote, null); assert.strictEqual(myNote.renote.files.length, 1); - assert.strictEqual(myNote.renote.files[0].id, file.body.id); + assert.strictEqual(myNote.renote.files[0].id, file.body!.id); }); test('ファイルが添付されたノートに返信した場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => { const file = await uploadFile(alice); - const createdNote = await api('/notes/create', { - fileIds: [file.body.id], + const createdNote = await api('notes/create', { + fileIds: [file.body!.id], }, alice); assert.strictEqual(createdNote.status, 200); - const reply = await api('/notes/create', { + const reply = await api('notes/create', { replyId: createdNote.body.createdNote.id, text: 'this is reply', }, alice); assert.strictEqual(reply.status, 200); - const res = await api('/notes', { + const res = await api('notes', { reply: true, }, alice); @@ -332,29 +415,29 @@ describe('Note', () => { const myNote = res.body.find((note: { id: string }) => note.id === reply.body.createdNote.id); assert.notEqual(myNote, null); assert.strictEqual(myNote.reply.files.length, 1); - assert.strictEqual(myNote.reply.files[0].id, file.body.id); + assert.strictEqual(myNote.reply.files[0].id, file.body!.id); }); test('ファイルが添付されたノートへの返信をリノートした場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => { const file = await uploadFile(alice); - const createdNote = await api('/notes/create', { - fileIds: [file.body.id], + const createdNote = await api('notes/create', { + fileIds: [file.body!.id], }, alice); assert.strictEqual(createdNote.status, 200); - const reply = await api('/notes/create', { + const reply = await api('notes/create', { replyId: createdNote.body.createdNote.id, text: 'this is reply', }, alice); assert.strictEqual(reply.status, 200); - const renoted = await api('/notes/create', { + const renoted = await api('notes/create', { renoteId: reply.body.createdNote.id, }, alice); assert.strictEqual(renoted.status, 200); - const res = await api('/notes', { + const res = await api('notes', { renote: true, }, alice); @@ -363,7 +446,7 @@ describe('Note', () => { const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id); assert.notEqual(myNote, null); assert.strictEqual(myNote.renote.reply.files.length, 1); - assert.strictEqual(myNote.renote.reply.files[0].id, file.body.id); + assert.strictEqual(myNote.renote.reply.files[0].id, file.body!.id); }); test('NSFWが強制されている場合変更できない', async () => { @@ -400,15 +483,15 @@ describe('Note', () => { }, alice); assert.strictEqual(assign.status, 204); - assert.strictEqual(file.body.isSensitive, false); + assert.strictEqual(file.body!.isSensitive, false); const nsfwfile = await uploadFile(alice); assert.strictEqual(nsfwfile.status, 200); - assert.strictEqual(nsfwfile.body.isSensitive, true); + assert.strictEqual(nsfwfile.body!.isSensitive, true); const liftnsfw = await api('drive/files/update', { - fileId: nsfwfile.body.id, + fileId: nsfwfile.body!.id, isSensitive: false, }, alice); @@ -416,7 +499,7 @@ describe('Note', () => { assert.strictEqual(liftnsfw.body.error.code, 'RESTRICTED_BY_ROLE'); const oldaddnsfw = await api('drive/files/update', { - fileId: file.body.id, + fileId: file.body!.id, isSensitive: true, }, alice); @@ -435,7 +518,7 @@ describe('Note', () => { describe('notes/create', () => { test('投票を添付できる', async () => { - const res = await api('/notes/create', { + const res = await api('notes/create', { text: 'test', poll: { choices: ['foo', 'bar'], @@ -448,14 +531,15 @@ describe('Note', () => { }); test('投票の選択肢が無くて怒られる', async () => { - const res = await api('/notes/create', { + const res = await api('notes/create', { + // @ts-expect-error poll must not be empty poll: {}, }, alice); assert.strictEqual(res.status, 400); }); test('投票の選択肢が無くて怒られる (空の配列)', async () => { - const res = await api('/notes/create', { + const res = await api('notes/create', { poll: { choices: [], }, @@ -464,7 +548,7 @@ describe('Note', () => { }); test('投票の選択肢が1つで怒られる', async () => { - const res = await api('/notes/create', { + const res = await api('notes/create', { poll: { choices: ['Strawberry Pasta'], }, @@ -473,14 +557,14 @@ describe('Note', () => { }); test('投票できる', async () => { - const { body } = await api('/notes/create', { + const { body } = await api('notes/create', { text: 'test', poll: { choices: ['sakura', 'izumi', 'ako'], }, }, alice); - const res = await api('/notes/polls/vote', { + const res = await api('notes/polls/vote', { noteId: body.createdNote.id, choice: 1, }, alice); @@ -489,19 +573,19 @@ describe('Note', () => { }); test('複数投票できない', async () => { - const { body } = await api('/notes/create', { + const { body } = await api('notes/create', { text: 'test', poll: { choices: ['sakura', 'izumi', 'ako'], }, }, alice); - await api('/notes/polls/vote', { + await api('notes/polls/vote', { noteId: body.createdNote.id, choice: 0, }, alice); - const res = await api('/notes/polls/vote', { + const res = await api('notes/polls/vote', { noteId: body.createdNote.id, choice: 2, }, alice); @@ -510,7 +594,7 @@ describe('Note', () => { }); test('許可されている場合は複数投票できる', async () => { - const { body } = await api('/notes/create', { + const { body } = await api('notes/create', { text: 'test', poll: { choices: ['sakura', 'izumi', 'ako'], @@ -518,17 +602,17 @@ describe('Note', () => { }, }, alice); - await api('/notes/polls/vote', { + await api('notes/polls/vote', { noteId: body.createdNote.id, choice: 0, }, alice); - await api('/notes/polls/vote', { + await api('notes/polls/vote', { noteId: body.createdNote.id, choice: 1, }, alice); - const res = await api('/notes/polls/vote', { + const res = await api('notes/polls/vote', { noteId: body.createdNote.id, choice: 2, }, alice); @@ -537,7 +621,7 @@ describe('Note', () => { }); test('締め切られている場合は投票できない', async () => { - const { body } = await api('/notes/create', { + const { body } = await api('notes/create', { text: 'test', poll: { choices: ['sakura', 'izumi', 'ako'], @@ -547,7 +631,7 @@ describe('Note', () => { await new Promise(x => setTimeout(x, 2)); - const res = await api('/notes/polls/vote', { + const res = await api('notes/polls/vote', { noteId: body.createdNote.id, choice: 1, }, alice); @@ -566,7 +650,7 @@ describe('Note', () => { await new Promise(x => setTimeout(x, 2)); - const note1 = await api('/notes/create', { + const note1 = await api('notes/create', { text: 'hogetesthuge', }, alice); @@ -583,7 +667,7 @@ describe('Note', () => { assert.strictEqual(sensitive.status, 204); - const note2 = await api('/notes/create', { + const note2 = await api('notes/create', { text: 'hogetesthuge', }, alice); @@ -600,13 +684,249 @@ describe('Note', () => { assert.strictEqual(sensitive.status, 204); - const note2 = await api('/notes/create', { + const note2 = await api('notes/create', { text: 'hogeTesthuge', }, alice); assert.strictEqual(note2.status, 200); assert.strictEqual(note2.body.createdNote.visibility, 'home'); }); + + test('禁止ワードを含む投稿はエラーになる (単語指定)', async () => { + const prohibited = await api('admin/update-meta', { + prohibitedWords: [ + 'test', + ], + }, alice); + + assert.strictEqual(prohibited.status, 204); + + await new Promise(x => setTimeout(x, 2)); + + const note1 = await api('notes/create', { + text: 'hogetesthuge', + }, alice); + + assert.strictEqual(note1.status, 400); + assert.strictEqual(note1.body.error.code, 'CONTAINS_PROHIBITED_WORDS'); + }); + + test('禁止ワードを含む投稿はエラーになる (正規表現)', async () => { + const prohibited = await api('admin/update-meta', { + prohibitedWords: [ + '/Test/i', + ], + }, alice); + + assert.strictEqual(prohibited.status, 204); + + const note2 = await api('notes/create', { + text: 'hogetesthuge', + }, alice); + + assert.strictEqual(note2.status, 400); + assert.strictEqual(note2.body.error.code, 'CONTAINS_PROHIBITED_WORDS'); + }); + + test('禁止ワードを含む投稿はエラーになる (スペースアンド)', async () => { + const prohibited = await api('admin/update-meta', { + prohibitedWords: [ + 'Test hoge', + ], + }, alice); + + assert.strictEqual(prohibited.status, 204); + + const note2 = await api('notes/create', { + text: 'hogeTesthuge', + }, alice); + + assert.strictEqual(note2.status, 400); + assert.strictEqual(note2.body.error.code, 'CONTAINS_PROHIBITED_WORDS'); + }); + + test('禁止ワードを含んでるリモートノートもエラーになる', async () => { + const prohibited = await api('admin/update-meta', { + prohibitedWords: [ + 'test', + ], + }, alice); + + assert.strictEqual(prohibited.status, 204); + + await new Promise(x => setTimeout(x, 2)); + + const note1 = await api('notes/create', { + text: 'hogetesthuge', + }, tom); + + assert.strictEqual(note1.status, 400); + }); + + test('メンションの数が上限を超えるとエラーになる', async () => { + const res = await api('admin/roles/create', { + name: 'test', + description: '', + color: null, + iconUrl: null, + displayOrder: 0, + target: 'manual', + condFormula: {}, + isAdministrator: false, + isModerator: false, + isPublic: false, + isExplorable: false, + asBadge: false, + canEditMembersByModerator: false, + policies: { + mentionLimit: { + useDefault: false, + priority: 1, + value: 0, + }, + }, + }, alice); + + assert.strictEqual(res.status, 200); + + await new Promise(x => setTimeout(x, 2)); + + const assign = await api('admin/roles/assign', { + userId: alice.id, + roleId: res.body.id, + }, alice); + + assert.strictEqual(assign.status, 204); + + await new Promise(x => setTimeout(x, 2)); + + const note = await api('notes/create', { + text: '@bob potentially annoying text', + }, alice); + + assert.strictEqual(note.status, 400); + assert.strictEqual(note.body.error.code, 'CONTAINS_TOO_MANY_MENTIONS'); + + await api('admin/roles/unassign', { + userId: alice.id, + roleId: res.body.id, + }); + + await api('admin/roles/delete', { + roleId: res.body.id, + }, alice); + }); + + test('ダイレクト投稿もエラーになる', async () => { + const res = await api('admin/roles/create', { + name: 'test', + description: '', + color: null, + iconUrl: null, + displayOrder: 0, + target: 'manual', + condFormula: {}, + isAdministrator: false, + isModerator: false, + isPublic: false, + isExplorable: false, + asBadge: false, + canEditMembersByModerator: false, + policies: { + mentionLimit: { + useDefault: false, + priority: 1, + value: 0, + }, + }, + }, alice); + + assert.strictEqual(res.status, 200); + + await new Promise(x => setTimeout(x, 2)); + + const assign = await api('admin/roles/assign', { + userId: alice.id, + roleId: res.body.id, + }, alice); + + assert.strictEqual(assign.status, 204); + + await new Promise(x => setTimeout(x, 2)); + + const note = await api('notes/create', { + text: 'potentially annoying text', + visibility: 'specified', + visibleUserIds: [bob.id], + }, alice); + + assert.strictEqual(note.status, 400); + assert.strictEqual(note.body.error.code, 'CONTAINS_TOO_MANY_MENTIONS'); + + await api('admin/roles/unassign', { + userId: alice.id, + roleId: res.body.id, + }); + + await api('admin/roles/delete', { + roleId: res.body.id, + }, alice); + }); + + test('ダイレクトの宛先とメンションが同じ場合は重複してカウントしない', async () => { + const res = await api('admin/roles/create', { + name: 'test', + description: '', + color: null, + iconUrl: null, + displayOrder: 0, + target: 'manual', + condFormula: {}, + isAdministrator: false, + isModerator: false, + isPublic: false, + isExplorable: false, + asBadge: false, + canEditMembersByModerator: false, + policies: { + mentionLimit: { + useDefault: false, + priority: 1, + value: 1, + }, + }, + }, alice); + + assert.strictEqual(res.status, 200); + + await new Promise(x => setTimeout(x, 2)); + + const assign = await api('admin/roles/assign', { + userId: alice.id, + roleId: res.body.id, + }, alice); + + assert.strictEqual(assign.status, 204); + + await new Promise(x => setTimeout(x, 2)); + + const note = await api('notes/create', { + text: '@bob potentially annoying text', + visibility: 'specified', + visibleUserIds: [bob.id], + }, alice); + + assert.strictEqual(note.status, 200); + + await api('admin/roles/unassign', { + userId: alice.id, + roleId: res.body.id, + }); + + await api('admin/roles/delete', { + roleId: res.body.id, + }, alice); + }); }); describe('notes/delete', () => { diff --git a/packages/backend/test/e2e/oauth.ts b/packages/backend/test/e2e/oauth.ts index df6ff42df9..ef7a6a579d 100644 --- a/packages/backend/test/e2e/oauth.ts +++ b/packages/backend/test/e2e/oauth.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/e2e/renote-mute.ts b/packages/backend/test/e2e/renote-mute.ts index 42cc414c3f..9826068e48 100644 --- a/packages/backend/test/e2e/renote-mute.ts +++ b/packages/backend/test/e2e/renote-mute.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -22,7 +22,7 @@ describe('Renote Mute', () => { }, 1000 * 60 * 2); test('ミュート作成', async () => { - const res = await api('/renote-mute/create', { + const res = await api('renote-mute/create', { userId: carol.id, }, alice); @@ -37,7 +37,7 @@ describe('Renote Mute', () => { // redisに追加されるのを待つ await sleep(100); - const res = await api('/notes/local-timeline', {}, alice); + const res = await api('notes/local-timeline', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); @@ -54,7 +54,7 @@ describe('Renote Mute', () => { // redisに追加されるのを待つ await sleep(100); - const res = await api('/notes/local-timeline', {}, alice); + const res = await api('notes/local-timeline', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); diff --git a/packages/backend/test/e2e/streaming.ts b/packages/backend/test/e2e/streaming.ts index b6f584fa70..edb930617f 100644 --- a/packages/backend/test/e2e/streaming.ts +++ b/packages/backend/test/e2e/streaming.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -40,9 +40,9 @@ describe('Streaming', () => { let chinatsu: misskey.entities.SignupResponse; let takumi: misskey.entities.SignupResponse; - let kyokoNote: any; - let kanakoNote: any; - let takumiNote: any; + let kyokoNote: misskey.entities.Note; + let kanakoNote: misskey.entities.Note; + let takumiNote: misskey.entities.Note; let list: any; beforeAll(async () => { @@ -68,6 +68,9 @@ describe('Streaming', () => { // Follow: ayano => akari await follow(ayano, akari); + // Follow: kyoko => chitose + await api('following/create', { userId: chitose.id }, kyoko); + // Mute: chitose => kanako await api('mute/create', { userId: kanako.id }, chitose); @@ -170,7 +173,28 @@ describe('Streaming', () => { */ test('フォローしているユーザーのフォローしていないユーザーの visibility: followers な投稿への返信が流れない', async () => { - // TODO + const chitoseNote = await post(chitose, { text: 'followers-only post', visibility: 'followers' }); + + const fired = await waitFire( + ayano, 'homeTimeline', // ayano:home + () => api('notes/create', { text: 'reply to chitose\'s followers-only post', replyId: chitoseNote.id }, kyoko), // kyoko's reply to chitose's followers-only post + msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko + ); + + assert.strictEqual(fired, false); + }); + + test('フォローしているユーザーのフォローしていないユーザーの visibility: followers な投稿への返信のリノートが流れない', async () => { + const chitoseNote = await post(chitose, { text: 'followers-only post', visibility: 'followers' }); + const kyokoReply = await post(kyoko, { text: 'reply to followers-only post', replyId: chitoseNote.id }); + + const fired = await waitFire( + ayano, 'homeTimeline', // ayano:home + () => api('notes/create', { renoteId: kyokoReply.id }, kyoko), // kyoko's renote of kyoko's reply to chitose's followers-only post + msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko + ); + + assert.strictEqual(fired, false); }); test('フォローしていないユーザーの投稿は流れない', async () => { @@ -202,6 +226,79 @@ describe('Streaming', () => { assert.strictEqual(fired, false); }); + + /** + * TODO: 落ちる + * @see https://github.com/misskey-dev/misskey/issues/13474 + test('visibility: specified なノートで visibleUserIds に自分が含まれているときそのノートへのリプライが流れてくる', async () => { + const chitoseToKyokoAndAyano = await post(chitose, { text: 'direct note from chitose to kyoko and ayano', visibility: 'specified', visibleUserIds: [kyoko.id, ayano.id] }); + + const fired = await waitFire( + ayano, 'homeTimeline', // ayano:home + () => api('notes/create', { text: 'direct reply from kyoko to chitose and ayano', replyId: chitoseToKyokoAndAyano.id, visibility: 'specified', visibleUserIds: [chitose.id, ayano.id] }, kyoko), + msg => msg.type === 'note' && msg.body.userId === kyoko.id, + ); + + assert.strictEqual(fired, true); + }); + */ + + test('visibility: specified な投稿に対するリプライで visibleUserIds が拡張されたとき、その拡張されたユーザーの HTL にはそのリプライが流れない', async () => { + const chitoseToKyoko = await post(chitose, { text: 'direct note from chitose to kyoko', visibility: 'specified', visibleUserIds: [kyoko.id] }); + + const fired = await waitFire( + ayano, 'homeTimeline', // ayano:home + () => api('notes/create', { text: 'direct reply from kyoko to chitose and ayano', replyId: chitoseToKyoko.id, visibility: 'specified', visibleUserIds: [chitose.id, ayano.id] }, kyoko), + msg => msg.type === 'note' && msg.body.userId === kyoko.id, + ); + + assert.strictEqual(fired, false); + }); + + test('visibility: specified な投稿に対するリプライで visibleUserIds が収縮されたとき、その収縮されたユーザーの HTL にはそのリプライが流れない', async () => { + const chitoseToKyokoAndAyano = await post(chitose, { text: 'direct note from chitose to kyoko and ayano', visibility: 'specified', visibleUserIds: [kyoko.id, ayano.id] }); + + const fired = await waitFire( + ayano, 'homeTimeline', // ayano:home + () => api('notes/create', { text: 'direct reply from kyoko to chitose', replyId: chitoseToKyokoAndAyano.id, visibility: 'specified', visibleUserIds: [chitose.id] }, kyoko), + msg => msg.type === 'note' && msg.body.userId === kyoko.id, + ); + + assert.strictEqual(fired, false); + }); + + test('withRenotes: false のときリノートが流れない', async () => { + const fired = await waitFire( + ayano, 'homeTimeline', // ayano:home + () => api('notes/create', { renoteId: kyokoNote.id }, kyoko), // kyoko renote + msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko + { withRenotes: false }, + ); + + assert.strictEqual(fired, false); + }); + + test('withRenotes: false のとき引用リノートが流れる', async () => { + const fired = await waitFire( + ayano, 'homeTimeline', // ayano:home + () => api('notes/create', { text: 'quote', renoteId: kyokoNote.id }, kyoko), // kyoko quote + msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko + { withRenotes: false }, + ); + + assert.strictEqual(fired, true); + }); + + test('withRenotes: false のとき投票のみのリノートが流れる', async () => { + const fired = await waitFire( + ayano, 'homeTimeline', // ayano:home + () => api('notes/create', { poll: { choices: ['kinoko', 'takenoko'] }, renoteId: kyokoNote.id }, kyoko), // kyoko renote with poll + msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko + { withRenotes: false }, + ); + + assert.strictEqual(fired, true); + }); }); // Home describe('Local Timeline', () => { @@ -504,7 +601,7 @@ describe('Streaming', () => { // #10443 test('ミュートしているサーバのノートがリストTLに流れない', async () => { - await api('/i/update', { + await api('i/update', { mutedInstances: ['example.com'], }, chitose); @@ -521,7 +618,7 @@ describe('Streaming', () => { // #10443 test('ミュートしているサーバのノートに対するリプライがリストTLに流れない', async () => { - await api('/i/update', { + await api('i/update', { mutedInstances: ['example.com'], }, chitose); @@ -538,7 +635,7 @@ describe('Streaming', () => { // #10443 test('ミュートしているサーバのノートに対するリノートがリストTLに流れない', async () => { - await api('/i/update', { + await api('i/update', { mutedInstances: ['example.com'], }, chitose); diff --git a/packages/backend/test/e2e/thread-mute.ts b/packages/backend/test/e2e/thread-mute.ts index 26c30d6c4c..53bb6eb765 100644 --- a/packages/backend/test/e2e/thread-mute.ts +++ b/packages/backend/test/e2e/thread-mute.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -24,12 +24,12 @@ describe('Note thread mute', () => { const bobNote = await post(bob, { text: '@alice @carol root note' }); const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' }); - await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice); + await api('notes/thread-muting/create', { noteId: bobNote.id }, alice); const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' }); const carolReplyWithoutMention = await post(carol, { replyId: aliceReply.id, text: 'child note' }); - const res = await api('/notes/mentions', {}, alice); + const res = await api('notes/mentions', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); @@ -40,15 +40,15 @@ describe('Note thread mute', () => { test('ミュートしているスレッドからメンションされても、hasUnreadMentions が true にならない', async () => { // 状態リセット - await api('/i/read-all-unread-notes', {}, alice); + await api('i/read-all-unread-notes', {}, alice); const bobNote = await post(bob, { text: '@alice @carol root note' }); - await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice); + await api('notes/thread-muting/create', { noteId: bobNote.id }, alice); const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' }); - const res = await api('/i', {}, alice); + const res = await api('i', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(res.body.hasUnreadMentions, false); @@ -56,11 +56,11 @@ describe('Note thread mute', () => { test('ミュートしているスレッドからメンションされても、ストリームに unreadMention イベントが流れてこない', () => new Promise(async done => { // 状態リセット - await api('/i/read-all-unread-notes', {}, alice); + await api('i/read-all-unread-notes', {}, alice); const bobNote = await post(bob, { text: '@alice @carol root note' }); - await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice); + await api('notes/thread-muting/create', { noteId: bobNote.id }, alice); let fired = false; @@ -84,12 +84,12 @@ describe('Note thread mute', () => { const bobNote = await post(bob, { text: '@alice @carol root note' }); const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' }); - await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice); + await api('notes/thread-muting/create', { noteId: bobNote.id }, alice); const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' }); const carolReplyWithoutMention = await post(carol, { replyId: aliceReply.id, text: 'child note' }); - const res = await api('/i/notifications', {}, alice); + const res = await api('i/notifications', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts index 88f89c4a6f..d413703ede 100644 --- a/packages/backend/test/e2e/timelines.ts +++ b/packages/backend/test/e2e/timelines.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -26,7 +26,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi'); @@ -35,14 +35,14 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーのノートが含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi' }); const carolNote = await post(carol, { text: 'hi' }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -51,14 +51,14 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーの visibility: followers なノートが含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); const carolNote = await post(carol, { text: 'hi' }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); @@ -68,14 +68,14 @@ describe('Timelines', () => { test.concurrent('withReplies: false でフォローしているユーザーの他人への返信が含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -84,15 +84,15 @@ describe('Timelines', () => { test.concurrent('withReplies: true でフォローしているユーザーの他人への返信が含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - await api('/following/update', { userId: bob.id, withReplies: true }, alice); + await api('following/create', { userId: bob.id }, alice); + await api('following/update', { userId: bob.id, withReplies: true }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -101,15 +101,15 @@ describe('Timelines', () => { test.concurrent('withReplies: true でフォローしているユーザーの他人へのDM返信が含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - await api('/following/update', { userId: bob.id, withReplies: true }, alice); + await api('following/create', { userId: bob.id }, alice); + await api('following/update', { userId: bob.id, withReplies: true }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -118,15 +118,15 @@ describe('Timelines', () => { test.concurrent('withReplies: true でフォローしているユーザーの他人の visibility: followers な投稿への返信が含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - await api('/following/update', { userId: bob.id, withReplies: true }, alice); + await api('following/create', { userId: bob.id }, alice); + await api('following/update', { userId: bob.id, withReplies: true }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi', visibility: 'followers' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -135,17 +135,17 @@ describe('Timelines', () => { test.concurrent('withReplies: true でフォローしているユーザーの行った別のフォローしているユーザーの visibility: followers な投稿への返信が含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - await api('/following/create', { userId: carol.id }, alice); - await api('/following/create', { userId: carol.id }, bob); - await api('/following/update', { userId: bob.id, withReplies: true }, alice); + await api('following/create', { userId: bob.id }, alice); + await api('following/create', { userId: carol.id }, alice); + await api('following/create', { userId: carol.id }, bob); + await api('following/update', { userId: bob.id, withReplies: true }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi', visibility: 'followers' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); @@ -155,16 +155,16 @@ describe('Timelines', () => { test.concurrent('withReplies: true でフォローしているユーザーの行った別のフォローしているユーザーの投稿への visibility: specified な返信が含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - await api('/following/create', { userId: carol.id }, alice); - await api('/following/update', { userId: bob.id, withReplies: true }, alice); + await api('following/create', { userId: bob.id }, alice); + await api('following/create', { userId: carol.id }, alice); + await api('following/update', { userId: bob.id, withReplies: true }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); @@ -173,14 +173,14 @@ describe('Timelines', () => { test.concurrent('withReplies: false でフォローしているユーザーのそのユーザー自身への返信が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); @@ -189,14 +189,14 @@ describe('Timelines', () => { test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const aliceNote = await post(alice, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); @@ -210,7 +210,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); @@ -219,14 +219,14 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーの他人の投稿のリノートが含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { renoteId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -235,14 +235,14 @@ describe('Timelines', () => { test.concurrent('[withRenotes: false] フォローしているユーザーの他人の投稿のリノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { renoteId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { + const res = await api('notes/timeline', { withRenotes: false, }, alice); @@ -253,14 +253,14 @@ describe('Timelines', () => { test.concurrent('[withRenotes: false] フォローしているユーザーの他人の投稿の引用が含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { + const res = await api('notes/timeline', { withRenotes: false, }, alice); @@ -271,13 +271,13 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーの他人への visibility: specified なノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -285,15 +285,15 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーが行ったミュートしているユーザーのリノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - await api('/mute/create', { userId: carol.id }, alice); + await api('following/create', { userId: bob.id }, alice); + await api('mute/create', { userId: carol.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -302,16 +302,16 @@ describe('Timelines', () => { test.concurrent('withReplies: true でフォローしているユーザーが行ったミュートしているユーザーの投稿への返信が含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - await api('/following/update', { userId: bob.id, withReplies: true }, alice); - await api('/mute/create', { userId: carol.id }, alice); + await api('following/create', { userId: bob.id }, alice); + await api('following/update', { userId: bob.id, withReplies: true }, alice); + await api('mute/create', { userId: carol.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -321,13 +321,13 @@ describe('Timelines', () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); const bobNote = await post(bob, { text: 'hi' }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -336,13 +336,13 @@ describe('Timelines', () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -350,7 +350,7 @@ describe('Timelines', () => { test.concurrent('[withFiles: true] フォローしているユーザーのファイル付きノートのみ含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const [bobFile, carolFile] = await Promise.all([ uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'), @@ -363,7 +363,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100, withFiles: true }, alice); + const res = await api('notes/timeline', { limit: 100, withFiles: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); @@ -374,14 +374,14 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーのチャンネル投稿が含まれない', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body); - await api('/following/create', { userId: bob.id }, alice); + const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -393,7 +393,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi'); @@ -402,13 +402,13 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーの自身を visibleUserIds に指定した visibility: specified なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); @@ -421,7 +421,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -429,13 +429,13 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーの自身を visibleUserIds に指定していない visibility: specified なノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] }); await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -448,7 +448,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'ok'); @@ -463,7 +463,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'ok'); @@ -479,7 +479,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/timeline', { limit: 100 }, alice); + const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -494,7 +494,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -508,7 +508,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); @@ -522,7 +522,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); @@ -531,12 +531,12 @@ describe('Timelines', () => { test.concurrent('チャンネル投稿が含まれない', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body); + const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body); const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -548,7 +548,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -557,14 +557,14 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーの visibility: home なノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: carol.id }, alice); + await api('following/create', { userId: carol.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi', visibility: 'home' }); const bobNote = await post(bob, { text: 'hi' }); await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -573,14 +573,14 @@ describe('Timelines', () => { test.concurrent('ミュートしているユーザーのノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/mute/create', { userId: carol.id }, alice); + await api('mute/create', { userId: carol.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi' }); await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -589,15 +589,15 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーが行ったミュートしているユーザーのリノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - await api('/mute/create', { userId: carol.id }, alice); + await api('following/create', { userId: bob.id }, alice); + await api('mute/create', { userId: carol.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -606,16 +606,16 @@ describe('Timelines', () => { test.concurrent('withReplies: true でフォローしているユーザーが行ったミュートしているユーザーの投稿への返信が含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - await api('/following/update', { userId: bob.id, withReplies: true }, alice); - await api('/mute/create', { userId: carol.id }, alice); + await api('following/create', { userId: bob.id }, alice); + await api('following/update', { userId: bob.id, withReplies: true }, alice); + await api('mute/create', { userId: carol.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); @@ -624,14 +624,14 @@ describe('Timelines', () => { test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const aliceNote = await post(alice, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); @@ -645,7 +645,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100, withReplies: true }, alice); + const res = await api('notes/local-timeline', { limit: 100, withReplies: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -659,7 +659,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100, withFiles: true }, alice); + const res = await api('notes/local-timeline', { limit: 100, withFiles: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); @@ -674,7 +674,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice); + const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -686,7 +686,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice); + const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -694,13 +694,13 @@ describe('Timelines', () => { test.concurrent('フォローしているローカルユーザーの visibility: home なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); - const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice); + const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -708,14 +708,14 @@ describe('Timelines', () => { test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const aliceNote = await post(alice, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); await waitForPushToTl(); - const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice); + const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); @@ -729,7 +729,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice); + const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); @@ -742,7 +742,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/local-timeline', { limit: 100 }, alice); + const res = await api('notes/local-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -751,13 +751,13 @@ describe('Timelines', () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); const bobNote = await post(bob, { text: 'hi' }); await waitForPushToTl(); - const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice); + const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -766,13 +766,13 @@ describe('Timelines', () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); - const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice); + const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -785,7 +785,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/hybrid-timeline', { limit: 100, withReplies: true }, alice); + const res = await api('notes/hybrid-timeline', { limit: 100, withReplies: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -799,7 +799,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/notes/hybrid-timeline', { limit: 100, withFiles: true }, alice); + const res = await api('notes/hybrid-timeline', { limit: 100, withFiles: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); @@ -810,14 +810,14 @@ describe('Timelines', () => { test.concurrent('リスインしているフォローしていないユーザーのノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi' }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -825,14 +825,14 @@ describe('Timelines', () => { test.concurrent('リスインしているフォローしていないユーザーの visibility: home なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -840,14 +840,14 @@ describe('Timelines', () => { test.concurrent('リスインしているフォローしていないユーザーの visibility: followers なノートが含まれない', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -855,15 +855,15 @@ describe('Timelines', () => { test.concurrent('リスインしているフォローしていないユーザーの他人への返信が含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -871,15 +871,15 @@ describe('Timelines', () => { test.concurrent('リスインしているフォローしていないユーザーのユーザー自身への返信が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await sleep(1000); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); @@ -888,15 +888,15 @@ describe('Timelines', () => { test.concurrent('withReplies: false でリスインしているフォローしていないユーザーからの自分への返信が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await sleep(1000); const aliceNote = await post(alice, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id, withReplies: false }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id, withReplies: false }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -904,16 +904,16 @@ describe('Timelines', () => { test.concurrent('withReplies: true でリスインしているフォローしていないユーザーの他人への返信が含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); - await api('/users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: true }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); + await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: true }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -921,15 +921,15 @@ describe('Timelines', () => { test.concurrent('リスインしているフォローしているユーザーの visibility: home なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -937,15 +937,15 @@ describe('Timelines', () => { test.concurrent('リスインしているフォローしているユーザーの visibility: followers なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); @@ -954,14 +954,14 @@ describe('Timelines', () => { test.concurrent('リスインしている自分の visibility: followers なノートが含まれる', async () => { const [alice] = await Promise.all([signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: alice.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: alice.id }, alice); await sleep(1000); const aliceNote = await post(alice, { text: 'hi', visibility: 'followers' }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi'); @@ -970,15 +970,15 @@ describe('Timelines', () => { test.concurrent('リスインしているユーザーのチャンネルノートが含まれない', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -986,15 +986,15 @@ describe('Timelines', () => { test.concurrent('[withFiles: true] リスインしているユーザーのファイル付きノートのみ含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id, withFiles: true }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id, withFiles: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); @@ -1003,14 +1003,14 @@ describe('Timelines', () => { test.concurrent('リスインしているユーザーの自身宛ての visibility: specified なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); @@ -1019,15 +1019,15 @@ describe('Timelines', () => { test.concurrent('リスインしているユーザーの自身宛てではない visibility: specified なノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); - await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); - await api('/users/lists/push', { listId: list.id, userId: carol.id }, alice); + const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); + await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); + await api('users/lists/push', { listId: list.id, userId: carol.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] }); await waitForPushToTl(); - const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); + const res = await api('notes/user-list-timeline', { listId: list.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -1041,7 +1041,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id }, alice); + const res = await api('users/notes', { userId: bob.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -1053,7 +1053,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id }, alice); + const res = await api('users/notes', { userId: bob.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -1061,13 +1061,13 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーの visibility: followers なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - await api('/following/create', { userId: bob.id }, alice); + await api('following/create', { userId: bob.id }, alice); await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id }, alice); + const res = await api('users/notes', { userId: bob.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); @@ -1080,7 +1080,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/users/notes', { userId: alice.id }, alice); + const res = await api('users/notes', { userId: alice.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi'); @@ -1089,12 +1089,12 @@ describe('Timelines', () => { test.concurrent('チャンネル投稿が含まれない', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body); + const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body); const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id }, alice); + const res = await api('users/notes', { userId: bob.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -1108,7 +1108,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id }, alice); + const res = await api('users/notes', { userId: bob.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), false); @@ -1123,7 +1123,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice); + const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); @@ -1138,7 +1138,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice); + const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), false); @@ -1153,7 +1153,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id, withFiles: true }, alice); + const res = await api('users/notes', { userId: bob.id, withFiles: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); @@ -1162,12 +1162,12 @@ describe('Timelines', () => { test.concurrent('[withChannelNotes: true] チャンネル投稿が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body); + const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body); const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id, withChannelNotes: true }, alice); + const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -1175,12 +1175,12 @@ describe('Timelines', () => { test.concurrent('[withChannelNotes: true] 他人が取得した場合センシティブチャンネル投稿が含まれない', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - const channel = await api('/channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body); + const channel = await api('channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body); const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id, withChannelNotes: true }, alice); + const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -1188,12 +1188,12 @@ describe('Timelines', () => { test.concurrent('[withChannelNotes: true] 自分が取得した場合センシティブチャンネル投稿が含まれる', async () => { const [bob] = await Promise.all([signup()]); - const channel = await api('/channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body); + const channel = await api('channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body); const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id, withChannelNotes: true }, bob); + const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, bob); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); }); @@ -1201,14 +1201,14 @@ describe('Timelines', () => { test.concurrent('ミュートしているユーザーに関連する投稿が含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/mute/create', { userId: carol.id }, alice); + await api('mute/create', { userId: carol.id }, alice); await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id }, alice); + const res = await api('users/notes', { userId: bob.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); @@ -1216,7 +1216,7 @@ describe('Timelines', () => { test.concurrent('ミュートしていても userId に指定したユーザーの投稿が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); - await api('/mute/create', { userId: bob.id }, alice); + await api('mute/create', { userId: bob.id }, alice); await sleep(1000); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); @@ -1224,7 +1224,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id }, alice); + const res = await api('users/notes', { userId: bob.id }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); @@ -1238,7 +1238,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/users/notes', { userId: alice.id, withReplies: true }, alice); + const res = await api('users/notes', { userId: alice.id, withReplies: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); }); @@ -1250,7 +1250,7 @@ describe('Timelines', () => { await waitForPushToTl(); - const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice); + const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice); assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); }); diff --git a/packages/backend/test/e2e/user-notes.ts b/packages/backend/test/e2e/user-notes.ts index 07da0db369..331e053935 100644 --- a/packages/backend/test/e2e/user-notes.ts +++ b/packages/backend/test/e2e/user-notes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -11,9 +11,9 @@ import type * as misskey from 'misskey-js'; describe('users/notes', () => { let alice: misskey.entities.SignupResponse; - let jpgNote: any; - let pngNote: any; - let jpgPngNote: any; + let jpgNote: misskey.entities.Note; + let pngNote: misskey.entities.Note; + let jpgPngNote: misskey.entities.Note; beforeAll(async () => { alice = await signup({ username: 'alice' }); @@ -31,7 +31,7 @@ describe('users/notes', () => { }, 1000 * 60 * 2); test('withFiles', async () => { - const res = await api('/users/notes', { + const res = await api('users/notes', { userId: alice.id, withFiles: true, }, alice); diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index bc23c009b2..3458e06384 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -8,7 +8,7 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { inspect } from 'node:util'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; -import { api, page, post, role, signup, successfulApiCall, uploadFile } from '../utils.js'; +import { api, post, role, signup, successfulApiCall, uploadFile } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('ユーザー', () => { @@ -24,31 +24,12 @@ describe('ユーザー', () => { }, {}); }; - // BUG misskey-jsとjson-schemaと実際に返ってくるデータが全部違う - type UserLite = misskey.entities.UserLite & { - badgeRoles: any[], - }; - - type UserDetailedNotMe = UserLite & - misskey.entities.UserDetailed & { - roles: any[], - }; - - type MeDetailed = UserDetailedNotMe & - misskey.entities.MeDetailed & { - achievements: object[], - loggedInDays: number, - policies: object, - }; - - type User = MeDetailed & { token: string }; - - const show = async (id: string, me = root): Promise => { - return successfulApiCall({ endpoint: 'users/show', parameters: { userId: id }, user: me }) as any; + const show = async (id: string, me = root): Promise => { + return successfulApiCall({ endpoint: 'users/show', parameters: { userId: id }, user: me }); }; // UserLiteのキーが過不足なく入っている? - const userLite = (user: User): Partial => { + const userLite = (user: misskey.entities.UserLite): Partial => { return stripUndefined({ id: user.id, name: user.name, @@ -71,7 +52,7 @@ describe('ユーザー', () => { }; // UserDetailedNotMeのキーが過不足なく入っている? - const userDetailedNotMe = (user: User): Partial => { + const userDetailedNotMe = (user: misskey.entities.SignupResponse): Partial => { return stripUndefined({ ...userLite(user), url: user.url, @@ -111,7 +92,7 @@ describe('ユーザー', () => { }; // Relations関連のキーが過不足なく入っている? - const userDetailedNotMeWithRelations = (user: User): Partial => { + const userDetailedNotMeWithRelations = (user: misskey.entities.SignupResponse): Partial => { return stripUndefined({ ...userDetailedNotMe(user), isFollowing: user.isFollowing ?? false, @@ -128,7 +109,7 @@ describe('ユーザー', () => { }; // MeDetailedのキーが過不足なく入っている? - const meDetailed = (user: User, security = false): Partial => { + const meDetailed = (user: misskey.entities.SignupResponse, security = false): Partial => { return stripUndefined({ ...userDetailedNotMe(user), avatarId: user.avatarId, @@ -159,6 +140,7 @@ describe('ユーザー', () => { mutedWords: user.mutedWords, hardMutedWords: user.hardMutedWords, mutedInstances: user.mutedInstances, + // @ts-expect-error 後方互換性 mutingNotificationTypes: user.mutingNotificationTypes, notificationRecieveConfig: user.notificationRecieveConfig, emailNotificationTypes: user.emailNotificationTypes, @@ -173,61 +155,53 @@ describe('ユーザー', () => { }); }; - let root: User; - let alice: User; + let root: misskey.entities.SignupResponse; + let alice: misskey.entities.SignupResponse; let aliceNote: misskey.entities.Note; - let alicePage: misskey.entities.Page; - let aliceList: misskey.entities.UserList; - let bob: User; - let bobNote: misskey.entities.Note; + let bob: misskey.entities.SignupResponse; - let carol: User; - let dave: User; - let ellen: User; - let frank: User; + // NOTE: これがないと落ちる(bob の updatedAt が null になってしまうため?) + let bobNote: misskey.entities.Note; // eslint-disable-line @typescript-eslint/no-unused-vars - let usersReplying: User[]; + let carol: misskey.entities.SignupResponse; - let userNoNote: User; - let userNotExplorable: User; - let userLocking: User; - let userAdmin: User; - let roleAdmin: any; - let userModerator: User; - let roleModerator: any; - let userRolePublic: User; - let rolePublic: any; - let userRoleBadge: User; - let roleBadge: any; - let userSilenced: User; - let roleSilenced: any; - let userSuspended: User; - let userDeletedBySelf: User; - let userDeletedByAdmin: User; - let userFollowingAlice: User; - let userFollowedByAlice: User; - let userBlockingAlice: User; - let userBlockedByAlice: User; - let userMutingAlice: User; - let userMutedByAlice: User; - let userRnMutingAlice: User; - let userRnMutedByAlice: User; - let userFollowRequesting: User; - let userFollowRequested: User; + let usersReplying: misskey.entities.SignupResponse[]; + + let userNoNote: misskey.entities.SignupResponse; + let userNotExplorable: misskey.entities.SignupResponse; + let userLocking: misskey.entities.SignupResponse; + let userAdmin: misskey.entities.SignupResponse; + let roleAdmin: misskey.entities.Role; + let userModerator: misskey.entities.SignupResponse; + let roleModerator: misskey.entities.Role; + let userRolePublic: misskey.entities.SignupResponse; + let rolePublic: misskey.entities.Role; + let userRoleBadge: misskey.entities.SignupResponse; + let roleBadge: misskey.entities.Role; + let userSilenced: misskey.entities.SignupResponse; + let roleSilenced: misskey.entities.Role; + let userSuspended: misskey.entities.SignupResponse; + let userDeletedBySelf: misskey.entities.SignupResponse; + let userDeletedByAdmin: misskey.entities.SignupResponse; + let userFollowingAlice: misskey.entities.SignupResponse; + let userFollowedByAlice: misskey.entities.SignupResponse; + let userBlockingAlice: misskey.entities.SignupResponse; + let userBlockedByAlice: misskey.entities.SignupResponse; + let userMutingAlice: misskey.entities.SignupResponse; + let userMutedByAlice: misskey.entities.SignupResponse; + let userRnMutingAlice: misskey.entities.SignupResponse; + let userRnMutedByAlice: misskey.entities.SignupResponse; + let userFollowRequesting: misskey.entities.SignupResponse; + let userFollowRequested: misskey.entities.SignupResponse; beforeAll(async () => { root = await signup({ username: 'root' }); alice = await signup({ username: 'alice' }); - aliceNote = await post(alice, { text: 'test' }) as any; - alicePage = await page(alice); - aliceList = (await api('users/list/create', { name: 'aliceList' }, alice)).body; + aliceNote = await post(alice, { text: 'test' }); bob = await signup({ username: 'bob' }); - bobNote = await post(bob, { text: 'test' }) as any; + bobNote = await post(bob, { text: 'test' }); carol = await signup({ username: 'carol' }); - dave = await signup({ username: 'dave' }); - ellen = await signup({ username: 'ellen' }); - frank = await signup({ username: 'frank' }); // @alice -> @replyingへのリプライ。Promise.allで一気に作るとtimeoutしてしまうのでreduceで一つ一つawaitする usersReplying = await [...Array(10)].map((_, i) => i).reduce(async (acc, i) => { @@ -238,7 +212,7 @@ describe('ユーザー', () => { } return (await acc).concat(u); - }, Promise.resolve([] as User[])); + }, Promise.resolve([] as misskey.entities.SignupResponse[])); userNoNote = await signup({ username: 'userNoNote' }); userNotExplorable = await signup({ username: 'userNotExplorable' }); @@ -306,7 +280,7 @@ describe('ユーザー', () => { beforeEach(async () => { alice = { ...alice, - ...await successfulApiCall({ endpoint: 'i', parameters: {}, user: alice }) as any, + ...await successfulApiCall({ endpoint: 'i', parameters: {}, user: alice }), }; aliceNote = await successfulApiCall({ endpoint: 'notes/show', parameters: { noteId: aliceNote.id }, user: alice }); }); @@ -319,7 +293,7 @@ describe('ユーザー', () => { endpoint: 'signup', parameters: { username: 'zoe', password: 'password' }, user: undefined, - }) as unknown as User; // BUG MeDetailedに足りないキーがある + }) as unknown as misskey.entities.SignupResponse; // BUG MeDetailedに足りないキーがある // signupの時はtokenが含まれる特別なMeDetailedが返ってくる assert.match(response.token, /[a-zA-Z0-9]{16}/); @@ -329,7 +303,7 @@ describe('ユーザー', () => { assert.strictEqual(response.name, null); assert.strictEqual(response.username, 'zoe'); assert.strictEqual(response.host, null); - assert.match(response.avatarUrl, /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/); + response.avatarUrl && assert.match(response.avatarUrl, /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/); assert.strictEqual(response.avatarBlurhash, null); assert.deepStrictEqual(response.avatarDecorations, []); assert.strictEqual(response.isBot, false); @@ -401,6 +375,7 @@ describe('ユーザー', () => { assert.deepStrictEqual(response.unreadAnnouncements, []); assert.deepStrictEqual(response.mutedWords, []); assert.deepStrictEqual(response.mutedInstances, []); + // @ts-expect-error 後方互換のため assert.deepStrictEqual(response.mutingNotificationTypes, []); assert.deepStrictEqual(response.notificationRecieveConfig, {}); assert.deepStrictEqual(response.emailNotificationTypes, ['follow', 'receiveFollowRequest']); @@ -430,66 +405,66 @@ describe('ユーザー', () => { //#region 自分の情報の更新(i/update) test.each([ - { parameters: (): object => ({ name: null }) }, - { parameters: (): object => ({ name: 'x'.repeat(50) }) }, - { parameters: (): object => ({ name: 'x' }) }, - { parameters: (): object => ({ name: 'My name' }) }, - { parameters: (): object => ({ description: null }) }, - { parameters: (): object => ({ description: 'x'.repeat(1500) }) }, - { parameters: (): object => ({ description: 'x' }) }, - { parameters: (): object => ({ description: 'My description' }) }, - { parameters: (): object => ({ location: null }) }, - { parameters: (): object => ({ location: 'x'.repeat(50) }) }, - { parameters: (): object => ({ location: 'x' }) }, - { parameters: (): object => ({ location: 'My location' }) }, - { parameters: (): object => ({ birthday: '0000-00-00' }) }, - { parameters: (): object => ({ birthday: '9999-99-99' }) }, - { parameters: (): object => ({ lang: 'en-US' }) }, - { parameters: (): object => ({ fields: [] }) }, - { parameters: (): object => ({ fields: [{ name: 'x', value: 'x' }] }) }, - { parameters: (): object => ({ fields: [{ name: 'x'.repeat(3000), value: 'x'.repeat(3000) }] }) }, // BUG? fieldには制限がない - { parameters: (): object => ({ fields: Array(16).fill({ name: 'x', value: 'y' }) }) }, - { parameters: (): object => ({ isLocked: true }) }, - { parameters: (): object => ({ isLocked: false }) }, - { parameters: (): object => ({ isExplorable: false }) }, - { parameters: (): object => ({ isExplorable: true }) }, - { parameters: (): object => ({ hideOnlineStatus: true }) }, - { parameters: (): object => ({ hideOnlineStatus: false }) }, - { parameters: (): object => ({ publicReactions: false }) }, - { parameters: (): object => ({ publicReactions: true }) }, - { parameters: (): object => ({ autoAcceptFollowed: true }) }, - { parameters: (): object => ({ autoAcceptFollowed: false }) }, - { parameters: (): object => ({ noCrawle: true }) }, - { parameters: (): object => ({ noCrawle: false }) }, - { parameters: (): object => ({ preventAiLearning: false }) }, - { parameters: (): object => ({ preventAiLearning: true }) }, - { parameters: (): object => ({ isBot: true }) }, - { parameters: (): object => ({ isBot: false }) }, - { parameters: (): object => ({ isCat: true }) }, - { parameters: (): object => ({ isCat: false }) }, - { parameters: (): object => ({ injectFeaturedNote: true }) }, - { parameters: (): object => ({ injectFeaturedNote: false }) }, - { parameters: (): object => ({ receiveAnnouncementEmail: true }) }, - { parameters: (): object => ({ receiveAnnouncementEmail: false }) }, - { parameters: (): object => ({ alwaysMarkNsfw: true }) }, - { parameters: (): object => ({ alwaysMarkNsfw: false }) }, - { parameters: (): object => ({ autoSensitive: true }) }, - { parameters: (): object => ({ autoSensitive: false }) }, - { parameters: (): object => ({ followingVisibility: 'private' }) }, - { parameters: (): object => ({ followingVisibility: 'followers' }) }, - { parameters: (): object => ({ followingVisibility: 'public' }) }, - { parameters: (): object => ({ followersVisibility: 'private' }) }, - { parameters: (): object => ({ followersVisibility: 'followers' }) }, - { parameters: (): object => ({ followersVisibility: 'public' }) }, - { parameters: (): object => ({ mutedWords: Array(19).fill(['xxxxx']) }) }, - { parameters: (): object => ({ mutedWords: [['x'.repeat(194)]] }) }, - { parameters: (): object => ({ mutedWords: [] }) }, - { parameters: (): object => ({ mutedInstances: ['xxxx.xxxxx'] }) }, - { parameters: (): object => ({ mutedInstances: [] }) }, - { parameters: (): object => ({ notificationRecieveConfig: { mention: { type: 'following' } } }) }, - { parameters: (): object => ({ notificationRecieveConfig: {} }) }, - { parameters: (): object => ({ emailNotificationTypes: ['mention', 'reply', 'quote', 'follow', 'receiveFollowRequest'] }) }, - { parameters: (): object => ({ emailNotificationTypes: [] }) }, + { parameters: () => ({ name: null }) }, + { parameters: () => ({ name: 'x'.repeat(50) }) }, + { parameters: () => ({ name: 'x' }) }, + { parameters: () => ({ name: 'My name' }) }, + { parameters: () => ({ description: null }) }, + { parameters: () => ({ description: 'x'.repeat(1500) }) }, + { parameters: () => ({ description: 'x' }) }, + { parameters: () => ({ description: 'My description' }) }, + { parameters: () => ({ location: null }) }, + { parameters: () => ({ location: 'x'.repeat(50) }) }, + { parameters: () => ({ location: 'x' }) }, + { parameters: () => ({ location: 'My location' }) }, + { parameters: () => ({ birthday: '0000-00-00' }) }, + { parameters: () => ({ birthday: '9999-99-99' }) }, + { parameters: () => ({ lang: 'en-US' as const }) }, + { parameters: () => ({ fields: [] }) }, + { parameters: () => ({ fields: [{ name: 'x', value: 'x' }] }) }, + { parameters: () => ({ fields: [{ name: 'x'.repeat(3000), value: 'x'.repeat(3000) }] }) }, // BUG? fieldには制限がない + { parameters: () => ({ fields: Array(16).fill({ name: 'x', value: 'y' }) }) }, + { parameters: () => ({ isLocked: true }) }, + { parameters: () => ({ isLocked: false }) }, + { parameters: () => ({ isExplorable: false }) }, + { parameters: () => ({ isExplorable: true }) }, + { parameters: () => ({ hideOnlineStatus: true }) }, + { parameters: () => ({ hideOnlineStatus: false }) }, + { parameters: () => ({ publicReactions: false }) }, + { parameters: () => ({ publicReactions: true }) }, + { parameters: () => ({ autoAcceptFollowed: true }) }, + { parameters: () => ({ autoAcceptFollowed: false }) }, + { parameters: () => ({ noCrawle: true }) }, + { parameters: () => ({ noCrawle: false }) }, + { parameters: () => ({ preventAiLearning: false }) }, + { parameters: () => ({ preventAiLearning: true }) }, + { parameters: () => ({ isBot: true }) }, + { parameters: () => ({ isBot: false }) }, + { parameters: () => ({ isCat: true }) }, + { parameters: () => ({ isCat: false }) }, + { parameters: () => ({ injectFeaturedNote: true }) }, + { parameters: () => ({ injectFeaturedNote: false }) }, + { parameters: () => ({ receiveAnnouncementEmail: true }) }, + { parameters: () => ({ receiveAnnouncementEmail: false }) }, + { parameters: () => ({ alwaysMarkNsfw: true }) }, + { parameters: () => ({ alwaysMarkNsfw: false }) }, + { parameters: () => ({ autoSensitive: true }) }, + { parameters: () => ({ autoSensitive: false }) }, + { parameters: () => ({ followingVisibility: 'private' as const }) }, + { parameters: () => ({ followingVisibility: 'followers' as const }) }, + { parameters: () => ({ followingVisibility: 'public' as const }) }, + { parameters: () => ({ followersVisibility: 'private' as const }) }, + { parameters: () => ({ followersVisibility: 'followers' as const }) }, + { parameters: () => ({ followersVisibility: 'public' as const }) }, + { parameters: () => ({ mutedWords: Array(19).fill(['xxxxx']) }) }, + { parameters: () => ({ mutedWords: [['x'.repeat(194)]] }) }, + { parameters: () => ({ mutedWords: [] }) }, + { parameters: () => ({ mutedInstances: ['xxxx.xxxxx'] }) }, + { parameters: () => ({ mutedInstances: [] }) }, + { parameters: () => ({ notificationRecieveConfig: { mention: { type: 'following' } } }) }, + { parameters: () => ({ notificationRecieveConfig: {} }) }, + { parameters: () => ({ emailNotificationTypes: ['mention', 'reply', 'quote', 'follow', 'receiveFollowRequest'] }) }, + { parameters: () => ({ emailNotificationTypes: [] }) }, ] as const)('を書き換えることができる($#)', async ({ parameters }) => { const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters(), user: alice }); const expected = { ...meDetailed(alice, true), ...parameters() }; @@ -498,13 +473,13 @@ describe('ユーザー', () => { test('を書き換えることができる(Avatar)', async () => { const aliceFile = (await uploadFile(alice)).body; - const parameters = { avatarId: aliceFile.id }; + const parameters = { avatarId: aliceFile!.id }; const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters, user: alice }); assert.match(response.avatarUrl ?? '.', /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/); assert.match(response.avatarBlurhash ?? '.', /[ -~]{54}/); const expected = { ...meDetailed(alice, true), - avatarId: aliceFile.id, + avatarId: aliceFile!.id, avatarBlurhash: response.avatarBlurhash, avatarUrl: response.avatarUrl, }; @@ -523,13 +498,13 @@ describe('ユーザー', () => { test('を書き換えることができる(Banner)', async () => { const aliceFile = (await uploadFile(alice)).body; - const parameters = { bannerId: aliceFile.id }; + const parameters = { bannerId: aliceFile!.id }; const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters, user: alice }); assert.match(response.bannerUrl ?? '.', /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/); assert.match(response.bannerBlurhash ?? '.', /[ -~]{54}/); const expected = { ...meDetailed(alice, true), - bannerId: aliceFile.id, + bannerId: aliceFile!.id, bannerBlurhash: response.bannerBlurhash, bannerUrl: response.bannerUrl, }; @@ -579,13 +554,13 @@ describe('ユーザー', () => { //#region ユーザー(users) test.each([ - { label: 'ID昇順', parameters: { limit: 5 }, selector: (u: UserLite): string => u.id }, - { label: 'フォロワー昇順', parameters: { sort: '+follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) }, - { label: 'フォロワー降順', parameters: { sort: '-follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) }, - { label: '登録日時昇順', parameters: { sort: '+createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt }, - { label: '登録日時降順', parameters: { sort: '-createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt }, - { label: '投稿日時昇順', parameters: { sort: '+updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) }, - { label: '投稿日時降順', parameters: { sort: '-updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) }, + { label: 'ID昇順', parameters: { limit: 5 }, selector: (u: misskey.entities.UserLite): string => u.id }, + { label: 'フォロワー昇順', parameters: { sort: '+follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) }, + { label: 'フォロワー降順', parameters: { sort: '-follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) }, + { label: '登録日時昇順', parameters: { sort: '+createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt }, + { label: '登録日時降順', parameters: { sort: '-createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt }, + { label: '投稿日時昇順', parameters: { sort: '+updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) }, + { label: '投稿日時降順', parameters: { sort: '-updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) }, ] as const)('をリスト形式で取得することができる($label)', async ({ parameters, selector }) => { const response = await successfulApiCall({ endpoint: 'users', parameters, user: alice }); @@ -598,15 +573,15 @@ describe('ユーザー', () => { assert.deepStrictEqual(response, expected); }); test.each([ - { label: '「見つけやすくする」がOFFのユーザーが含まれない', user: (): User => userNotExplorable, excluded: true }, - { label: 'ミュートユーザーが含まれない', user: (): User => userMutedByAlice, excluded: true }, - { label: 'ブロックされているユーザーが含まれない', user: (): User => userBlockedByAlice, excluded: true }, - { label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice, excluded: true }, - { label: '承認制ユーザーが含まれる', user: (): User => userLocking }, - { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced }, - { label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true }, - { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf }, - { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin }, + { label: '「見つけやすくする」がOFFのユーザーが含まれない', user: () => userNotExplorable, excluded: true }, + { label: 'ミュートユーザーが含まれない', user: () => userMutedByAlice, excluded: true }, + { label: 'ブロックされているユーザーが含まれない', user: () => userBlockedByAlice, excluded: true }, + { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice, excluded: true }, + { label: '承認制ユーザーが含まれる', user: () => userLocking }, + { label: 'サイレンスユーザーが含まれる', user: () => userSilenced }, + { label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true }, + { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf }, + { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin }, ] as const)('をリスト形式で取得することができ、結果に$label', async ({ user, excluded }) => { const parameters = { limit: 100 }; const response = await successfulApiCall({ endpoint: 'users', parameters, user: alice }); @@ -620,39 +595,44 @@ describe('ユーザー', () => { //#region ユーザー情報(users/show) test.each([ - { label: 'ID指定で自分自身を', parameters: (): object => ({ userId: alice.id }), user: (): User => alice, type: meDetailed }, - { label: 'ID指定で他人を', parameters: (): object => ({ userId: alice.id }), user: (): User => bob, type: userDetailedNotMeWithRelations }, - { label: 'ID指定かつ未認証', parameters: (): object => ({ userId: alice.id }), user: undefined, type: userDetailedNotMe }, - { label: '@指定で自分自身を', parameters: (): object => ({ username: alice.username }), user: (): User => alice, type: meDetailed }, - { label: '@指定で他人を', parameters: (): object => ({ username: alice.username }), user: (): User => bob, type: userDetailedNotMeWithRelations }, - { label: '@指定かつ未認証', parameters: (): object => ({ username: alice.username }), user: undefined, type: userDetailedNotMe }, + { label: 'ID指定で自分自身を', parameters: () => ({ userId: alice.id }), user: () => alice, type: meDetailed }, + { label: 'ID指定で他人を', parameters: () => ({ userId: alice.id }), user: () => bob, type: userDetailedNotMeWithRelations }, + { label: 'ID指定かつ未認証', parameters: () => ({ userId: alice.id }), user: undefined, type: userDetailedNotMe }, + { label: '@指定で自分自身を', parameters: () => ({ username: alice.username }), user: () => alice, type: meDetailed }, + { label: '@指定で他人を', parameters: () => ({ username: alice.username }), user: () => bob, type: userDetailedNotMeWithRelations }, + { label: '@指定かつ未認証', parameters: () => ({ username: alice.username }), user: undefined, type: userDetailedNotMe }, ] as const)('を取得することができる($label)', async ({ parameters, user, type }) => { const response = await successfulApiCall({ endpoint: 'users/show', parameters: parameters(), user: user?.() }); const expected = type(alice); assert.deepStrictEqual(response, expected); }); test.each([ - { label: 'Administratorになっている', user: (): User => userAdmin, me: (): User => userAdmin, selector: (user: User): unknown => user.isAdmin }, - { label: '自分以外から見たときはAdministratorか判定できない', user: (): User => userAdmin, selector: (user: User): unknown => user.isAdmin, expected: (): undefined => undefined }, - { label: 'Moderatorになっている', user: (): User => userModerator, me: (): User => userModerator, selector: (user: User): unknown => user.isModerator }, - { label: '自分以外から見たときはModeratorか判定できない', user: (): User => userModerator, selector: (user: User): unknown => user.isModerator, expected: (): undefined => undefined }, - { label: 'サイレンスになっている', user: (): User => userSilenced, selector: (user: User): unknown => user.isSilenced }, - //{ label: 'サスペンドになっている', user: (): User => userSuspended, selector: (user: User): unknown => user.isSuspended }, - { label: '削除済みになっている', user: (): User => userDeletedBySelf, me: (): User => userDeletedBySelf, selector: (user: User): unknown => user.isDeleted }, - { label: '自分以外から見たときは削除済みか判定できない', user: (): User => userDeletedBySelf, selector: (user: User): unknown => user.isDeleted, expected: (): undefined => undefined }, - { label: '削除済み(byAdmin)になっている', user: (): User => userDeletedByAdmin, me: (): User => userDeletedByAdmin, selector: (user: User): unknown => user.isDeleted }, - { label: '自分以外から見たときは削除済み(byAdmin)か判定できない', user: (): User => userDeletedByAdmin, selector: (user: User): unknown => user.isDeleted, expected: (): undefined => undefined }, - { label: 'フォロー中になっている', user: (): User => userFollowedByAlice, selector: (user: User): unknown => user.isFollowing }, - { label: 'フォローされている', user: (): User => userFollowingAlice, selector: (user: User): unknown => user.isFollowed }, - { label: 'ブロック中になっている', user: (): User => userBlockedByAlice, selector: (user: User): unknown => user.isBlocking }, - { label: 'ブロックされている', user: (): User => userBlockingAlice, selector: (user: User): unknown => user.isBlocked }, - { label: 'ミュート中になっている', user: (): User => userMutedByAlice, selector: (user: User): unknown => user.isMuted }, - { label: 'リノートミュート中になっている', user: (): User => userRnMutedByAlice, selector: (user: User): unknown => user.isRenoteMuted }, - { label: 'フォローリクエスト中になっている', user: (): User => userFollowRequested, me: (): User => userFollowRequesting, selector: (user: User): unknown => user.hasPendingFollowRequestFromYou }, - { label: 'フォローリクエストされている', user: (): User => userFollowRequesting, me: (): User => userFollowRequested, selector: (user: User): unknown => user.hasPendingFollowRequestToYou }, + { label: 'Administratorになっている', user: () => userAdmin, me: () => userAdmin, selector: (user: misskey.entities.MeDetailed) => user.isAdmin }, + // @ts-expect-error UserDetailedNotMe doesn't include isAdmin + { label: '自分以外から見たときはAdministratorか判定できない', user: () => userAdmin, selector: (user: misskey.entities.UserDetailedNotMe) => user.isAdmin, expected: () => undefined }, + { label: 'Moderatorになっている', user: () => userModerator, me: () => userModerator, selector: (user: misskey.entities.MeDetailed) => user.isModerator }, + // @ts-expect-error UserDetailedNotMe doesn't include isModerator + { label: '自分以外から見たときはModeratorか判定できない', user: () => userModerator, selector: (user: misskey.entities.UserDetailedNotMe) => user.isModerator, expected: () => undefined }, + { label: 'サイレンスになっている', user: () => userSilenced, selector: (user: misskey.entities.UserDetailed) => user.isSilenced }, + // FIXME: 落ちる + //{ label: 'サスペンドになっている', user: () => userSuspended, selector: (user: misskey.entities.UserDetailed) => user.isSuspended }, + { label: '削除済みになっている', user: () => userDeletedBySelf, me: () => userDeletedBySelf, selector: (user: misskey.entities.MeDetailed) => user.isDeleted }, + // @ts-expect-error UserDetailedNotMe doesn't include isDeleted + { label: '自分以外から見たときは削除済みか判定できない', user: () => userDeletedBySelf, selector: (user: misskey.entities.UserDetailedNotMe) => user.isDeleted, expected: () => undefined }, + { label: '削除済み(byAdmin)になっている', user: () => userDeletedByAdmin, me: () => userDeletedByAdmin, selector: (user: misskey.entities.MeDetailed) => user.isDeleted }, + // @ts-expect-error UserDetailedNotMe doesn't include isDeleted + { label: '自分以外から見たときは削除済み(byAdmin)か判定できない', user: () => userDeletedByAdmin, selector: (user: misskey.entities.UserDetailedNotMe) => user.isDeleted, expected: () => undefined }, + { label: 'フォロー中になっている', user: () => userFollowedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isFollowing }, + { label: 'フォローされている', user: () => userFollowingAlice, selector: (user: misskey.entities.UserDetailed) => user.isFollowed }, + { label: 'ブロック中になっている', user: () => userBlockedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isBlocking }, + { label: 'ブロックされている', user: () => userBlockingAlice, selector: (user: misskey.entities.UserDetailed) => user.isBlocked }, + { label: 'ミュート中になっている', user: () => userMutedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isMuted }, + { label: 'リノートミュート中になっている', user: () => userRnMutedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isRenoteMuted }, + { label: 'フォローリクエスト中になっている', user: () => userFollowRequested, me: () => userFollowRequesting, selector: (user: misskey.entities.UserDetailed) => user.hasPendingFollowRequestFromYou }, + { label: 'フォローリクエストされている', user: () => userFollowRequesting, me: () => userFollowRequested, selector: (user: misskey.entities.UserDetailed) => user.hasPendingFollowRequestToYou }, ] as const)('を取得することができ、$labelこと', async ({ user, me, selector, expected }) => { const response = await successfulApiCall({ endpoint: 'users/show', parameters: { userId: user().id }, user: me?.() ?? alice }); - assert.strictEqual(selector(response), (expected ?? ((): true => true))()); + assert.strictEqual(selector(response as any), (expected ?? ((): true => true))()); }); test('を取得することができ、Publicなロールがセットされていること', async () => { const response = await successfulApiCall({ endpoint: 'users/show', parameters: { userId: userRolePublic.id }, user: alice }); @@ -694,17 +674,18 @@ describe('ユーザー', () => { assert.deepStrictEqual(response, expected); }); test.each([ - { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable }, - { label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice }, - { label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice }, - { label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice }, - { label: '承認制ユーザーが含まれる', user: (): User => userLocking }, - { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced }, - { label: 'サスペンドユーザーが(モデレーターが見るときは)含まれる', user: (): User => userSuspended, me: (): User => root }, + { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable }, + { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice }, + { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice }, + { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice }, + { label: '承認制ユーザーが含まれる', user: () => userLocking }, + { label: 'サイレンスユーザーが含まれる', user: () => userSilenced }, + { label: 'サスペンドユーザーが(モデレーターが見るときは)含まれる', user: () => userSuspended, me: () => root }, // BUG サスペンドユーザーを一般ユーザーから見るとrootユーザーが返ってくる - //{ label: 'サスペンドユーザーが(一般ユーザーが見るときは)含まれない', user: (): User => userSuspended, me: (): User => bob, excluded: true }, - { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf }, - { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin }, + //{ label: 'サスペンドユーザーが(一般ユーザーが見るときは)含まれない', user: () => userSuspended, me: () => bob, excluded: true }, + { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf }, + { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin }, + // @ts-expect-error excluded は上でコメントアウトされているので ] as const)('をID指定のリスト形式で取得することができ、結果に$label', async ({ user, me, excluded }) => { const parameters = { userIds: [user().id] }; const response = await successfulApiCall({ endpoint: 'users/show', parameters, user: me?.() ?? alice }); @@ -729,15 +710,15 @@ describe('ユーザー', () => { assert.deepStrictEqual(response, expected); }); test.each([ - { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable }, - { label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice }, - { label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice }, - { label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice }, - { label: '承認制ユーザーが含まれる', user: (): User => userLocking }, - { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced }, - { label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true }, - { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf }, - { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin }, + { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable }, + { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice }, + { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice }, + { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice }, + { label: '承認制ユーザーが含まれる', user: () => userLocking }, + { label: 'サイレンスユーザーが含まれる', user: () => userSilenced }, + { label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true }, + { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf }, + { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin }, ] as const)('を検索することができ、結果に$labelが含まれる', async ({ user, excluded }) => { const parameters = { query: user().username, limit: 1 }; const response = await successfulApiCall({ endpoint: 'users/search', parameters, user: alice }); @@ -751,30 +732,30 @@ describe('ユーザー', () => { //#region ID指定検索(users/search-by-username-and-host) test.each([ - { label: '自分', parameters: { username: 'alice' }, user: (): User[] => [alice] }, - { label: '自分かつusernameが大文字', parameters: { username: 'ALICE' }, user: (): User[] => [alice] }, - { label: 'ローカルのフォロイーでノートなし', parameters: { username: 'userFollowedByAlice' }, user: (): User[] => [userFollowedByAlice] }, - { label: 'ローカルでノートなしは検索に載らない', parameters: { username: 'userNoNote' }, user: (): User[] => [] }, - { label: 'ローカルの他人1', parameters: { username: 'bob' }, user: (): User[] => [bob] }, - { label: 'ローカルの他人2', parameters: { username: 'bob', host: null }, user: (): User[] => [bob] }, - { label: 'ローカルの他人3', parameters: { username: 'bob', host: '.' }, user: (): User[] => [bob] }, - { label: 'ローカル', parameters: { host: null, limit: 1 }, user: (): User[] => [userFollowedByAlice] }, - { label: 'ローカル', parameters: { host: '.', limit: 1 }, user: (): User[] => [userFollowedByAlice] }, + { label: '自分', parameters: { username: 'alice' }, user: () => [alice] }, + { label: '自分かつusernameが大文字', parameters: { username: 'ALICE' }, user: () => [alice] }, + { label: 'ローカルのフォロイーでノートなし', parameters: { username: 'userFollowedByAlice' }, user: () => [userFollowedByAlice] }, + { label: 'ローカルでノートなしは検索に載らない', parameters: { username: 'userNoNote' }, user: () => [] }, + { label: 'ローカルの他人1', parameters: { username: 'bob' }, user: () => [bob] }, + { label: 'ローカルの他人2', parameters: { username: 'bob', host: null }, user: () => [bob] }, + { label: 'ローカルの他人3', parameters: { username: 'bob', host: '.' }, user: () => [bob] }, + { label: 'ローカル', parameters: { host: null, limit: 1 }, user: () => [userFollowedByAlice] }, + { label: 'ローカル', parameters: { host: '.', limit: 1 }, user: () => [userFollowedByAlice] }, ])('をID&ホスト指定で検索できる($label)', async ({ parameters, user }) => { const response = await successfulApiCall({ endpoint: 'users/search-by-username-and-host', parameters, user: alice }); const expected = await Promise.all(user().map(u => show(u.id, alice))); assert.deepStrictEqual(response, expected); }); test.each([ - { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable }, - { label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice }, - { label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice }, - { label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice }, - { label: '承認制ユーザーが含まれる', user: (): User => userLocking }, - { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced }, - { label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true }, - { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf }, - { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin }, + { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable }, + { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice }, + { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice }, + { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice }, + { label: '承認制ユーザーが含まれる', user: () => userLocking }, + { label: 'サイレンスユーザーが含まれる', user: () => userSilenced }, + { label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true }, + { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf }, + { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin }, ] as const)('をID&ホスト指定で検索でき、結果に$label', async ({ user, excluded }) => { const parameters = { username: user().username }; const response = await successfulApiCall({ endpoint: 'users/search-by-username-and-host', parameters, user: alice }); @@ -796,15 +777,15 @@ describe('ユーザー', () => { assert.deepStrictEqual(response, expected); }); test.each([ - { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable }, - { label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice }, - { label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice }, - { label: 'ブロックしてきているユーザーが含まれない', user: (): User => userBlockingAlice, excluded: true }, - { label: '承認制ユーザーが含まれる', user: (): User => userLocking }, - { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced }, - //{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true }, - { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf }, - { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin }, + { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable }, + { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice }, + { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice }, + { label: 'ブロックしてきているユーザーが含まれない', user: () => userBlockingAlice, excluded: true }, + { label: '承認制ユーザーが含まれる', user: () => userLocking }, + { label: 'サイレンスユーザーが含まれる', user: () => userSilenced }, + //{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true }, + { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf }, + { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin }, ] as const)('がよくリプライをするユーザーのリストを取得でき、結果に$label', async ({ user, excluded }) => { const replyTo = (await successfulApiCall({ endpoint: 'users/notes', parameters: { userId: user().id }, user: undefined }))[0]; await post(alice, { text: `@${user().username} test`, replyId: replyTo.id }); @@ -818,12 +799,12 @@ describe('ユーザー', () => { //#region ハッシュタグ(hashtags/users) test.each([ - { label: 'フォロワー昇順', sort: { sort: '+follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) }, - { label: 'フォロワー降順', sort: { sort: '-follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) }, - { label: '登録日時昇順', sort: { sort: '+createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt }, - { label: '登録日時降順', sort: { sort: '-createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt }, - { label: '投稿日時昇順', sort: { sort: '+updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) }, - { label: '投稿日時降順', sort: { sort: '-updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) }, + { label: 'フォロワー昇順', sort: { sort: '+follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) }, + { label: 'フォロワー降順', sort: { sort: '-follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) }, + { label: '登録日時昇順', sort: { sort: '+createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt }, + { label: '登録日時降順', sort: { sort: '-createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt }, + { label: '投稿日時昇順', sort: { sort: '+updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) }, + { label: '投稿日時降順', sort: { sort: '-updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) }, ] as const)('をハッシュタグ指定で取得することができる($label)', async ({ sort, selector }) => { const hashtag = 'test_hashtag'; await successfulApiCall({ endpoint: 'i/update', parameters: { description: `#${hashtag}` }, user: alice }); @@ -837,15 +818,15 @@ describe('ユーザー', () => { assert.deepStrictEqual(response, expected); }); test.each([ - { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable }, - { label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice }, - { label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice }, - { label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice }, - { label: '承認制ユーザーが含まれる', user: (): User => userLocking }, - { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced }, - { label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true }, - { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf }, - { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin }, + { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable }, + { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice }, + { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice }, + { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice }, + { label: '承認制ユーザーが含まれる', user: () => userLocking }, + { label: 'サイレンスユーザーが含まれる', user: () => userSilenced }, + { label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true }, + { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf }, + { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin }, ] as const)('をハッシュタグ指定で取得することができ、結果に$label', async ({ user, excluded }) => { const hashtag = `user_test${user().username}`; if (user() !== userSuspended) { diff --git a/packages/backend/test/e2e/well-known.ts b/packages/backend/test/e2e/well-known.ts index 0429b7c8b2..bdb298dfe4 100644 --- a/packages/backend/test/e2e/well-known.ts +++ b/packages/backend/test/e2e/well-known.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/misc/mock-resolver.ts b/packages/backend/test/misc/mock-resolver.ts index 7ee65d1ab0..3c7e796700 100644 --- a/packages/backend/test/misc/mock-resolver.ts +++ b/packages/backend/test/misc/mock-resolver.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/prelude/get-api-validator.ts b/packages/backend/test/prelude/get-api-validator.ts index cccd63299a..b86a7a978d 100644 --- a/packages/backend/test/prelude/get-api-validator.ts +++ b/packages/backend/test/prelude/get-api-validator.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/prelude/maybe.ts b/packages/backend/test/prelude/maybe.ts index 37ccfbf7fe..16e92216d4 100644 --- a/packages/backend/test/prelude/maybe.ts +++ b/packages/backend/test/prelude/maybe.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/prelude/url.ts b/packages/backend/test/prelude/url.ts index 340c6451ce..b26ae09444 100644 --- a/packages/backend/test/prelude/url.ts +++ b/packages/backend/test/prelude/url.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/AnnouncementService.ts b/packages/backend/test/unit/AnnouncementService.ts index f02c4e6700..aa082ff2f2 100644 --- a/packages/backend/test/unit/AnnouncementService.ts +++ b/packages/backend/test/unit/AnnouncementService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -51,7 +51,7 @@ describe('AnnouncementService', () => { function createAnnouncement(data: Partial = {}) { return announcementsRepository.insert({ - id: genAidx(data.createdAt ?? new Date()), + id: genAidx(data.createdAt?.getTime() ?? Date.now()), updatedAt: null, title: 'Title', text: 'Text', diff --git a/packages/backend/test/unit/ApMfmService.ts b/packages/backend/test/unit/ApMfmService.ts new file mode 100644 index 0000000000..2b79041c86 --- /dev/null +++ b/packages/backend/test/unit/ApMfmService.ts @@ -0,0 +1,44 @@ +import * as assert from 'assert'; +import { Test } from '@nestjs/testing'; + +import { CoreModule } from '@/core/CoreModule.js'; +import { ApMfmService } from '@/core/activitypub/ApMfmService.js'; +import { GlobalModule } from '@/GlobalModule.js'; +import { MiNote } from '@/models/Note.js'; + +describe('ApMfmService', () => { + let apMfmService: ApMfmService; + + beforeAll(async () => { + const app = await Test.createTestingModule({ + imports: [GlobalModule, CoreModule], + }).compile(); + apMfmService = app.get(ApMfmService); + }); + + describe('getNoteHtml', () => { + test('Do not provide _misskey_content for simple text', () => { + const note: MiNote = { + text: 'テキスト #タグ @mention 🍊 :emoji: https://example.com', + mentionedRemoteUsers: '[]', + } as any; + + const { content, noMisskeyContent } = apMfmService.getNoteHtml(note); + + assert.equal(noMisskeyContent, true, 'noMisskeyContent'); + assert.equal(content, '

テキスト @mention 🍊 ​:emoji:​ https://example.com

', 'content'); + }); + + test('Provide _misskey_content for MFM', () => { + const note: MiNote = { + text: '$[tada foo]', + mentionedRemoteUsers: '[]', + } as any; + + const { content, noMisskeyContent } = apMfmService.getNoteHtml(note); + + assert.equal(noMisskeyContent, false, 'noMisskeyContent'); + assert.equal(content, '

foo

', 'content'); + }); + }); +}); diff --git a/packages/backend/test/unit/DriveService.ts b/packages/backend/test/unit/DriveService.ts index 64397a1a4f..964c65ccaa 100644 --- a/packages/backend/test/unit/DriveService.ts +++ b/packages/backend/test/unit/DriveService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/FetchInstanceMetadataService.ts b/packages/backend/test/unit/FetchInstanceMetadataService.ts index cddc374f9a..bf8f3ab0e3 100644 --- a/packages/backend/test/unit/FetchInstanceMetadataService.ts +++ b/packages/backend/test/unit/FetchInstanceMetadataService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -19,8 +19,8 @@ import { DI } from '@/di-symbols.js'; import type { TestingModule } from '@nestjs/testing'; function mockRedis() { - const hash = {}; - const set = jest.fn((key, value) => { + const hash = {} as any; + const set = jest.fn((key: string, value) => { const ret = hash[key]; hash[key] = value; return ret; @@ -56,12 +56,13 @@ describe('FetchInstanceMetadataService', () => { } else if (token === DI.redis) { return mockRedis; } + return null; }) .compile(); app.enableShutdownHooks(); - fetchInstanceMetadataService = app.get(FetchInstanceMetadataService); + fetchInstanceMetadataService = app.get(FetchInstanceMetadataService) as jest.Mocked; federatedInstanceService = app.get(FederatedInstanceService) as jest.Mocked; redisClient = app.get(DI.redis) as jest.Mocked; httpRequestService = app.get(HttpRequestService) as jest.Mocked; @@ -74,11 +75,12 @@ describe('FetchInstanceMetadataService', () => { test('Lock and update', async () => { redisClient.set = mockRedis(); const now = Date.now(); - federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => { return now - 10 * 1000 * 60 * 60 * 24; } } }); + federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => { return now - 10 * 1000 * 60 * 60 * 24; } } } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock'); const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock'); - await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' }); + + await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any); expect(tryLockSpy).toHaveBeenCalledTimes(1); expect(unlockSpy).toHaveBeenCalledTimes(1); expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1); @@ -88,11 +90,12 @@ describe('FetchInstanceMetadataService', () => { test('Lock and don\'t update', async () => { redisClient.set = mockRedis(); const now = Date.now(); - federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => now } }); + federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now } } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock'); const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock'); - await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' }); + + await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any); expect(tryLockSpy).toHaveBeenCalledTimes(1); expect(unlockSpy).toHaveBeenCalledTimes(1); expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1); @@ -101,15 +104,33 @@ describe('FetchInstanceMetadataService', () => { test('Do nothing when lock not acquired', async () => { redisClient.set = mockRedis(); - federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } }); + const now = Date.now(); + federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); + await fetchInstanceMetadataService.tryLock('example.com'); const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock'); const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock'); - await fetchInstanceMetadataService.tryLock('example.com'); - await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' }); - expect(tryLockSpy).toHaveBeenCalledTimes(2); + + await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any); + expect(tryLockSpy).toHaveBeenCalledTimes(1); expect(unlockSpy).toHaveBeenCalledTimes(0); expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0); expect(httpRequestService.getJson).toHaveBeenCalledTimes(0); }); + + test('Do when lock not acquired but forced', async () => { + redisClient.set = mockRedis(); + const now = Date.now(); + federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any); + httpRequestService.getJson.mockImplementation(() => { throw Error(); }); + await fetchInstanceMetadataService.tryLock('example.com'); + const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock'); + const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock'); + + await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any, true); + expect(tryLockSpy).toHaveBeenCalledTimes(0); + expect(unlockSpy).toHaveBeenCalledTimes(1); + expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0); + expect(httpRequestService.getJson).toHaveBeenCalled(); + }); }); diff --git a/packages/backend/test/unit/FileInfoService.ts b/packages/backend/test/unit/FileInfoService.ts index f3717d73cd..2eec80d763 100644 --- a/packages/backend/test/unit/FileInfoService.ts +++ b/packages/backend/test/unit/FileInfoService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/MetaService.ts b/packages/backend/test/unit/MetaService.ts index c4c7f21913..19c98eab3d 100644 --- a/packages/backend/test/unit/MetaService.ts +++ b/packages/backend/test/unit/MetaService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/MfmService.ts b/packages/backend/test/unit/MfmService.ts index bb8e6981d5..f613fe9c7c 100644 --- a/packages/backend/test/unit/MfmService.ts +++ b/packages/backend/test/unit/MfmService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -33,6 +33,12 @@ describe('MfmService', () => { const output = '

foo
bar
baz

'; assert.equal(mfmService.toHtml(mfm.parse(input)), output); }); + + test('Do not generate unnecessary span', () => { + const input = 'foo $[tada bar]'; + const output = '

foo bar

'; + assert.equal(mfmService.toHtml(mfm.parse(input)), output); + }); }); describe('fromHtml', () => { diff --git a/packages/backend/test/unit/ReactionService.ts b/packages/backend/test/unit/ReactionService.ts index 7b5bf7d0a0..1957f4544c 100644 --- a/packages/backend/test/unit/ReactionService.ts +++ b/packages/backend/test/unit/ReactionService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -90,4 +90,45 @@ describe('ReactionService', () => { assert.strictEqual(await reactionService.normalize('unknown'), '❤'); }); }); + + describe('convertLegacyReactions', () => { + test('空の入力に対しては何もしない', () => { + const input = {}; + assert.deepStrictEqual(reactionService.convertLegacyReactions(input), input); + }); + + test('Unicode絵文字リアクションを変換してしまわない', () => { + const input = { '👍': 1, '🍮': 2 }; + assert.deepStrictEqual(reactionService.convertLegacyReactions(input), input); + }); + + test('カスタム絵文字リアクションを変換してしまわない', () => { + const input = { ':like@.:': 1, ':pudding@example.tld:': 2 }; + assert.deepStrictEqual(reactionService.convertLegacyReactions(input), input); + }); + + test('文字列によるレガシーなリアクションを変換する', () => { + const input = { 'like': 1, 'pudding': 2 }; + const output = { '👍': 1, '🍮': 2 }; + assert.deepStrictEqual(reactionService.convertLegacyReactions(input), output); + }); + + test('host部分が省略されたレガシーなカスタム絵文字リアクションを変換する', () => { + const input = { ':custom_emoji:': 1 }; + const output = { ':custom_emoji@.:': 1 }; + assert.deepStrictEqual(reactionService.convertLegacyReactions(input), output); + }); + + test('「0個のリアクション」情報を削除する', () => { + const input = { 'angry': 0 }; + const output = {}; + assert.deepStrictEqual(reactionService.convertLegacyReactions(input), output); + }); + + test('host部分の有無によりデコードすると同じ表記になるカスタム絵文字リアクションの個数情報を正しく足し合わせる', () => { + const input = { ':custom_emoji:': 1, ':custom_emoji@.:': 2 }; + const output = { ':custom_emoji@.:': 3 }; + assert.deepStrictEqual(reactionService.convertLegacyReactions(input), output); + }); + }); }); diff --git a/packages/backend/test/unit/RelayService.ts b/packages/backend/test/unit/RelayService.ts index f780a25388..f2a67dba46 100644 --- a/packages/backend/test/unit/RelayService.ts +++ b/packages/backend/test/unit/RelayService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts index 46613c29c8..19d03570e0 100644 --- a/packages/backend/test/unit/RoleService.ts +++ b/packages/backend/test/unit/RoleService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -228,11 +228,14 @@ describe('RoleService', () => { }, target: 'conditional', condFormula: { + id: '232a4221-9816-49a6-a967-ae0fac52ec5e', type: 'and', values: [{ + id: '2a37ef43-2d93-4c4d-87f6-f2fdb7d9b530', type: 'followersMoreThanOrEq', value: 10, }, { + id: '1bd67839-b126-4f92-bad0-4e285dab453b', type: 'createdMoreThan', sec: 60 * 60 * 24 * 7, }], @@ -251,6 +254,34 @@ describe('RoleService', () => { expect(user2Policies.canManageCustomEmojis).toBe(true); }); + test('コンディショナルロール: マニュアルロールにアサイン済み', async () => { + const [user1, user2, role1] = await Promise.all([ + createUser(), + createUser(), + createRole({ + name: 'manual role', + }), + ]); + const role2 = await createRole({ + name: 'conditional role', + target: 'conditional', + condFormula: { + // idはバックエンドのロジックに必要ない? + id: 'bdc612bd-9d54-4675-ae83-0499c82ea670', + type: 'roleAssignedTo', + roleId: role1.id, + }, + }); + await roleService.assign(user2.id, role1.id); + + const [u1role, u2role] = await Promise.all([ + roleService.getUserRoles(user1.id), + roleService.getUserRoles(user2.id), + ]); + expect(u1role.some(r => r.id === role2.id)).toBe(false); + expect(u2role.some(r => r.id === role2.id)).toBe(true); + }); + test('expired role', async () => { const user = await createUser(); const role = await createRole({ diff --git a/packages/backend/test/unit/S3Service.ts b/packages/backend/test/unit/S3Service.ts index 2ffc99380d..151f3b826a 100644 --- a/packages/backend/test/unit/S3Service.ts +++ b/packages/backend/test/unit/S3Service.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/activitypub.ts b/packages/backend/test/unit/activitypub.ts index 63952e6434..b4b06b06bd 100644 --- a/packages/backend/test/unit/activitypub.ts +++ b/packages/backend/test/unit/activitypub.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -100,6 +100,7 @@ describe('ActivityPub', () => { perRemoteUserUserTimelineCacheMax: 100, blockedHosts: [] as string[], sensitiveWords: [] as string[], + prohibitedWords: [] as string[], } as MiMeta; let meta = metaInitial; @@ -202,7 +203,7 @@ describe('ActivityPub', () => { describe('Renderer', () => { test('Render an announce with visibility: followers', () => { - rendererService.renderAnnounce(null, { + rendererService.renderAnnounce('https://example.com/notes/00example', { id: genAidx(Date.now()), visibility: 'followers', } as MiNote); diff --git a/packages/backend/test/unit/ap-request.ts b/packages/backend/test/unit/ap-request.ts index 9edd53d274..d3d39240dc 100644 --- a/packages/backend/test/unit/ap-request.ts +++ b/packages/backend/test/unit/ap-request.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/chart.ts b/packages/backend/test/unit/chart.ts index 036e73fd5e..9dedd3a79d 100644 --- a/packages/backend/test/unit/chart.ts +++ b/packages/backend/test/unit/chart.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/extract-mentions.ts b/packages/backend/test/unit/extract-mentions.ts index 5901f33fdc..3403387e30 100644 --- a/packages/backend/test/unit/extract-mentions.ts +++ b/packages/backend/test/unit/extract-mentions.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/misc/check-word-mute.ts b/packages/backend/test/unit/misc/check-word-mute.ts index 12bfca8bd7..eb0ca0f6cf 100644 --- a/packages/backend/test/unit/misc/check-word-mute.ts +++ b/packages/backend/test/unit/misc/check-word-mute.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/misc/correct-filename.ts b/packages/backend/test/unit/misc/correct-filename.ts index 0c4482e0bf..c76fb4c494 100644 --- a/packages/backend/test/unit/misc/correct-filename.ts +++ b/packages/backend/test/unit/misc/correct-filename.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/misc/id.ts b/packages/backend/test/unit/misc/id.ts index 1498c075aa..d14efb10a6 100644 --- a/packages/backend/test/unit/misc/id.ts +++ b/packages/backend/test/unit/misc/id.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/unit/misc/others.ts b/packages/backend/test/unit/misc/others.ts index caa815b3df..3bc134a2b8 100644 --- a/packages/backend/test/unit/misc/others.ts +++ b/packages/backend/test/unit/misc/others.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index a41002cc8c..86814fffe0 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -9,18 +9,18 @@ import { basename, isAbsolute } from 'node:path'; import { randomUUID } from 'node:crypto'; import { inspect } from 'node:util'; import WebSocket, { ClientOptions } from 'ws'; -import fetch, { File, RequestInit } from 'node-fetch'; +import fetch, { File, RequestInit, type Headers } from 'node-fetch'; import { DataSource } from 'typeorm'; import { JSDOM } from 'jsdom'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; +import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js'; import { entities } from '../src/postgres.js'; import { loadConfig } from '../src/config.js'; import type * as misskey from 'misskey-js'; -import { Packed } from '@/misc/json-schema.js'; export { server as startServer, jobQueue as startJobQueue } from '@/boot/common.js'; -interface UserToken { +export interface UserToken { token: string; bearer?: boolean; } @@ -34,20 +34,15 @@ export const cookie = (me: UserToken): string => { return `token=${me.token};`; }; -export const api = async (endpoint: string, params: any, me?: UserToken) => { - const normalized = endpoint.replace(/^\//, ''); - return await request(`api/${normalized}`, params, me); -}; - -export type ApiRequest = { - endpoint: string, - parameters: object, +export type ApiRequest = { + endpoint: E, + parameters: P, user: UserToken | undefined, }; -export const successfulApiCall = async (request: ApiRequest, assertion: { +export const successfulApiCall = async (request: ApiRequest, assertion: { status?: number, -} = {}): Promise => { +} = {}): Promise> => { const { endpoint, parameters, user } = request; const res = await api(endpoint, parameters, user); const status = assertion.status ?? (res.body == null ? 204 : 200); @@ -55,7 +50,7 @@ export const successfulApiCall = async (request: ApiRequest, assertion: { return res.body; }; -export const failedApiCall = async (request: ApiRequest, assertion: { +export const failedApiCall = async (request: ApiRequest, assertion: { status: number, code: string, id: string @@ -69,7 +64,7 @@ export const failedApiCall = async (request: ApiRequest, assertion: { return res.body; }; -const request = async (path: string, params: any, me?: UserToken): Promise<{ +export const api = async (path: E, params: misskey.Endpoints[E]['req'], me?: UserToken): Promise<{ status: number, headers: Headers, body: any @@ -85,7 +80,7 @@ const request = async (path: string, params: any, me?: UserToken): Promise<{ bodyAuth.i = me.token; } - const res = await relativeFetch(path, { + const res = await relativeFetch(`api/${path}`, { method: 'POST', headers, body: JSON.stringify(Object.assign(bodyAuth, params)), @@ -123,9 +118,9 @@ export function randomString(chars = 'abcdefghijklmnopqrstuvwxyz0123456789', len function timeoutPromise(p: Promise, timeout: number): Promise { return Promise.race([ p, - new Promise((reject) =>{ - setTimeout(() => { reject(new Error('timed out')); }, timeout) - }) as never + new Promise((reject) => { + setTimeout(() => { reject(new Error('timed out')); }, timeout); + }) as never, ]); } @@ -140,7 +135,7 @@ export const signup = async (params?: Partial => { +export const post = async (user: UserToken, params: misskey.Endpoints['notes/create']['req']): Promise => { const q = params; const res = await api('notes/create', q, user); @@ -158,8 +153,8 @@ export const createAppToken = async (user: UserToken, permissions: (typeof missk }; // 非公開ノートをAPI越しに見たときのノート NoteEntityService.ts -export const hiddenNote = (note: any): any => { - const temp = { +export const hiddenNote = (note: misskey.entities.Note): misskey.entities.Note => { + const temp: misskey.entities.Note = { ...note, fileIds: [], files: [], @@ -172,21 +167,22 @@ export const hiddenNote = (note: any): any => { return temp; }; -export const react = async (user: UserToken, note: any, reaction: string): Promise => { +export const react = async (user: UserToken, note: misskey.entities.Note, reaction: string): Promise => { await api('notes/reactions/create', { noteId: note.id, reaction: reaction, }, user); }; -export const userList = async (user: UserToken, userList: any = {}): Promise => { +export const userList = async (user: UserToken, userList: Partial = {}): Promise => { const res = await api('users/lists/create', { name: 'test', + ...userList, }, user); return res.body; }; -export const page = async (user: UserToken, page: any = {}): Promise => { +export const page = async (user: UserToken, page: Partial = {}): Promise => { const res = await api('pages/create', { alignCenter: false, content: [ @@ -197,7 +193,7 @@ export const page = async (user: UserToken, page: any = {}): Promise => { }, ], eyeCatchingImageId: null, - font: 'sans-serif', + font: 'sans-serif' as any, hideTitleWhenPinned: false, name: '1678594845072', script: '', @@ -209,7 +205,7 @@ export const page = async (user: UserToken, page: any = {}): Promise => { return res.body; }; -export const play = async (user: UserToken, play: any = {}): Promise => { +export const play = async (user: UserToken, play: Partial = {}): Promise => { const res = await api('flash/create', { permissions: [], script: 'test', @@ -220,7 +216,7 @@ export const play = async (user: UserToken, play: any = {}): Promise => { return res.body; }; -export const clip = async (user: UserToken, clip: any = {}): Promise => { +export const clip = async (user: UserToken, clip: Partial = {}): Promise => { const res = await api('clips/create', { description: null, isPublic: true, @@ -230,18 +226,18 @@ export const clip = async (user: UserToken, clip: any = {}): Promise => { return res.body; }; -export const galleryPost = async (user: UserToken, channel: any = {}): Promise => { +export const galleryPost = async (user: UserToken, galleryPost: Partial = {}): Promise => { const res = await api('gallery/posts/create', { description: null, fileIds: [], isSensitive: false, title: 'test', - ...channel, + ...galleryPost, }, user); return res.body; }; -export const channel = async (user: UserToken, channel: any = {}): Promise => { +export const channel = async (user: UserToken, channel: Partial = {}): Promise => { const res = await api('channels/create', { bannerId: null, description: null, @@ -251,7 +247,7 @@ export const channel = async (user: UserToken, channel: any = {}): Promise return res.body; }; -export const role = async (user: UserToken, role: any = {}, policies: any = {}): Promise => { +export const role = async (user: UserToken, role: Partial = {}, policies: any = {}): Promise => { const res = await api('admin/roles/create', { asBadge: false, canEditMembersByModerator: false, @@ -259,7 +255,7 @@ export const role = async (user: UserToken, role: any = {}, policies: any = {}): condFormula: { id: 'ebef1684-672d-49b6-ad82-1b3ec3784f85', type: 'isRemote', - }, + } as any, description: '', displayOrder: 0, iconUrl: null, @@ -297,7 +293,7 @@ interface UploadOptions { export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadOptions = {}): Promise<{ status: number, headers: Headers, - body: misskey.Endpoints['drive/files/create']['res'] | null + body: misskey.entities.DriveFile | null }> => { const absPath = path == null ? new URL('resources/Lenna.jpg', import.meta.url) @@ -327,7 +323,6 @@ export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadO }); const body = res.status !== 204 ? await res.json() as misskey.Endpoints['drive/files/create']['res'] : null; - return { status: res.status, headers: res.headers, @@ -335,15 +330,15 @@ export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadO }; }; -export const uploadUrl = async (user: UserToken, url: string): Promise> => { +export const uploadUrl = async (user: UserToken, url: string): Promise => { const marker = Math.random().toString(); const catcher = makeStreamCatcher( user, 'main', (msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker, - (msg) => msg.body.file as Packed<'DriveFile'>, - 60 * 1000 + (msg) => msg.body.file, + 60 * 1000, ); await api('drive/files/upload-from-url', { @@ -355,7 +350,7 @@ export const uploadUrl = async (user: UserToken, url: string): Promise) => any, params?: any): Promise { +export function connectStream(user: UserToken, channel: C, listener: (message: Record) => any, params?: misskey.Channels[C]['params']): Promise { return new Promise((res, rej) => { const url = new URL(`ws://127.0.0.1:${port}/streaming`); const options: ClientOptions = {}; @@ -390,7 +385,7 @@ export function connectStream(user: UserToken, channel: string, listener: (messa }); } -export const waitFire = async (user: UserToken, channel: string, trgr: () => any, cond: (msg: Record) => boolean, params?: any) => { +export const waitFire = async (user: UserToken, channel: C, trgr: () => any, cond: (msg: Record) => boolean, params?: misskey.Channels[C]['params']) => { return new Promise(async (res, rej) => { let timer: NodeJS.Timeout | null = null; @@ -434,20 +429,20 @@ export const waitFire = async (user: UserToken, channel: string, trgr: () => any * @returns 時間内に正常に処理できた場合に通知からextractorを通した値を得る */ export function makeStreamCatcher( - user: UserToken, - channel: string, - cond: (message: Record) => boolean, - extractor: (message: Record) => T, - timeout = 60 * 1000): Promise { - let ws: WebSocket + user: UserToken, + channel: keyof misskey.Channels, + cond: (message: Record) => boolean, + extractor: (message: Record) => T, + timeout = 60 * 1000): Promise { + let ws: WebSocket; const p = new Promise(async (resolve) => { ws = await connectStream(user, channel, (msg) => { if (cond(msg)) { - resolve(extractor(msg)) + resolve(extractor(msg)); } }); }).finally(() => { - ws?.close(); + ws.close(); }); return timeoutPromise(p, timeout); @@ -476,6 +471,14 @@ export const simpleGet = async (path: string, accept = '*/*', cookie: any = unde 'text/html; charset=utf-8', ]; + if (res.ok && ( + accept.startsWith('application/activity+json') || + (accept.startsWith('application/ld+json') && accept.includes('https://www.w3.org/ns/activitystreams')) + )) { + // validateContentTypeSetAsActivityPubのテストを兼ねる + validateContentTypeSetAsActivityPub(res); + } + const body = jsonTypes.includes(res.headers.get('content-type') ?? '') ? await res.json() : htmlTypes.includes(res.headers.get('content-type') ?? '') ? new JSDOM(await res.text()) : diff --git a/packages/backend/watch.mjs b/packages/backend/watch.mjs index 81c23a0f50..a0ccea3b16 100644 --- a/packages/backend/watch.mjs +++ b/packages/backend/watch.mjs @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/.storybook/changes.ts b/packages/frontend/.storybook/changes.ts index 0cc648fbae..7c70972e1e 100644 --- a/packages/frontend/.storybook/changes.ts +++ b/packages/frontend/.storybook/changes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/.storybook/fakes.ts b/packages/frontend/.storybook/fakes.ts index 2960489c77..48c9e0261d 100644 --- a/packages/frontend/.storybook/fakes.ts +++ b/packages/frontend/.storybook/fakes.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/.storybook/generate.tsx b/packages/frontend/.storybook/generate.tsx index d61df9e7be..1e925aede6 100644 --- a/packages/frontend/.storybook/generate.tsx +++ b/packages/frontend/.storybook/generate.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -401,7 +401,8 @@ function toStories(component: string): Promise { // glob('src/{components,pages,ui,widgets}/**/*.vue') (async () => { const globs = await Promise.all([ - glob('src/components/global/*.vue'), + glob('src/components/global/Mk*.vue'), + glob('src/components/global/RouterView.vue'), glob('src/components/Mk{A,B}*.vue'), glob('src/components/MkDigitalClock.vue'), glob('src/components/MkGalleryPostPreview.vue'), diff --git a/packages/frontend/.storybook/main.ts b/packages/frontend/.storybook/main.ts index a450f8b46b..0a87488573 100644 --- a/packages/frontend/.storybook/main.ts +++ b/packages/frontend/.storybook/main.ts @@ -1,27 +1,30 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -import { resolve } from 'node:path'; +import { createRequire } from 'node:module'; +import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import type { StorybookConfig } from '@storybook/vue3-vite'; import { type Plugin, mergeConfig } from 'vite'; import turbosnap from 'vite-plugin-turbosnap'; -const dirname = fileURLToPath(new URL('.', import.meta.url)); +const require = createRequire(import.meta.url); +const _dirname = fileURLToPath(new URL('.', import.meta.url)); const config = { stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], addons: [ - '@storybook/addon-essentials', - '@storybook/addon-interactions', - '@storybook/addon-links', - '@storybook/addon-storysource', - resolve(dirname, '../node_modules/storybook-addon-misskey-theme'), + getAbsolutePath('@storybook/addon-essentials'), + getAbsolutePath('@storybook/addon-interactions'), + getAbsolutePath('@storybook/addon-links'), + getAbsolutePath('@storybook/addon-storysource'), + getAbsolutePath('@storybook/addon-mdx-gfm'), + resolve(_dirname, '../node_modules/storybook-addon-misskey-theme'), ], framework: { - name: '@storybook/vue3-vite', + name: getAbsolutePath('@storybook/vue3-vite') as '@storybook/vue3-vite', options: {}, }, docs: { @@ -37,10 +40,13 @@ const config = { } return mergeConfig(config, { plugins: [ - // XXX: https://github.com/IanVS/vite-plugin-turbosnap/issues/8 - (turbosnap as any as typeof turbosnap['default'])({ - rootDir: config.root ?? process.cwd(), - }), + { + // XXX: https://github.com/IanVS/vite-plugin-turbosnap/issues/8 + ...(turbosnap as any as typeof turbosnap['default'])({ + rootDir: config.root ?? process.cwd(), + }), + name: 'fake-turbosnap', + }, ], build: { target: [ @@ -53,3 +59,7 @@ const config = { }, } satisfies StorybookConfig; export default config; + +function getAbsolutePath(value: string): string { + return dirname(require.resolve(join(value, 'package.json'))); +} diff --git a/packages/frontend/.storybook/manager.ts b/packages/frontend/.storybook/manager.ts index 8f501111d0..7375a1f2a9 100644 --- a/packages/frontend/.storybook/manager.ts +++ b/packages/frontend/.storybook/manager.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/.storybook/mocks.ts b/packages/frontend/.storybook/mocks.ts index 80e5157c5a..817b0125e7 100644 --- a/packages/frontend/.storybook/mocks.ts +++ b/packages/frontend/.storybook/mocks.ts @@ -1,9 +1,9 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -import { type SharedOptions, rest } from 'msw'; +import { type SharedOptions, http, HttpResponse } from 'msw'; export const onUnhandledRequest = ((req, print) => { if (req.url.hostname !== 'localhost' || /^\/(?:client-assets\/|fluent-emojis?\/|iframe.html$|node_modules\/|src\/|sb-|static-assets\/|vite\/)/.test(req.url.pathname)) { @@ -13,19 +13,31 @@ export const onUnhandledRequest = ((req, print) => { }) satisfies SharedOptions['onUnhandledRequest']; export const commonHandlers = [ - rest.get('/fluent-emoji/:codepoints.png', async (req, res, ctx) => { - const { codepoints } = req.params; + http.get('/fluent-emoji/:codepoints.png', async ({ params }) => { + const { codepoints } = params; const value = await fetch(`https://raw.githubusercontent.com/misskey-dev/emojis/main/dist/${codepoints}.png`).then((response) => response.blob()); - return res(ctx.set('Content-Type', 'image/png'), ctx.body(value)); + return new HttpResponse(value, { + headers: { + 'Content-Type': 'image/png', + }, + }); }), - rest.get('/fluent-emojis/:codepoints.png', async (req, res, ctx) => { - const { codepoints } = req.params; + http.get('/fluent-emojis/:codepoints.png', async ({ params }) => { + const { codepoints } = params; const value = await fetch(`https://raw.githubusercontent.com/misskey-dev/emojis/main/dist/${codepoints}.png`).then((response) => response.blob()); - return res(ctx.set('Content-Type', 'image/png'), ctx.body(value)); + return new HttpResponse(value, { + headers: { + 'Content-Type': 'image/png', + }, + }); }), - rest.get('/twemoji/:codepoints.svg', async (req, res, ctx) => { - const { codepoints } = req.params; + http.get('/twemoji/:codepoints.svg', async ({ params }) => { + const { codepoints } = params; const value = await fetch(`https://unpkg.com/@discordapp/twemoji@15.0.2/dist/svg/${codepoints}.svg`).then((response) => response.blob()); - return res(ctx.set('Content-Type', 'image/svg+xml'), ctx.body(value)); + return new HttpResponse(value, { + headers: { + 'Content-Type': 'image/svg+xml', + }, + }); }), ]; diff --git a/packages/frontend/.storybook/preload-locale.ts b/packages/frontend/.storybook/preload-locale.ts index 349cc13508..c823ff9bee 100644 --- a/packages/frontend/.storybook/preload-locale.ts +++ b/packages/frontend/.storybook/preload-locale.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/.storybook/preload-theme.ts b/packages/frontend/.storybook/preload-theme.ts index ad2cf18a35..fb93d7be13 100644 --- a/packages/frontend/.storybook/preload-theme.ts +++ b/packages/frontend/.storybook/preload-theme.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/.storybook/preview.ts b/packages/frontend/.storybook/preview.ts index 9860b60c67..982a2979ac 100644 --- a/packages/frontend/.storybook/preview.ts +++ b/packages/frontend/.storybook/preview.ts @@ -1,10 +1,10 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ -import { addons } from '@storybook/addons'; import { FORCE_REMOUNT } from '@storybook/core-events'; +import { addons } from '@storybook/preview-api'; import { type Preview, setup } from '@storybook/vue3'; import isChromatic from 'chromatic/isChromatic'; import { initialize, mswDecorator } from 'msw-storybook-addon'; diff --git a/packages/frontend/@types/global.d.ts b/packages/frontend/@types/global.d.ts index 7d9335cc52..1025d1bedb 100644 --- a/packages/frontend/@types/global.d.ts +++ b/packages/frontend/@types/global.d.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -16,3 +16,8 @@ declare const _DATA_TRANSFER_DECK_COLUMN_: string; // for dev-mode declare const _LANGS_FULL_: string[][]; + +// TagCanvas +interface Window { + TagCanvas: any; +} diff --git a/packages/frontend/@types/theme.d.ts b/packages/frontend/@types/theme.d.ts index 376bbb0e9c..0a7281898d 100644 --- a/packages/frontend/@types/theme.d.ts +++ b/packages/frontend/@types/theme.d.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts index 535adc9c85..5d8cf05fff 100644 --- a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts index 68cdc0bc78..0ed2e14d2a 100644 --- a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/package.json b/packages/frontend/package.json index eeac6dcea3..682def8e8d 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -8,7 +8,7 @@ "build": "vite build", "storybook-dev": "nodemon --verbose --watch src --ext \"mdx,ts,vue\" --ignore \"*.stories.ts\" --exec \"pnpm build-storybook-pre && pnpm exec storybook dev -p 6006 --ci\"", "build-storybook-pre": "(tsc -p .storybook || echo done.) && node .storybook/generate.js && node .storybook/preload-locale.js && node .storybook/preload-theme.js", - "build-storybook": "pnpm build-storybook-pre && storybook build", + "build-storybook": "pnpm build-storybook-pre && storybook build --webpack-stats-json storybook-static", "chromatic": "chromatic", "test": "vitest --run --globals", "test-and-coverage": "vitest --run --coverage --globals", @@ -20,26 +20,26 @@ "@discordapp/twemoji": "15.0.2", "@github/webauthn-json": "2.1.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@misskey-dev/browser-image-resizer": "2.2.1-misskey.10", + "@misskey-dev/browser-image-resizer": "2024.1.0", "@rollup/plugin-json": "6.1.0", "@rollup/plugin-replace": "5.0.5", "@rollup/pluginutils": "5.1.0", "@syuilo/aiscript": "0.17.0", "@tabler/icons-webfont": "2.44.0", "@twemoji/parser": "15.0.0", - "@vitejs/plugin-vue": "5.0.2", - "@vue/compiler-sfc": "3.4.3", - "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.0.6", + "@vitejs/plugin-vue": "5.0.4", + "@vue/compiler-sfc": "3.4.21", + "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.2", "astring": "1.8.6", "broadcast-channel": "7.0.0", "buraha": "0.0.1", - "canvas-confetti": "1.6.1", - "chart.js": "4.4.1", + "canvas-confetti": "1.9.2", + "chart.js": "4.4.2", "chartjs-adapter-date-fns": "3.0.0", "chartjs-chart-matrix": "2.0.1", "chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-zoom": "2.0.1", - "chromatic": "10.3.1", + "chromatic": "11.0.0", "compare-versions": "6.1.0", "cropperjs": "2.0.0-beta.4", "date-fns": "2.30.0", @@ -57,84 +57,85 @@ "misskey-reversi": "workspace:*", "photoswipe": "5.4.3", "punycode": "2.3.1", - "rollup": "4.9.6", - "sanitize-html": "2.11.0", - "sass": "1.70.0", - "shiki": "0.14.7", + "rollup": "4.12.0", + "sanitize-html": "2.12.1", + "sass": "1.71.1", + "shiki": "1.1.7", "strict-event-emitter-types": "2.0.0", "textarea-caret": "3.1.0", - "three": "0.160.0", + "three": "0.162.0", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", "tsc-alias": "1.8.8", "tsconfig-paths": "4.2.0", "typescript": "5.3.3", "uuid": "9.0.1", - "v-code-diff": "1.7.2", - "vite": "5.0.12", - "vue": "3.4.15", + "v-code-diff": "1.9.0", + "vite": "5.1.4", + "vue": "3.4.21", "vuedraggable": "next" }, "devDependencies": { - "@misskey-dev/eslint-plugin": "^1.0.0", - "@misskey-dev/summaly": "^5.0.3", - "@storybook/addon-actions": "7.6.10", - "@storybook/addon-essentials": "7.6.10", - "@storybook/addon-interactions": "7.6.10", - "@storybook/addon-links": "7.6.10", - "@storybook/addon-storysource": "7.6.10", - "@storybook/addons": "7.6.10", - "@storybook/blocks": "7.6.10", - "@storybook/core-events": "7.6.10", - "@storybook/jest": "0.2.3", - "@storybook/manager-api": "7.6.10", - "@storybook/preview-api": "7.6.10", - "@storybook/react": "7.6.10", - "@storybook/react-vite": "7.6.10", - "@storybook/testing-library": "0.2.2", - "@storybook/theming": "7.6.10", - "@storybook/types": "7.6.10", - "@storybook/vue3": "7.6.10", - "@storybook/vue3-vite": "7.6.10", - "@testing-library/vue": "8.0.1", + "@misskey-dev/eslint-plugin": "1.0.0", + "@misskey-dev/summaly": "5.0.3", + "@storybook/addon-actions": "8.0.0-beta.6", + "@storybook/addon-essentials": "8.0.0-beta.6", + "@storybook/addon-interactions": "8.0.0-beta.6", + "@storybook/addon-links": "8.0.0-beta.6", + "@storybook/addon-mdx-gfm": "8.0.0-beta.6", + "@storybook/addon-storysource": "8.0.0-beta.6", + "@storybook/blocks": "8.0.0-beta.6", + "@storybook/components": "8.0.0-beta.6", + "@storybook/core-events": "8.0.0-beta.6", + "@storybook/manager-api": "8.0.0-beta.6", + "@storybook/preview-api": "8.0.0-beta.6", + "@storybook/react": "8.0.0-beta.6", + "@storybook/react-vite": "8.0.0-beta.6", + "@storybook/test": "8.0.0-beta.6", + "@storybook/theming": "8.0.0-beta.6", + "@storybook/types": "8.0.0-beta.6", + "@storybook/vue3": "8.0.0-beta.6", + "@storybook/vue3-vite": "8.0.0-beta.6", + "@testing-library/vue": "8.0.2", "@types/escape-regexp": "0.0.3", "@types/estree": "1.0.5", "@types/matter-js": "0.19.6", "@types/micromatch": "4.0.6", - "@types/node": "20.11.5", - "@types/punycode": "2.1.3", - "@types/sanitize-html": "2.9.5", + "@types/node": "20.11.22", + "@types/punycode": "2.1.4", + "@types/sanitize-html": "2.11.0", "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", - "@types/uuid": "9.0.7", + "@types/uuid": "9.0.8", "@types/ws": "8.5.10", - "@typescript-eslint/eslint-plugin": "6.18.1", - "@typescript-eslint/parser": "6.18.1", + "@typescript-eslint/eslint-plugin": "7.1.0", + "@typescript-eslint/parser": "7.1.0", "@vitest/coverage-v8": "0.34.6", - "@vue/runtime-core": "3.4.15", + "@vue/runtime-core": "3.4.21", "acorn": "8.11.3", "cross-env": "7.0.3", - "cypress": "13.6.3", - "eslint": "8.56.0", + "cypress": "13.6.6", + "eslint": "8.57.0", "eslint-plugin-import": "2.29.1", - "eslint-plugin-vue": "9.20.1", + "eslint-plugin-vue": "9.22.0", "fast-glob": "3.3.2", - "happy-dom": "10.0.3", + "happy-dom": "13.6.2", "intersection-observer": "0.12.2", "micromatch": "4.0.5", - "msw": "2.1.2", - "msw-storybook-addon": "1.10.0", - "nodemon": "3.0.3", - "prettier": "3.2.4", + "msw": "2.1.7", + "msw-storybook-addon": "2.0.0-beta.1", + "nodemon": "3.1.0", + "prettier": "3.2.5", "react": "18.2.0", "react-dom": "18.2.0", "start-server-and-test": "2.0.3", - "storybook": "7.6.10", + "storybook": "8.0.0-beta.6", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "vite-plugin-turbosnap": "1.0.3", "vitest": "0.34.6", "vitest-fetch-mock": "0.2.2", - "vue-eslint-parser": "9.4.0", + "vue-component-type-helpers": "1.8.27", + "vue-eslint-parser": "9.4.2", "vue-tsc": "1.8.27" } } diff --git a/packages/frontend/public/mockServiceWorker.js b/packages/frontend/public/mockServiceWorker.js index 5384ce6b94..3bb1e66910 100644 --- a/packages/frontend/public/mockServiceWorker.js +++ b/packages/frontend/public/mockServiceWorker.js @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/src/_boot_.ts b/packages/frontend/src/_boot_.ts index efb78fe447..875353f8a4 100644 --- a/packages/frontend/src/_boot_.ts +++ b/packages/frontend/src/_boot_.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/src/_dev_boot_.ts b/packages/frontend/src/_dev_boot_.ts index d01a957048..eceec76c51 100644 --- a/packages/frontend/src/_dev_boot_.ts +++ b/packages/frontend/src/_dev_boot_.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/src/account.ts b/packages/frontend/src/account.ts index b01a80d137..7f20e0b1a2 100644 --- a/packages/frontend/src/account.ts +++ b/packages/frontend/src/account.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -290,7 +290,7 @@ export async function openAccountMenu(opts: { text: i18n.ts.profile, to: `/@${ $i.username }`, avatar: $i, - }, { type: 'divider' }, ...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises, { + }, { type: 'divider' as const }, ...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises, { type: 'parent' as const, icon: 'ti ti-plus', text: i18n.ts.addAccount, diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts index c67911c9c3..681beaf00f 100644 --- a/packages/frontend/src/boot/common.ts +++ b/packages/frontend/src/boot/common.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -22,7 +22,7 @@ import { getAccountFromId } from '@/scripts/get-account-from-id.js'; import { deckStore } from '@/ui/deck/deck-store.js'; import { miLocalStorage } from '@/local-storage.js'; import { fetchCustomEmojis } from '@/custom-emojis.js'; -import { setupRouter } from '@/global/router/definition.js'; +import { setupRouter } from '@/router/definition.js'; export async function common(createVue: () => App) { console.info(`Misskey v${version}`); @@ -60,12 +60,6 @@ export async function common(createVue: () => App) { }); } - const splash = document.getElementById('splash'); - // 念のためnullチェック(HTMLが古い場合があるため(そのうち消す)) - if (splash) splash.addEventListener('transitionend', () => { - splash.remove(); - }); - let isClientUpdated = false; //#region クライアントが更新されたかチェック @@ -289,5 +283,10 @@ function removeSplash() { if (splash) { splash.style.opacity = '0'; splash.style.pointerEvents = 'none'; + + // transitionendイベントが発火しない場合があるため + window.setTimeout(() => { + splash.remove(); + }, 1000); } } diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index eb0ac43da7..61f04678bf 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -11,6 +11,7 @@ import { alert, confirm, popup, post, toast } from '@/os.js'; import { useStream } from '@/stream.js'; import * as sound from '@/scripts/sound.js'; import { $i, signout, updateAccount } from '@/account.js'; +import { instance } from '@/instance.js'; import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { makeHotkey } from '@/scripts/hotkey.js'; import { reactionPicker } from '@/scripts/reaction-picker.js'; @@ -19,7 +20,7 @@ import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js import { initializeSw } from '@/scripts/initialize-sw.js'; import { deckStore } from '@/ui/deck/deck-store.js'; import { emojiPicker } from '@/scripts/emoji-picker.js'; -import { mainRouter } from '@/global/router/main.js'; +import { mainRouter } from '@/router/main.js'; export async function mainBoot() { const { isClientUpdated } = await common(() => createApp( @@ -81,13 +82,18 @@ export async function mainBoot() { // ▼南半球 if (month === 7 || month === 8) { const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect; - new SnowfallEffect().render(); + new SnowfallEffect({}).render(); } } else { // ▼北半球 if (month === 12 || month === 1) { const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect; - new SnowfallEffect().render(); + new SnowfallEffect({}).render(); + } else if (month === 3 || month === 4) { + const SakuraEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect; + new SakuraEffect({ + sakura: true, + }).render(); } } } @@ -229,6 +235,11 @@ export async function mainBoot() { } } + const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read'); + if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey') { + popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed'); + } + if ('Notification' in window) { // 許可を得ていなかったらリクエスト if (Notification.permission === 'default') { diff --git a/packages/frontend/src/boot/sub-boot.ts b/packages/frontend/src/boot/sub-boot.ts index 92ee074afb..017457822b 100644 --- a/packages/frontend/src/boot/sub-boot.ts +++ b/packages/frontend/src/boot/sub-boot.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/src/cache.ts b/packages/frontend/src/cache.ts index 20950add80..b286528de6 100644 --- a/packages/frontend/src/cache.ts +++ b/packages/frontend/src/cache.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/src/components/MkAbuseReport.stories.impl.ts b/packages/frontend/src/components/MkAbuseReport.stories.impl.ts index 77e7c84d5c..cf09c96fd4 100644 --- a/packages/frontend/src/components/MkAbuseReport.stories.impl.ts +++ b/packages/frontend/src/components/MkAbuseReport.stories.impl.ts @@ -1,12 +1,12 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { action } from '@storybook/addon-actions'; import { StoryObj } from '@storybook/vue3'; -import { rest } from 'msw'; +import { HttpResponse, http } from 'msw'; import { abuseUserReport } from '../../.storybook/fakes.js'; import { commonHandlers } from '../../.storybook/mocks.js'; import MkAbuseReport from './MkAbuseReport.vue'; @@ -44,9 +44,9 @@ export const Default = { msw: { handlers: [ ...commonHandlers, - rest.post('/api/admin/resolve-abuse-user-report', async (req, res, ctx) => { - action('POST /api/admin/resolve-abuse-user-report')(await req.json()); - return res(ctx.json({})); + http.post('/api/admin/resolve-abuse-user-report', async ({ request }) => { + action('POST /api/admin/resolve-abuse-user-report')(await request.json()); + return HttpResponse.json({}); }), ], }, diff --git a/packages/frontend/src/components/MkAbuseReport.vue b/packages/frontend/src/components/MkAbuseReport.vue index ce7e134b70..271b94feaa 100644 --- a/packages/frontend/src/components/MkAbuseReport.vue +++ b/packages/frontend/src/components/MkAbuseReport.vue @@ -1,12 +1,12 @@ -
+
@@ -68,7 +68,7 @@ import MkInput from '@/components/MkInput.vue'; import MkSwitch from '@/components/MkSwitch.vue'; import MkTextarea from '@/components/MkTextarea.vue'; import MkSelect from '@/components/MkSelect.vue'; -import { AsUiComponent } from '@/scripts/aiscript/ui.js'; +import { AsUiComponent, AsUiRoot, AsUiPostFormButton } from '@/scripts/aiscript/ui.js'; import MkFolder from '@/components/MkFolder.vue'; import MkPostForm from '@/components/MkPostForm.vue'; @@ -85,20 +85,32 @@ const props = withDefaults(defineProps<{ const c = props.component; function g(id) { - return props.components.find(x => x.value.id === id).value; + const v = props.components.find(x => x.value.id === id)?.value; + if (v) return v; + + return { + id: 'dummy', + type: 'root', + children: [], + } as AsUiRoot; } -const valueForSwitch = ref(c.default ?? false); +const valueForSwitch = ref('default' in c && typeof c.default === 'boolean' ? c.default : false); function onSwitchUpdate(v) { valueForSwitch.value = v; - if (c.onChange) c.onChange(v); + if ('onChange' in c && c.onChange) { + c.onChange(v as never); + } } function openPostForm() { + const form = (c as AsUiPostFormButton).form; + if (!form) return; + os.post({ - initialText: c.form.text, - initialCw: c.form.cw, + initialText: form.text, + initialCw: form.cw, instant: true, }); } diff --git a/packages/frontend/src/components/MkAutocomplete.stories.impl.ts b/packages/frontend/src/components/MkAutocomplete.stories.impl.ts index 969519386f..ec24b8c240 100644 --- a/packages/frontend/src/components/MkAutocomplete.stories.impl.ts +++ b/packages/frontend/src/components/MkAutocomplete.stories.impl.ts @@ -1,14 +1,13 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { action } from '@storybook/addon-actions'; -import { expect } from '@storybook/jest'; -import { userEvent, waitFor, within } from '@storybook/testing-library'; +import { expect, userEvent, waitFor, within } from '@storybook/test'; import { StoryObj } from '@storybook/vue3'; -import { rest } from 'msw'; +import { HttpResponse, http } from 'msw'; import { userDetailed } from '../../.storybook/fakes.js'; import { commonHandlers } from '../../.storybook/mocks.js'; import MkAutocomplete from './MkAutocomplete.vue'; @@ -99,11 +98,11 @@ export const User = { msw: { handlers: [ ...commonHandlers, - rest.post('/api/users/search-by-username-and-host', (req, res, ctx) => { - return res(ctx.json([ + http.post('/api/users/search-by-username-and-host', () => { + return HttpResponse.json([ userDetailed('44', 'mizuki', 'misskey-hub.net', 'Mizuki'), userDetailed('49', 'momoko', 'misskey-hub.net', 'Momoko'), - ])); + ]); }), ], }, @@ -132,12 +131,12 @@ export const Hashtag = { msw: { handlers: [ ...commonHandlers, - rest.post('/api/hashtags/search', (req, res, ctx) => { - return res(ctx.json([ + http.post('/api/hashtags/search', () => { + return HttpResponse.json([ '気象警報注意報', '気象警報', '気象情報', - ])); + ]); }), ], }, diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 9d03eab2cb..932c4ecb2e 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -1,5 +1,5 @@ @@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
  1. - + @@ -57,18 +57,7 @@ import { i18n } from '@/i18n.js'; import { miLocalStorage } from '@/local-storage.js'; import { customEmojis } from '@/custom-emojis.js'; import { MFM_TAGS, MFM_PARAMS } from '@/const.js'; - -type EmojiDef = { - emoji: string; - name: string; - url: string; - aliasOf?: string; -} | { - emoji: string; - name: string; - aliasOf?: string; - isCustomEmoji?: true; -}; +import { searchEmoji, EmojiDef } from '@/scripts/search-emoji.js'; const lib = emojilist.filter(x => x.category !== 'flags'); @@ -88,7 +77,7 @@ const emojiDb = computed(() => { unicodeEmojiDB.push({ emoji: emoji, name: k, - aliasOf: getEmojiName(emoji)!, + aliasOf: getEmojiName(emoji), url: char2path(emoji), }); } @@ -249,7 +238,7 @@ function exec() { return; } - emojis.value = emojiAutoComplete(props.q, emojiDb.value); + emojis.value = searchEmoji(props.q, emojiDb.value); } else if (props.type === 'mfmTag') { if (!props.q || props.q === '') { mfmTags.value = MFM_TAGS; @@ -267,87 +256,6 @@ function exec() { } } -type EmojiScore = { emoji: EmojiDef, score: number }; - -function emojiAutoComplete(query: string | null, emojiDb: EmojiDef[], max = 30): EmojiDef[] { - if (!query) { - return []; - } - - const matched = new Map(); - // 完全一致(エイリアス込み) - emojiDb.some(x => { - if (x.name === query && !matched.has(x.aliasOf ?? x.name)) { - matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length + 2 }); - } - return matched.size === max; - }); - - // 前方一致(エイリアスなし) - if (matched.size < max) { - emojiDb.some(x => { - if (x.name.startsWith(query) && !x.aliasOf) { - matched.set(x.name, { emoji: x, score: query.length + 1 }); - } - return matched.size === max; - }); - } - - // 前方一致(エイリアス込み) - if (matched.size < max) { - emojiDb.some(x => { - if (x.name.startsWith(query) && !matched.has(x.aliasOf ?? x.name)) { - matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length }); - } - return matched.size === max; - }); - } - - // 部分一致(エイリアス込み) - if (matched.size < max) { - emojiDb.some(x => { - if (x.name.includes(query) && !matched.has(x.aliasOf ?? x.name)) { - matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length - 1 }); - } - return matched.size === max; - }); - } - - // 簡易あいまい検索(3文字以上) - if (matched.size < max && query.length > 3) { - const queryChars = [...query]; - const hitEmojis = new Map(); - - for (const x of emojiDb) { - // 文字列の位置を進めながら、クエリの文字を順番に探す - - let pos = 0; - let hit = 0; - for (const c of queryChars) { - pos = x.name.indexOf(c, pos); - if (pos <= -1) break; - hit++; - } - - // 半分以上の文字が含まれていればヒットとする - if (hit > Math.ceil(queryChars.length / 2) && hit - 2 > (matched.get(x.aliasOf ?? x.name)?.score ?? 0)) { - hitEmojis.set(x.aliasOf ?? x.name, { emoji: x, score: hit - 2 }); - } - } - - // ヒットしたものを全部追加すると雑多になるので、先頭の6件程度だけにしておく(6件=オートコンプリートのポップアップのサイズ分) - [...hitEmojis.values()] - .sort((x, y) => y.score - x.score) - .slice(0, 6) - .forEach(it => matched.set(it.emoji.name, it)); - } - - return [...matched.values()] - .sort((x, y) => y.score - x.score) - .slice(0, max) - .map(it => it.emoji); -} - function onMousedown(event: Event) { if (!contains(rootEl.value, event.target) && (rootEl.value !== event.target)) props.close(); } @@ -431,7 +339,7 @@ function applySelect() { function chooseUser() { props.close(); - os.selectUser().then(user => { + os.selectUser({ includeSelf: true }).then(user => { complete('user', user); props.textarea.focus(); }); diff --git a/packages/frontend/src/components/MkAvatars.stories.impl.ts b/packages/frontend/src/components/MkAvatars.stories.impl.ts index d41b64695f..d2a4a9f03b 100644 --- a/packages/frontend/src/components/MkAvatars.stories.impl.ts +++ b/packages/frontend/src/components/MkAvatars.stories.impl.ts @@ -1,11 +1,11 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StoryObj } from '@storybook/vue3'; -import { rest } from 'msw'; +import { HttpResponse, http } from 'msw'; import { userDetailed } from '../../.storybook/fakes.js'; import { commonHandlers } from '../../.storybook/mocks.js'; import MkAvatars from './MkAvatars.vue'; @@ -38,12 +38,12 @@ export const Default = { msw: { handlers: [ ...commonHandlers, - rest.post('/api/users/show', (req, res, ctx) => { - return res(ctx.json([ + http.post('/api/users/show', () => { + return HttpResponse.json([ userDetailed('17'), userDetailed('20'), userDetailed('18'), - ])); + ]); }), ], }, diff --git a/packages/frontend/src/components/MkAvatars.vue b/packages/frontend/src/components/MkAvatars.vue index 6ef4a7dfe2..8236d0ddb9 100644 --- a/packages/frontend/src/components/MkAvatars.vue +++ b/packages/frontend/src/components/MkAvatars.vue @@ -1,5 +1,5 @@ diff --git a/packages/frontend/src/components/MkButton.stories.impl.ts b/packages/frontend/src/components/MkButton.stories.impl.ts index e852557b12..e8802e4f8f 100644 --- a/packages/frontend/src/components/MkButton.stories.impl.ts +++ b/packages/frontend/src/components/MkButton.stories.impl.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index 8d4631968d..817f1aadf3 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -1,5 +1,5 @@ @@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
    diff --git a/packages/frontend/src/components/MkCaptcha.stories.impl.ts b/packages/frontend/src/components/MkCaptcha.stories.impl.ts index fb50e50b18..475257cc45 100644 --- a/packages/frontend/src/components/MkCaptcha.stories.impl.ts +++ b/packages/frontend/src/components/MkCaptcha.stories.impl.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue index f60c721eae..c64bb47e77 100644 --- a/packages/frontend/src/components/MkCaptcha.vue +++ b/packages/frontend/src/components/MkCaptcha.vue @@ -1,11 +1,11 @@ - - diff --git a/packages/frontend/src/components/MkFeaturedPhotos.vue b/packages/frontend/src/components/MkFeaturedPhotos.vue index 8a23d7d4bf..8d875790bc 100644 --- a/packages/frontend/src/components/MkFeaturedPhotos.vue +++ b/packages/frontend/src/components/MkFeaturedPhotos.vue @@ -1,5 +1,5 @@ diff --git a/packages/frontend/src/components/MkFileCaptionEditWindow.vue b/packages/frontend/src/components/MkFileCaptionEditWindow.vue index 922089a78b..76bb965101 100644 --- a/packages/frontend/src/components/MkFileCaptionEditWindow.vue +++ b/packages/frontend/src/components/MkFileCaptionEditWindow.vue @@ -1,5 +1,5 @@ @@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only :withOkButton="true" :okButtonDisabled="false" @ok="ok()" - @close="dialog.close()" + @close="dialog?.close()" @closed="emit('closed')" > @@ -48,6 +48,6 @@ const caption = ref(props.default); async function ok() { emit('done', caption.value); - dialog.value.close(); + dialog.value?.close(); } diff --git a/packages/frontend/src/components/MkFileListForAdmin.vue b/packages/frontend/src/components/MkFileListForAdmin.vue index 3edd30bc37..30822ef655 100644 --- a/packages/frontend/src/components/MkFileListForAdmin.vue +++ b/packages/frontend/src/components/MkFileListForAdmin.vue @@ -1,5 +1,5 @@ @@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
    diff --git a/packages/frontend/src/components/MkFoldableSection.vue b/packages/frontend/src/components/MkFoldableSection.vue index 1ffc95d944..f10d58b38a 100644 --- a/packages/frontend/src/components/MkFoldableSection.vue +++ b/packages/frontend/src/components/MkFoldableSection.vue @@ -1,10 +1,10 @@