Merge branch 'develop' into report-renote-abuse

This commit is contained in:
anatawa12 2023-08-21 18:03:23 +09:00 committed by GitHub
commit 7bd341ec9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
636 changed files with 4210 additions and 3217 deletions

View File

@ -159,6 +159,9 @@ id: 'aid'
#deliverJobMaxAttempts: 12 #deliverJobMaxAttempts: 12
#inboxJobMaxAttempts: 8 #inboxJobMaxAttempts: 8
# Local address used for outgoing requests
#outgoingAddress: 127.0.0.1
# IP address family used for outgoing request (ipv4, ipv6 or dual) # IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4 #outgoingAddressFamily: ipv4

View File

@ -6,7 +6,7 @@
"features": { "features": {
"ghcr.io/devcontainers-contrib/features/pnpm:2": {}, "ghcr.io/devcontainers-contrib/features/pnpm:2": {},
"ghcr.io/devcontainers/features/node:1": { "ghcr.io/devcontainers/features/node:1": {
"version": "20.3.1" "version": "20.5.0"
} }
}, },
"forwardPorts": [3000], "forwardPorts": [3000],

View File

@ -1,7 +1,4 @@
contact_links: contact_links:
- name: 👪 Misskey Forum
url: https://forum.misskey.io/
about: Ask questions and share knowledge
- name: 💬 Misskey official Discord - name: 💬 Misskey official Discord
url: https://discord.gg/Wp8gVStHW3 url: https://discord.gg/Wp8gVStHW3
about: Chat freely about Misskey about: Chat freely about Misskey

View File

@ -9,24 +9,24 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: daily interval: daily
open-pull-requests-limit: 0 open-pull-requests-limit: 100
# Add only the root, not each workspace item
# https://github.com/dependabot/dependabot-core/issues/4993#issuecomment-1289133027
- package-ecosystem: npm - package-ecosystem: npm
directory: "/" directory: "/"
schedule: schedule:
interval: daily interval: daily
# PNPM has an issue with dependabot. See:
# https://github.com/dependabot/dependabot-core/issues/7258
# https://github.com/pnpm/pnpm/issues/6530
# TODO: Restore this when the issue is solved
open-pull-requests-limit: 0 open-pull-requests-limit: 0
- package-ecosystem: npm groups:
directory: "/packages/backend" swc:
schedule: patterns:
interval: daily - "@swc/*"
open-pull-requests-limit: 0 storybook:
- package-ecosystem: npm patterns:
directory: "/packages/frontend" - "storybook*"
schedule: - "@storybook/*"
interval: daily
open-pull-requests-limit: 0
- package-ecosystem: npm
directory: "/packages/sw"
schedule:
interval: daily
open-pull-requests-limit: 0

View File

@ -9,12 +9,12 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.3
- run: corepack enable - run: corepack enable
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.8.1
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
cache: 'pnpm' cache: 'pnpm'

View File

@ -10,7 +10,7 @@ jobs:
check_copyright_year: check_copyright_year:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3.2.0 - uses: actions/checkout@v3.5.3
- run: | - run: |
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
echo "Please change copyright year!" echo "Please change copyright year!"

View File

@ -13,10 +13,10 @@ jobs:
if: github.repository == 'misskey-dev/misskey' if: github.repository == 'misskey-dev/misskey'
steps: steps:
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.3
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@v2.3.0 uses: docker/setup-buildx-action@v2.9.1
with: with:
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
- name: Docker meta - name: Docker meta

View File

@ -12,10 +12,10 @@ jobs:
steps: steps:
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.3
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@v2.3.0 uses: docker/setup-buildx-action@v2.9.1
with: with:
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
- name: Docker meta - name: Docker meta

View File

@ -14,7 +14,7 @@ jobs:
env: env:
DOCKER_CONTENT_TRUST: 1 DOCKER_CONTENT_TRUST: 1
steps: steps:
- uses: actions/checkout@v3.2.0 - uses: actions/checkout@v3.5.3
- run: | - run: |
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v0.4.10/dockle_0.4.10_Linux-64bit.deb" curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v0.4.10/dockle_0.4.10_Linux-64bit.deb"
sudo dpkg -i dockle.deb sudo dpkg -i dockle.deb

View File

@ -11,7 +11,7 @@ jobs:
pnpm_install: pnpm_install:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3.3.0 - uses: actions/checkout@v3.5.3
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
@ -19,7 +19,7 @@ jobs:
with: with:
version: 8 version: 8
run_install: false run_install: false
- uses: actions/setup-node@v3.6.0 - uses: actions/setup-node@v3.8.1
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
cache: 'pnpm' cache: 'pnpm'
@ -38,7 +38,7 @@ jobs:
- sw - sw
- misskey-js - misskey-js
steps: steps:
- uses: actions/checkout@v3.3.0 - uses: actions/checkout@v3.5.3
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
@ -46,7 +46,7 @@ jobs:
with: with:
version: 7 version: 7
run_install: false run_install: false
- uses: actions/setup-node@v3.6.0 - uses: actions/setup-node@v3.8.1
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
cache: 'pnpm' cache: 'pnpm'
@ -64,7 +64,7 @@ jobs:
- backend - backend
- misskey-js - misskey-js
steps: steps:
- uses: actions/checkout@v3.3.0 - uses: actions/checkout@v3.5.3
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
@ -72,7 +72,7 @@ jobs:
with: with:
version: 7 version: 7
run_install: false run_install: false
- uses: actions/setup-node@v3.6.0 - uses: actions/setup-node@v3.8.1
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
cache: 'pnpm' cache: 'pnpm'

View File

@ -23,7 +23,7 @@ jobs:
private_key: ${{ secrets.DEPLOYBOT_PRIVATE_KEY }} private_key: ${{ secrets.DEPLOYBOT_PRIVATE_KEY }}
- name: Slash Command Dispatch - name: Slash Command Dispatch
uses: peter-evans/slash-command-dispatch@v1 uses: peter-evans/slash-command-dispatch@v3
env: env:
TOKEN: ${{ steps.generate_token.outputs.token }} TOKEN: ${{ steps.generate_token.outputs.token }}
with: with:

View File

@ -53,7 +53,7 @@ jobs:
# Check out merge commit # Check out merge commit
- name: Fork based /deploy checkout - name: Fork based /deploy checkout
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.3
with: with:
ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge' ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge'

View File

@ -7,7 +7,7 @@ jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v3.5.3
- uses: uesteibar/reviewer-lottery@v2 - uses: uesteibar/reviewer-lottery@v3
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -15,12 +15,12 @@ jobs:
NODE_OPTIONS: "--max_old_space_size=7168" NODE_OPTIONS: "--max_old_space_size=7168"
steps: steps:
- uses: actions/checkout@v3.3.0 - uses: actions/checkout@v3.5.3
if: github.event_name != 'pull_request_target' if: github.event_name != 'pull_request_target'
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- uses: actions/checkout@v3.3.0 - uses: actions/checkout@v3.5.3
if: github.event_name == 'pull_request_target' if: github.event_name == 'pull_request_target'
with: with:
fetch-depth: 0 fetch-depth: 0
@ -38,7 +38,7 @@ jobs:
version: 8 version: 8
run_install: false run_install: false
- name: Use Node.js 20.x - name: Use Node.js 20.x
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.8.1
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
cache: 'pnpm' cache: 'pnpm'

View File

@ -29,7 +29,7 @@ jobs:
- 56312:6379 - 56312:6379
steps: steps:
- uses: actions/checkout@v3.3.0 - uses: actions/checkout@v3.5.3
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Install pnpm
@ -38,7 +38,7 @@ jobs:
version: 8 version: 8
run_install: false run_install: false
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.8.1
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'

View File

@ -16,7 +16,7 @@ jobs:
node-version: [20.x] node-version: [20.x]
steps: steps:
- uses: actions/checkout@v3.3.0 - uses: actions/checkout@v3.5.3
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Install pnpm
@ -25,7 +25,7 @@ jobs:
version: 8 version: 8
run_install: false run_install: false
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.8.1
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
@ -68,7 +68,7 @@ jobs:
- 56312:6379 - 56312:6379
steps: steps:
- uses: actions/checkout@v3.3.0 - uses: actions/checkout@v3.5.3
with: with:
submodules: true submodules: true
# https://github.com/cypress-io/cypress-docker-images/issues/150 # https://github.com/cypress-io/cypress-docker-images/issues/150
@ -83,7 +83,7 @@ jobs:
version: 7 version: 7
run_install: false run_install: false
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.8.1
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'

View File

@ -21,12 +21,12 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.3
- run: corepack enable - run: corepack enable
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.8.1
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'

View File

@ -19,7 +19,7 @@ jobs:
node-version: [20.x] node-version: [20.x]
steps: steps:
- uses: actions/checkout@v3.3.0 - uses: actions/checkout@v3.5.3
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Install pnpm
@ -28,7 +28,7 @@ jobs:
version: 8 version: 8
run_install: false run_install: false
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.8.1
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'

View File

@ -1 +1 @@
20.3.1 20.5.0

View File

@ -12,10 +12,14 @@
--> -->
## 2023.8.0 (unreleased) ## 2023.9.0 (unreleased)
### General ### General
- OAuth 2.0のサポート - OAuth 2.0のサポート
- お知らせ機能の強化
- ユーザー個別のお知らせを作成可能に
- お知らせのバナー表示やダイアログ表示が可能に
- お知らせのアイコンを設定可能に
- チャンネルをセンシティブ指定できるようになりました - チャンネルをセンシティブ指定できるようになりました
### Client ### Client
@ -23,12 +27,27 @@
- 絵文字ピッカーの検索の表示件数を100件に増加 - 絵文字ピッカーの検索の表示件数を100件に増加
- Enhance: ユーザーメニューでスイッチでユーザーリストに追加・削除できるように - Enhance: ユーザーメニューでスイッチでユーザーリストに追加・削除できるように
- Enhance: 自分が押したリアクションのデザインを改善 - Enhance: 自分が押したリアクションのデザインを改善
- Enhance: ノート検索にローカルのみ検索可能なオプションの追加
- Enhance: AiScriptで`LOCALE`として現在の設定言語を取得できるように
- Enhance: Renote自体を通報できるように - Enhance: Renote自体を通報できるように
- Fix: サーバー情報画面(`/instance-info/{domain}`)でブロックができないのを修正 - Fix: サーバー情報画面(`/instance-info/{domain}`)でブロックができないのを修正
- Fix: 未読のお知らせの「わかった」をクリック・タップしてもその場で「わかった」が消えない問題を修正 - Fix: 未読のお知らせの「わかった」をクリック・タップしてもその場で「わかった」が消えない問題を修正
- Fix: iOSで画面を回転させるとテキストサイズが変わる問題を修正
- Fix: word mute for sub note is not applied
- Fix: タイムラインを下にスクロールしてノート画面に移動して再び戻ったら以前のスクロール位置を失う問題を修正
- Fix: Misskeyプラグインをインストールする際のAiScriptバージョンのチェックが0.14.0以降に対応していない問題を修正
- Fix: 他のサーバーのユーザーへ「メッセージを送信」した時の初期テキストのメンションが間違っている問題を修正
- Playの操作を行うAPI TokenをAPIコンソールから発行できるように
### Server ### Server
- Fix: ノート検索 `notes/search` にてhostを指定した際に検索結果に反映されるように
- cacheRemoteFilesの初期値はfalseになりました - cacheRemoteFilesの初期値はfalseになりました
- ファイルアップロード時等にファイル名の拡張子を修正する関数(correctFilename)の挙動を改善
- Webhookのペイロードにサーバーのurlが含まれるようになりました
- Fix: 一部のfeatured noteを照会できない問題を修正
- Fix: muteがapiからのuser list timeline取得で機能しない問題を修正
- Fix: ジョブキュー管理画面の認証を回避できる問題を修正
- Fix: 一部のサーバー内部エラーがスタックトレースを返さないように修正
## 13.14.2 ## 13.14.2
@ -43,6 +62,7 @@
### Server ### Server
- Fix: APIのオフセットが壊れていたせいで「もっと見る」でもっと見れない問題を修正 - Fix: APIのオフセットが壊れていたせいで「もっと見る」でもっと見れない問題を修正
- Fix: 外部サーバーの投稿がタイムラインに表示されないことがある問題を修正 - Fix: 外部サーバーの投稿がタイムラインに表示されないことがある問題を修正
- Enhance: Add address bind config option (outgoingAddress)
## 13.14.1 ## 13.14.1

View File

@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.4 # syntax = docker/dockerfile:1.4
ARG NODE_VERSION=20.3.1-bullseye ARG NODE_VERSION=20.5.0-bullseye
# build assets & compile TypeScript # build assets & compile TypeScript

20
locales/index.d.ts vendored
View File

@ -1099,6 +1099,22 @@ export interface Locale {
"doYouAgree": string; "doYouAgree": string;
"beSureToReadThisAsItIsImportant": string; "beSureToReadThisAsItIsImportant": string;
"iHaveReadXCarefullyAndAgree": string; "iHaveReadXCarefullyAndAgree": string;
"dialog": string;
"icon": string;
"forYou": string;
"currentAnnouncements": string;
"pastAnnouncements": string;
"youHaveUnreadAnnouncements": string;
"_announcement": {
"forExistingUsers": string;
"forExistingUsersDescription": string;
"needConfirmationToRead": string;
"needConfirmationToReadDescription": string;
"end": string;
"tooManyActiveAnnouncementDescription": string;
"readConfirmTitle": string;
"readConfirmText": string;
};
"_initialAccountSetting": { "_initialAccountSetting": {
"accountCreated": string; "accountCreated": string;
"letsStartAccountSetup": string; "letsStartAccountSetup": string;
@ -1847,6 +1863,10 @@ export interface Locale {
"write:gallery": string; "write:gallery": string;
"read:gallery-likes": string; "read:gallery-likes": string;
"write:gallery-likes": string; "write:gallery-likes": string;
"read:flash": string;
"write:flash": string;
"read:flash-likes": string;
"write:flash-likes": string;
}; };
"_auth": { "_auth": {
"shareAccessTitle": string; "shareAccessTitle": string;

View File

@ -74,7 +74,7 @@ import: "インポート"
export: "エクスポート" export: "エクスポート"
files: "ファイル" files: "ファイル"
download: "ダウンロード" download: "ダウンロード"
driveFileDeleteConfirm: "ファイル「{name}」を削除しますか?このファイルを使用した全てのコンテンツからも削除されます。" driveFileDeleteConfirm: "ファイル「{name}」を削除しますか?このファイルを使用した一部のコンテンツも削除されます。"
unfollowConfirm: "{name}のフォローを解除しますか?" unfollowConfirm: "{name}のフォローを解除しますか?"
exportRequested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、「ドライブ」に追加されます。" exportRequested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、「ドライブ」に追加されます。"
importRequested: "インポートをリクエストしました。これには時間がかかる場合があります。" importRequested: "インポートをリクエストしました。これには時間がかかる場合があります。"
@ -330,7 +330,7 @@ watch: "ウォッチ"
unwatch: "ウォッチ解除" unwatch: "ウォッチ解除"
accept: "許可" accept: "許可"
reject: "拒否" reject: "拒否"
normal: "常" normal: "常"
instanceName: "サーバー名" instanceName: "サーバー名"
instanceDescription: "サーバーの紹介" instanceDescription: "サーバーの紹介"
maintainerName: "管理者の名前" maintainerName: "管理者の名前"
@ -1096,6 +1096,22 @@ expired: "期限切れ"
doYouAgree: "同意しますか?" doYouAgree: "同意しますか?"
beSureToReadThisAsItIsImportant: "重要ですので必ずお読みください。" beSureToReadThisAsItIsImportant: "重要ですので必ずお読みください。"
iHaveReadXCarefullyAndAgree: "「{x}」の内容をよく読み、同意します。" iHaveReadXCarefullyAndAgree: "「{x}」の内容をよく読み、同意します。"
dialog: "ダイアログ"
icon: "アイコン"
forYou: "あなたへ"
currentAnnouncements: "現在のお知らせ"
pastAnnouncements: "過去のお知らせ"
youHaveUnreadAnnouncements: "未読のお知らせがあります。"
_announcement:
forExistingUsers: "既存ユーザーのみ"
forExistingUsersDescription: "有効にすると、このお知らせ作成時点で存在するユーザーにのみお知らせが表示されます。無効にすると、このお知らせ作成後にアカウントを作成したユーザーにもお知らせが表示されます。"
needConfirmationToRead: "既読にするのに確認が必要"
needConfirmationToReadDescription: "有効にすると、このお知らせを既読にする際に確認ダイアログが表示されます。また、一括既読操作の対象になりません。"
end: "お知らせを終了"
tooManyActiveAnnouncementDescription: "アクティブなお知らせが多いため、UXが低下する可能性があります。終了したお知らせはアーカイブすることを検討してください。"
readConfirmTitle: "既読にしますか?"
readConfirmText: "「{title}」の内容を読み、既読にします。"
_initialAccountSetting: _initialAccountSetting:
accountCreated: "アカウントの作成が完了しました!" accountCreated: "アカウントの作成が完了しました!"
@ -1765,6 +1781,10 @@ _permissions:
"write:gallery": "ギャラリーを操作する" "write:gallery": "ギャラリーを操作する"
"read:gallery-likes": "ギャラリーのいいねを見る" "read:gallery-likes": "ギャラリーのいいねを見る"
"write:gallery-likes": "ギャラリーのいいねを操作する" "write:gallery-likes": "ギャラリーのいいねを操作する"
"read:flash": "Playを見る"
"write:flash": "Playを操作する"
"read:flash-likes": "Playのいいねを見る"
"write:flash-likes": "Playのいいねを操作する"
_auth: _auth:
shareAccessTitle: "アプリへのアクセス許可" shareAccessTitle: "アプリへのアクセス許可"

View File

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "13.14.2", "version": "2023.9.0-beta.1",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -16,5 +16,9 @@ export class addRenoteMuting1665091090561 {
} }
async down(queryRunner) { async down(queryRunner) {
await queryRunner.query(`DROP INDEX "IDX_renote_muting_muterId"`);
await queryRunner.query(`DROP INDEX "IDX_renote_muting_muteeId"`);
await queryRunner.query(`DROP INDEX "IDX_renote_muting_createdAt"`);
await queryRunner.query(`DROP TABLE "renote_muting"`);
} }
} }

View File

@ -0,0 +1,12 @@
export class FixRenoteMuting1690417561185 {
name = 'FixRenoteMuting1690417561185'
async up(queryRunner) {
await queryRunner.query(`DELETE FROM "renote_muting" WHERE "muteeId" NOT IN (SELECT "id" FROM "user")`);
await queryRunner.query(`DELETE FROM "renote_muting" WHERE "muterId" NOT IN (SELECT "id" FROM "user")`);
}
async down(queryRunner) {
}
}

View File

@ -0,0 +1,27 @@
export class RefineAnnouncement1691649257651 {
name = 'RefineAnnouncement1691649257651'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "announcement" ADD "display" character varying(256) NOT NULL DEFAULT 'normal'`);
await queryRunner.query(`ALTER TABLE "announcement" ADD "needConfirmationToRead" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "announcement" ADD "isActive" boolean NOT NULL DEFAULT true`);
await queryRunner.query(`ALTER TABLE "announcement" ADD "forExistingUsers" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "announcement" ADD "userId" character varying(32)`);
await queryRunner.query(`CREATE INDEX "IDX_bc1afcc8ef7e9400cdc3c0a87e" ON "announcement" ("isActive") `);
await queryRunner.query(`CREATE INDEX "IDX_da795d3a83187e8832005ba19d" ON "announcement" ("forExistingUsers") `);
await queryRunner.query(`CREATE INDEX "IDX_fd25dfe3da37df1715f11ba6ec" ON "announcement" ("userId") `);
await queryRunner.query(`ALTER TABLE "announcement" ADD CONSTRAINT "FK_fd25dfe3da37df1715f11ba6ec8" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "announcement" DROP CONSTRAINT "FK_fd25dfe3da37df1715f11ba6ec8"`);
await queryRunner.query(`DROP INDEX "public"."IDX_fd25dfe3da37df1715f11ba6ec"`);
await queryRunner.query(`DROP INDEX "public"."IDX_da795d3a83187e8832005ba19d"`);
await queryRunner.query(`DROP INDEX "public"."IDX_bc1afcc8ef7e9400cdc3c0a87e"`);
await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "userId"`);
await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "forExistingUsers"`);
await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "isActive"`);
await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "needConfirmationToRead"`);
await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "display"`);
}
}

View File

@ -0,0 +1,11 @@
export class RefineAnnouncement21691657412740 {
name = 'RefineAnnouncement21691657412740'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "announcement" ADD "icon" character varying(256) NOT NULL DEFAULT 'info'`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "icon"`);
}
}

View File

@ -76,6 +76,7 @@ export type Source = {
id: string; id: string;
outgoingAddress?: string;
outgoingAddressFamily?: 'ipv4' | 'ipv6' | 'dual'; outgoingAddressFamily?: 'ipv4' | 'ipv6' | 'dual';
deliverJobConcurrency?: number; deliverJobConcurrency?: number;

View File

@ -8,7 +8,7 @@ import { IsNull, In, MoreThan, Not } from 'typeorm';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js'; import type { MiLocalUser, MiRemoteUser, MiUser } from '@/models/entities/User.js';
import type { BlockingsRepository, FollowingsRepository, InstancesRepository, MutingsRepository, UserListJoiningsRepository, UsersRepository } from '@/models/index.js'; import type { BlockingsRepository, FollowingsRepository, InstancesRepository, MutingsRepository, UserListJoiningsRepository, UsersRepository } from '@/models/index.js';
import type { RelationshipJobData, ThinUser } from '@/queue/types.js'; import type { RelationshipJobData, ThinUser } from '@/queue/types.js';
@ -71,12 +71,12 @@ export class AccountMoveService {
* After delivering Move activity, its local followers unfollow the old account and then follow the new one. * After delivering Move activity, its local followers unfollow the old account and then follow the new one.
*/ */
@bindThis @bindThis
public async moveFromLocal(src: LocalUser, dst: LocalUser | RemoteUser): Promise<unknown> { public async moveFromLocal(src: MiLocalUser, dst: MiLocalUser | MiRemoteUser): Promise<unknown> {
const srcUri = this.userEntityService.getUserUri(src); const srcUri = this.userEntityService.getUserUri(src);
const dstUri = this.userEntityService.getUserUri(dst); const dstUri = this.userEntityService.getUserUri(dst);
// add movedToUri to indicate that the user has moved // add movedToUri to indicate that the user has moved
const update = {} as Partial<LocalUser>; const update = {} as Partial<MiLocalUser>;
update.alsoKnownAs = src.alsoKnownAs?.includes(dstUri) ? src.alsoKnownAs : src.alsoKnownAs?.concat([dstUri]) ?? [dstUri]; update.alsoKnownAs = src.alsoKnownAs?.includes(dstUri) ? src.alsoKnownAs : src.alsoKnownAs?.concat([dstUri]) ?? [dstUri];
update.movedToUri = dstUri; update.movedToUri = dstUri;
update.movedAt = new Date(); update.movedAt = new Date();
@ -114,7 +114,7 @@ export class AccountMoveService {
} }
@bindThis @bindThis
public async postMoveProcess(src: User, dst: User): Promise<void> { public async postMoveProcess(src: MiUser, dst: MiUser): Promise<void> {
// Copy blockings and mutings, and update lists // Copy blockings and mutings, and update lists
try { try {
await Promise.all([ await Promise.all([
@ -213,7 +213,7 @@ export class AccountMoveService {
* @returns Promise<void> * @returns Promise<void>
*/ */
@bindThis @bindThis
public async updateLists(src: ThinUser, dst: User): Promise<void> { public async updateLists(src: ThinUser, dst: MiUser): Promise<void> {
// Return if there is no list to be updated. // Return if there is no list to be updated.
const oldJoinings = await this.userListJoiningsRepository.find({ const oldJoinings = await this.userListJoiningsRepository.find({
where: { where: {
@ -260,7 +260,7 @@ export class AccountMoveService {
} }
@bindThis @bindThis
private async adjustFollowingCounts(localFollowerIds: string[], oldAccount: User): Promise<void> { private async adjustFollowingCounts(localFollowerIds: string[], oldAccount: MiUser): Promise<void> {
if (localFollowerIds.length === 0) return; if (localFollowerIds.length === 0) return;
// Set the old account's following and followers counts to 0. // Set the old account's following and followers counts to 0.
@ -301,11 +301,11 @@ export class AccountMoveService {
*/ */
@bindThis @bindThis
public async validateAlsoKnownAs( public async validateAlsoKnownAs(
dst: LocalUser | RemoteUser, dst: MiLocalUser | MiRemoteUser,
check: (oldUser: LocalUser | RemoteUser | null, newUser: LocalUser | RemoteUser) => boolean | Promise<boolean> = () => true, check: (oldUser: MiLocalUser | MiRemoteUser | null, newUser: MiLocalUser | MiRemoteUser) => boolean | Promise<boolean> = () => true,
instant = false, instant = false,
): Promise<LocalUser | RemoteUser | null> { ): Promise<MiLocalUser | MiRemoteUser | null> {
let resultUser: LocalUser | RemoteUser | null = null; let resultUser: MiLocalUser | MiRemoteUser | null = null;
if (this.userEntityService.isRemoteUser(dst)) { if (this.userEntityService.isRemoteUser(dst)) {
if ((new Date()).getTime() - (dst.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) { if ((new Date()).getTime() - (dst.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {

View File

@ -6,7 +6,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { UsersRepository } from '@/models/index.js'; import type { UsersRepository } from '@/models/index.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { RelayService } from '@/core/RelayService.js'; import { RelayService } from '@/core/RelayService.js';
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js'; import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
@ -27,7 +27,7 @@ export class AccountUpdateService {
} }
@bindThis @bindThis
public async publishToFollowers(userId: User['id']) { public async publishToFollowers(userId: MiUser['id']) {
const user = await this.usersRepository.findOneBy({ id: userId }); const user = await this.usersRepository.findOneBy({ id: userId });
if (user == null) throw new Error('user not found'); if (user == null) throw new Error('user not found');

View File

@ -5,7 +5,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import type { UserProfilesRepository } from '@/models/index.js'; import type { UserProfilesRepository } from '@/models/index.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { NotificationService } from '@/core/NotificationService.js'; import { NotificationService } from '@/core/NotificationService.js';
@ -99,7 +99,7 @@ export class AchievementService {
@bindThis @bindThis
public async create( public async create(
userId: User['id'], userId: MiUser['id'],
type: typeof ACHIEVEMENT_TYPES[number], type: typeof ACHIEVEMENT_TYPES[number],
): Promise<void> { ): Promise<void> {
if (!ACHIEVEMENT_TYPES.includes(type)) return; if (!ACHIEVEMENT_TYPES.includes(type)) return;

View File

@ -0,0 +1,135 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Brackets } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { MiUser } from '@/models/entities/User.js';
import type { AnnouncementReadsRepository, AnnouncementsRepository, MiAnnouncement, MiAnnouncementRead } from '@/models/index.js';
import { bindThis } from '@/decorators.js';
import { Packed } from '@/misc/json-schema.js';
import { IdService } from '@/core/IdService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
@Injectable()
export class AnnouncementService {
constructor(
@Inject(DI.announcementsRepository)
private announcementsRepository: AnnouncementsRepository,
@Inject(DI.announcementReadsRepository)
private announcementReadsRepository: AnnouncementReadsRepository,
private idService: IdService,
private globalEventService: GlobalEventService,
) {
}
@bindThis
public async getReads(userId: MiUser['id']): Promise<MiAnnouncementRead[]> {
return this.announcementReadsRepository.findBy({
userId: userId,
});
}
@bindThis
public async getUnreadAnnouncements(user: MiUser): Promise<MiAnnouncement[]> {
const readsQuery = this.announcementReadsRepository.createQueryBuilder('read')
.select('read.announcementId')
.where('read.userId = :userId', { userId: user.id });
const q = this.announcementsRepository.createQueryBuilder('announcement')
.where('announcement.isActive = true')
.andWhere(new Brackets(qb => {
qb.orWhere('announcement.userId = :userId', { userId: user.id });
qb.orWhere('announcement.userId IS NULL');
}))
.andWhere(new Brackets(qb => {
qb.orWhere('announcement.forExistingUsers = false');
qb.orWhere('announcement.createdAt > :createdAt', { createdAt: user.createdAt });
}))
.andWhere(`announcement.id NOT IN (${ readsQuery.getQuery() })`);
q.setParameters(readsQuery.getParameters());
return q.getMany();
}
@bindThis
public async create(values: Partial<MiAnnouncement>): Promise<{ raw: MiAnnouncement; packed: Packed<'Announcement'> }> {
const announcement = await this.announcementsRepository.insert({
id: this.idService.genId(),
createdAt: new Date(),
updatedAt: null,
title: values.title,
text: values.text,
imageUrl: values.imageUrl,
icon: values.icon,
display: values.display,
forExistingUsers: values.forExistingUsers,
needConfirmationToRead: values.needConfirmationToRead,
userId: values.userId,
}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0]));
const packed = (await this.packMany([announcement]))[0];
if (values.userId) {
this.globalEventService.publishMainStream(values.userId, 'announcementCreated', {
announcement: packed,
});
} else {
this.globalEventService.publishBroadcastStream('announcementCreated', {
announcement: packed,
});
}
return {
raw: announcement,
packed: packed,
};
}
@bindThis
public async read(user: MiUser, announcementId: MiAnnouncement['id']): Promise<void> {
try {
await this.announcementReadsRepository.insert({
id: this.idService.genId(),
createdAt: new Date(),
announcementId: announcementId,
userId: user.id,
});
} catch (e) {
return;
}
if ((await this.getUnreadAnnouncements(user)).length === 0) {
this.globalEventService.publishMainStream(user.id, 'readAllAnnouncements');
}
}
@bindThis
public async packMany(
announcements: MiAnnouncement[],
me?: { id: MiUser['id'] } | null | undefined,
options?: {
reads?: MiAnnouncementRead[];
},
): Promise<Packed<'Announcement'>[]> {
const reads = me ? (options?.reads ?? await this.getReads(me.id)) : [];
return announcements.map(announcement => ({
id: announcement.id,
createdAt: announcement.createdAt.toISOString(),
updatedAt: announcement.updatedAt?.toISOString() ?? null,
text: announcement.text,
title: announcement.title,
imageUrl: announcement.imageUrl,
icon: announcement.icon,
display: announcement.display,
needConfirmationToRead: announcement.needConfirmationToRead,
forYou: announcement.userId === me?.id,
isRead: reads.some(read => read.announcementId === announcement.id),
}));
}
}

View File

@ -5,9 +5,9 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import type { Antenna } from '@/models/entities/Antenna.js'; import type { MiAntenna } from '@/models/entities/Antenna.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import * as Acct from '@/misc/acct.js'; import * as Acct from '@/misc/acct.js';
import type { Packed } from '@/misc/json-schema.js'; import type { Packed } from '@/misc/json-schema.js';
@ -21,7 +21,7 @@ import type { OnApplicationShutdown } from '@nestjs/common';
@Injectable() @Injectable()
export class AntennaService implements OnApplicationShutdown { export class AntennaService implements OnApplicationShutdown {
private antennasFetched: boolean; private antennasFetched: boolean;
private antennas: Antenna[]; private antennas: MiAntenna[];
constructor( constructor(
@Inject(DI.redis) @Inject(DI.redis)
@ -76,7 +76,7 @@ export class AntennaService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async addNoteToAntennas(note: Note, noteUser: { id: User['id']; username: string; host: string | null; }): Promise<void> { public async addNoteToAntennas(note: MiNote, noteUser: { id: MiUser['id']; username: string; host: string | null; }): Promise<void> {
const antennas = await this.getAntennas(); const antennas = await this.getAntennas();
const antennasWithMatchResult = await Promise.all(antennas.map(antenna => this.checkHitAntenna(antenna, note, noteUser).then(hit => [antenna, hit] as const))); const antennasWithMatchResult = await Promise.all(antennas.map(antenna => this.checkHitAntenna(antenna, note, noteUser).then(hit => [antenna, hit] as const)));
const matchedAntennas = antennasWithMatchResult.filter(([, hit]) => hit).map(([antenna]) => antenna); const matchedAntennas = antennasWithMatchResult.filter(([, hit]) => hit).map(([antenna]) => antenna);
@ -99,7 +99,7 @@ export class AntennaService implements OnApplicationShutdown {
// NOTE: フォローしているユーザーのノート、リストのユーザーのノート、グループのユーザーのノート指定はパフォーマンス上の理由で無効になっている // NOTE: フォローしているユーザーのノート、リストのユーザーのノート、グループのユーザーのノート指定はパフォーマンス上の理由で無効になっている
@bindThis @bindThis
public async checkHitAntenna(antenna: Antenna, note: (Note | Packed<'Note'>), noteUser: { id: User['id']; username: string; host: string | null; }): Promise<boolean> { public async checkHitAntenna(antenna: MiAntenna, note: (MiNote | Packed<'Note'>), noteUser: { id: MiUser['id']; username: string; host: string | null; }): Promise<boolean> {
if (note.visibility === 'specified') return false; if (note.visibility === 'specified') return false;
if (note.visibility === 'followers') return false; if (note.visibility === 'followers') return false;

View File

@ -5,9 +5,9 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import type { BlockingsRepository, ChannelFollowingsRepository, FollowingsRepository, MutingsRepository, RenoteMutingsRepository, UserProfile, UserProfilesRepository, UsersRepository } from '@/models/index.js'; import type { BlockingsRepository, ChannelFollowingsRepository, FollowingsRepository, MutingsRepository, RenoteMutingsRepository, MiUserProfile, UserProfilesRepository, UsersRepository } from '@/models/index.js';
import { MemoryKVCache, RedisKVCache } from '@/misc/cache.js'; import { MemoryKVCache, RedisKVCache } from '@/misc/cache.js';
import type { LocalUser, User } from '@/models/entities/User.js'; import type { MiLocalUser, MiUser } from '@/models/entities/User.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -16,11 +16,11 @@ import type { OnApplicationShutdown } from '@nestjs/common';
@Injectable() @Injectable()
export class CacheService implements OnApplicationShutdown { export class CacheService implements OnApplicationShutdown {
public userByIdCache: MemoryKVCache<User, User | string>; public userByIdCache: MemoryKVCache<MiUser, MiUser | string>;
public localUserByNativeTokenCache: MemoryKVCache<LocalUser | null, string | null>; public localUserByNativeTokenCache: MemoryKVCache<MiLocalUser | null, string | null>;
public localUserByIdCache: MemoryKVCache<LocalUser>; public localUserByIdCache: MemoryKVCache<MiLocalUser>;
public uriPersonCache: MemoryKVCache<User | null, string | null>; public uriPersonCache: MemoryKVCache<MiUser | null, string | null>;
public userProfileCache: RedisKVCache<UserProfile>; public userProfileCache: RedisKVCache<MiUserProfile>;
public userMutingsCache: RedisKVCache<Set<string>>; public userMutingsCache: RedisKVCache<Set<string>>;
public userBlockingCache: RedisKVCache<Set<string>>; public userBlockingCache: RedisKVCache<Set<string>>;
public userBlockedCache: RedisKVCache<Set<string>>; // NOTE: 「被」Blockキャッシュ public userBlockedCache: RedisKVCache<Set<string>>; // NOTE: 「被」Blockキャッシュ
@ -60,14 +60,14 @@ export class CacheService implements OnApplicationShutdown {
) { ) {
//this.onMessage = this.onMessage.bind(this); //this.onMessage = this.onMessage.bind(this);
const localUserByIdCache = new MemoryKVCache<LocalUser>(1000 * 60 * 60 * 6 /* 6h */); const localUserByIdCache = new MemoryKVCache<MiLocalUser>(1000 * 60 * 60 * 6 /* 6h */);
this.localUserByIdCache = localUserByIdCache; this.localUserByIdCache = localUserByIdCache;
// ローカルユーザーならlocalUserByIdCacheにデータを追加し、こちらにはid(文字列)だけを追加する // ローカルユーザーならlocalUserByIdCacheにデータを追加し、こちらにはid(文字列)だけを追加する
const userByIdCache = new MemoryKVCache<User, User | string>(1000 * 60 * 60 * 6 /* 6h */, { const userByIdCache = new MemoryKVCache<MiUser, MiUser | string>(1000 * 60 * 60 * 6 /* 6h */, {
toMapConverter: user => { toMapConverter: user => {
if (user.host === null) { if (user.host === null) {
localUserByIdCache.set(user.id, user as LocalUser); localUserByIdCache.set(user.id, user as MiLocalUser);
return user.id; return user.id;
} }
@ -77,7 +77,7 @@ export class CacheService implements OnApplicationShutdown {
}); });
this.userByIdCache = userByIdCache; this.userByIdCache = userByIdCache;
this.localUserByNativeTokenCache = new MemoryKVCache<LocalUser | null, string | null>(Infinity, { this.localUserByNativeTokenCache = new MemoryKVCache<MiLocalUser | null, string | null>(Infinity, {
toMapConverter: user => { toMapConverter: user => {
if (user === null) return null; if (user === null) return null;
@ -86,7 +86,7 @@ export class CacheService implements OnApplicationShutdown {
}, },
fromMapConverter: id => id === null ? null : localUserByIdCache.get(id), fromMapConverter: id => id === null ? null : localUserByIdCache.get(id),
}); });
this.uriPersonCache = new MemoryKVCache<User | null, string | null>(Infinity, { this.uriPersonCache = new MemoryKVCache<MiUser | null, string | null>(Infinity, {
toMapConverter: user => { toMapConverter: user => {
if (user === null) return null; if (user === null) return null;
@ -96,7 +96,7 @@ export class CacheService implements OnApplicationShutdown {
fromMapConverter: id => id === null ? null : userByIdCache.get(id), fromMapConverter: id => id === null ? null : userByIdCache.get(id),
}); });
this.userProfileCache = new RedisKVCache<UserProfile>(this.redisClient, 'userProfile', { this.userProfileCache = new RedisKVCache<MiUserProfile>(this.redisClient, 'userProfile', {
lifetime: 1000 * 60 * 30, // 30m lifetime: 1000 * 60 * 30, // 30m
memoryCacheLifetime: 1000 * 60, // 1m memoryCacheLifetime: 1000 * 60, // 1m
fetcher: (key) => this.userProfilesRepository.findOneByOrFail({ userId: key }), fetcher: (key) => this.userProfilesRepository.findOneByOrFail({ userId: key }),
@ -178,7 +178,7 @@ export class CacheService implements OnApplicationShutdown {
break; break;
} }
case 'userTokenRegenerated': { case 'userTokenRegenerated': {
const user = await this.usersRepository.findOneByOrFail({ id: body.id }) as LocalUser; const user = await this.usersRepository.findOneByOrFail({ id: body.id }) as MiLocalUser;
this.localUserByNativeTokenCache.delete(body.oldToken); this.localUserByNativeTokenCache.delete(body.oldToken);
this.localUserByNativeTokenCache.set(body.newToken, user); this.localUserByNativeTokenCache.set(body.newToken, user);
break; break;
@ -197,7 +197,7 @@ export class CacheService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public findUserById(userId: User['id']) { public findUserById(userId: MiUser['id']) {
return this.userByIdCache.fetch(userId, () => this.usersRepository.findOneByOrFail({ id: userId })); return this.userByIdCache.fetch(userId, () => this.usersRepository.findOneByOrFail({ id: userId }));
} }

View File

@ -7,6 +7,7 @@ import { Module } from '@nestjs/common';
import { AccountMoveService } from './AccountMoveService.js'; import { AccountMoveService } from './AccountMoveService.js';
import { AccountUpdateService } from './AccountUpdateService.js'; import { AccountUpdateService } from './AccountUpdateService.js';
import { AiService } from './AiService.js'; import { AiService } from './AiService.js';
import { AnnouncementService } from './AnnouncementService.js';
import { AntennaService } from './AntennaService.js'; import { AntennaService } from './AntennaService.js';
import { AppLockService } from './AppLockService.js'; import { AppLockService } from './AppLockService.js';
import { AchievementService } from './AchievementService.js'; import { AchievementService } from './AchievementService.js';
@ -130,6 +131,7 @@ const $LoggerService: Provider = { provide: 'LoggerService', useExisting: Logger
const $AccountMoveService: Provider = { provide: 'AccountMoveService', useExisting: AccountMoveService }; const $AccountMoveService: Provider = { provide: 'AccountMoveService', useExisting: AccountMoveService };
const $AccountUpdateService: Provider = { provide: 'AccountUpdateService', useExisting: AccountUpdateService }; const $AccountUpdateService: Provider = { provide: 'AccountUpdateService', useExisting: AccountUpdateService };
const $AiService: Provider = { provide: 'AiService', useExisting: AiService }; const $AiService: Provider = { provide: 'AiService', useExisting: AiService };
const $AnnouncementService: Provider = { provide: 'AnnouncementService', useExisting: AnnouncementService };
const $AntennaService: Provider = { provide: 'AntennaService', useExisting: AntennaService }; const $AntennaService: Provider = { provide: 'AntennaService', useExisting: AntennaService };
const $AppLockService: Provider = { provide: 'AppLockService', useExisting: AppLockService }; const $AppLockService: Provider = { provide: 'AppLockService', useExisting: AppLockService };
const $AchievementService: Provider = { provide: 'AchievementService', useExisting: AchievementService }; const $AchievementService: Provider = { provide: 'AchievementService', useExisting: AchievementService };
@ -257,6 +259,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
AccountMoveService, AccountMoveService,
AccountUpdateService, AccountUpdateService,
AiService, AiService,
AnnouncementService,
AntennaService, AntennaService,
AppLockService, AppLockService,
AchievementService, AchievementService,
@ -377,6 +380,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$AccountMoveService, $AccountMoveService,
$AccountUpdateService, $AccountUpdateService,
$AiService, $AiService,
$AnnouncementService,
$AntennaService, $AntennaService,
$AppLockService, $AppLockService,
$AchievementService, $AchievementService,
@ -498,6 +502,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
AccountMoveService, AccountMoveService,
AccountUpdateService, AccountUpdateService,
AiService, AiService,
AnnouncementService,
AntennaService, AntennaService,
AppLockService, AppLockService,
AchievementService, AchievementService,
@ -617,6 +622,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$AccountMoveService, $AccountMoveService,
$AccountUpdateService, $AccountUpdateService,
$AiService, $AiService,
$AnnouncementService,
$AntennaService, $AntennaService,
$AppLockService, $AppLockService,
$AchievementService, $AchievementService,

View File

@ -8,11 +8,11 @@ import { Inject, Injectable } from '@nestjs/common';
import bcrypt from 'bcryptjs'; import bcrypt from 'bcryptjs';
import { IsNull, DataSource } from 'typeorm'; import { IsNull, DataSource } from 'typeorm';
import { genRsaKeyPair } from '@/misc/gen-key-pair.js'; import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
import { User } from '@/models/entities/User.js'; import { MiUser } from '@/models/entities/User.js';
import { UserProfile } from '@/models/entities/UserProfile.js'; import { MiUserProfile } from '@/models/entities/UserProfile.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { UserKeypair } from '@/models/entities/UserKeypair.js'; import { MiUserKeypair } from '@/models/entities/UserKeypair.js';
import { UsedUsername } from '@/models/entities/UsedUsername.js'; import { MiUsedUsername } from '@/models/entities/UsedUsername.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import generateNativeUserToken from '@/misc/generate-native-user-token.js'; import generateNativeUserToken from '@/misc/generate-native-user-token.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -28,7 +28,7 @@ export class CreateSystemUserService {
} }
@bindThis @bindThis
public async createSystemUser(username: string): Promise<User> { public async createSystemUser(username: string): Promise<MiUser> {
const password = randomUUID(); const password = randomUUID();
// Generate hash of password // Generate hash of password
@ -40,18 +40,18 @@ export class CreateSystemUserService {
const keyPair = await genRsaKeyPair(); const keyPair = await genRsaKeyPair();
let account!: User; let account!: MiUser;
// Start transaction // Start transaction
await this.db.transaction(async transactionalEntityManager => { await this.db.transaction(async transactionalEntityManager => {
const exist = await transactionalEntityManager.findOneBy(User, { const exist = await transactionalEntityManager.findOneBy(MiUser, {
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
host: IsNull(), host: IsNull(),
}); });
if (exist) throw new Error('the user is already exists'); if (exist) throw new Error('the user is already exists');
account = await transactionalEntityManager.insert(User, { account = await transactionalEntityManager.insert(MiUser, {
id: this.idService.genId(), id: this.idService.genId(),
createdAt: new Date(), createdAt: new Date(),
username: username, username: username,
@ -62,21 +62,21 @@ export class CreateSystemUserService {
isLocked: true, isLocked: true,
isExplorable: false, isExplorable: false,
isBot: true, isBot: true,
}).then(x => transactionalEntityManager.findOneByOrFail(User, x.identifiers[0])); }).then(x => transactionalEntityManager.findOneByOrFail(MiUser, x.identifiers[0]));
await transactionalEntityManager.insert(UserKeypair, { await transactionalEntityManager.insert(MiUserKeypair, {
publicKey: keyPair.publicKey, publicKey: keyPair.publicKey,
privateKey: keyPair.privateKey, privateKey: keyPair.privateKey,
userId: account.id, userId: account.id,
}); });
await transactionalEntityManager.insert(UserProfile, { await transactionalEntityManager.insert(MiUserProfile, {
userId: account.id, userId: account.id,
autoAcceptFollowed: false, autoAcceptFollowed: false,
password: hash, password: hash,
}); });
await transactionalEntityManager.insert(UsedUsername, { await transactionalEntityManager.insert(MiUsedUsername, {
createdAt: new Date(), createdAt: new Date(),
username: username.toLowerCase(), username: username.toLowerCase(),
}); });

View File

@ -10,9 +10,9 @@ import { DI } from '@/di-symbols.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MiDriveFile } from '@/models/entities/DriveFile.js';
import type { Emoji } from '@/models/entities/Emoji.js'; import type { MiEmoji } from '@/models/entities/Emoji.js';
import type { EmojisRepository, Role } from '@/models/index.js'; import type { EmojisRepository, MiRole } from '@/models/index.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { MemoryKVCache, RedisSingleCache } from '@/misc/cache.js'; import { MemoryKVCache, RedisSingleCache } from '@/misc/cache.js';
import { UtilityService } from '@/core/UtilityService.js'; import { UtilityService } from '@/core/UtilityService.js';
@ -23,8 +23,8 @@ const parseEmojiStrRegexp = /^(\w+)(?:@([\w.-]+))?$/;
@Injectable() @Injectable()
export class CustomEmojiService implements OnApplicationShutdown { export class CustomEmojiService implements OnApplicationShutdown {
private cache: MemoryKVCache<Emoji | null>; private cache: MemoryKVCache<MiEmoji | null>;
public localEmojisCache: RedisSingleCache<Map<string, Emoji>>; public localEmojisCache: RedisSingleCache<Map<string, MiEmoji>>;
constructor( constructor(
@Inject(DI.redis) @Inject(DI.redis)
@ -38,16 +38,16 @@ export class CustomEmojiService implements OnApplicationShutdown {
private emojiEntityService: EmojiEntityService, private emojiEntityService: EmojiEntityService,
private globalEventService: GlobalEventService, private globalEventService: GlobalEventService,
) { ) {
this.cache = new MemoryKVCache<Emoji | null>(1000 * 60 * 60 * 12); this.cache = new MemoryKVCache<MiEmoji | null>(1000 * 60 * 60 * 12);
this.localEmojisCache = new RedisSingleCache<Map<string, Emoji>>(this.redisClient, 'localEmojis', { this.localEmojisCache = new RedisSingleCache<Map<string, MiEmoji>>(this.redisClient, 'localEmojis', {
lifetime: 1000 * 60 * 30, // 30m lifetime: 1000 * 60 * 30, // 30m
memoryCacheLifetime: 1000 * 60 * 3, // 3m memoryCacheLifetime: 1000 * 60 * 3, // 3m
fetcher: () => this.emojisRepository.find({ where: { host: IsNull() } }).then(emojis => new Map(emojis.map(emoji => [emoji.name, emoji]))), fetcher: () => this.emojisRepository.find({ where: { host: IsNull() } }).then(emojis => new Map(emojis.map(emoji => [emoji.name, emoji]))),
toRedisConverter: (value) => JSON.stringify(Array.from(value.values())), toRedisConverter: (value) => JSON.stringify(Array.from(value.values())),
fromRedisConverter: (value) => { fromRedisConverter: (value) => {
if (!Array.isArray(JSON.parse(value))) return undefined; // 古いバージョンの壊れたキャッシュが残っていることがある(そのうち消す) if (!Array.isArray(JSON.parse(value))) return undefined; // 古いバージョンの壊れたキャッシュが残っていることがある(そのうち消す)
return new Map(JSON.parse(value).map((x: Serialized<Emoji>) => [x.name, { return new Map(JSON.parse(value).map((x: Serialized<MiEmoji>) => [x.name, {
...x, ...x,
updatedAt: x.updatedAt ? new Date(x.updatedAt) : null, updatedAt: x.updatedAt ? new Date(x.updatedAt) : null,
}])); }]));
@ -57,7 +57,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
@bindThis @bindThis
public async add(data: { public async add(data: {
driveFile: DriveFile; driveFile: MiDriveFile;
name: string; name: string;
category: string | null; category: string | null;
aliases: string[]; aliases: string[];
@ -65,8 +65,8 @@ export class CustomEmojiService implements OnApplicationShutdown {
license: string | null; license: string | null;
isSensitive: boolean; isSensitive: boolean;
localOnly: boolean; localOnly: boolean;
roleIdsThatCanBeUsedThisEmojiAsReaction: Role['id'][]; roleIdsThatCanBeUsedThisEmojiAsReaction: MiRole['id'][];
}): Promise<Emoji> { }): Promise<MiEmoji> {
const emoji = await this.emojisRepository.insert({ const emoji = await this.emojisRepository.insert({
id: this.idService.genId(), id: this.idService.genId(),
updatedAt: new Date(), updatedAt: new Date(),
@ -95,15 +95,15 @@ export class CustomEmojiService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async update(id: Emoji['id'], data: { public async update(id: MiEmoji['id'], data: {
driveFile?: DriveFile; driveFile?: MiDriveFile;
name?: string; name?: string;
category?: string | null; category?: string | null;
aliases?: string[]; aliases?: string[];
license?: string | null; license?: string | null;
isSensitive?: boolean; isSensitive?: boolean;
localOnly?: boolean; localOnly?: boolean;
roleIdsThatCanBeUsedThisEmojiAsReaction?: Role['id'][]; roleIdsThatCanBeUsedThisEmojiAsReaction?: MiRole['id'][];
}): Promise<void> { }): Promise<void> {
const emoji = await this.emojisRepository.findOneByOrFail({ id: id }); const emoji = await this.emojisRepository.findOneByOrFail({ id: id });
const sameNameEmoji = await this.emojisRepository.findOneBy({ name: data.name, host: IsNull() }); const sameNameEmoji = await this.emojisRepository.findOneBy({ name: data.name, host: IsNull() });
@ -143,7 +143,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async addAliasesBulk(ids: Emoji['id'][], aliases: string[]) { public async addAliasesBulk(ids: MiEmoji['id'][], aliases: string[]) {
const emojis = await this.emojisRepository.findBy({ const emojis = await this.emojisRepository.findBy({
id: In(ids), id: In(ids),
}); });
@ -163,7 +163,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async setAliasesBulk(ids: Emoji['id'][], aliases: string[]) { public async setAliasesBulk(ids: MiEmoji['id'][], aliases: string[]) {
await this.emojisRepository.update({ await this.emojisRepository.update({
id: In(ids), id: In(ids),
}, { }, {
@ -179,7 +179,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async removeAliasesBulk(ids: Emoji['id'][], aliases: string[]) { public async removeAliasesBulk(ids: MiEmoji['id'][], aliases: string[]) {
const emojis = await this.emojisRepository.findBy({ const emojis = await this.emojisRepository.findBy({
id: In(ids), id: In(ids),
}); });
@ -199,7 +199,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async setCategoryBulk(ids: Emoji['id'][], category: string | null) { public async setCategoryBulk(ids: MiEmoji['id'][], category: string | null) {
await this.emojisRepository.update({ await this.emojisRepository.update({
id: In(ids), id: In(ids),
}, { }, {
@ -215,7 +215,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async setLicenseBulk(ids: Emoji['id'][], license: string | null) { public async setLicenseBulk(ids: MiEmoji['id'][], license: string | null) {
await this.emojisRepository.update({ await this.emojisRepository.update({
id: In(ids), id: In(ids),
}, { }, {
@ -231,7 +231,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async delete(id: Emoji['id']) { public async delete(id: MiEmoji['id']) {
const emoji = await this.emojisRepository.findOneByOrFail({ id: id }); const emoji = await this.emojisRepository.findOneByOrFail({ id: id });
await this.emojisRepository.delete(emoji.id); await this.emojisRepository.delete(emoji.id);
@ -244,7 +244,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async deleteBulk(ids: Emoji['id'][]) { public async deleteBulk(ids: MiEmoji['id'][]) {
const emojis = await this.emojisRepository.findBy({ const emojis = await this.emojisRepository.findBy({
id: In(ids), id: In(ids),
}); });

View File

@ -14,9 +14,9 @@ import { DI } from '@/di-symbols.js';
import type { DriveFilesRepository, UsersRepository, DriveFoldersRepository, UserProfilesRepository } from '@/models/index.js'; import type { DriveFilesRepository, UsersRepository, DriveFoldersRepository, UserProfilesRepository } from '@/models/index.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import Logger from '@/logger.js'; import Logger from '@/logger.js';
import type { RemoteUser, User } from '@/models/entities/User.js'; import type { MiRemoteUser, MiUser } from '@/models/entities/User.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { DriveFile } from '@/models/entities/DriveFile.js'; import { MiDriveFile } from '@/models/entities/DriveFile.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; import { FILE_TYPE_BROWSERSAFE } from '@/const.js';
@ -27,7 +27,7 @@ import { VideoProcessingService } from '@/core/VideoProcessingService.js';
import { ImageProcessingService } from '@/core/ImageProcessingService.js'; import { ImageProcessingService } from '@/core/ImageProcessingService.js';
import type { IImage } from '@/core/ImageProcessingService.js'; import type { IImage } from '@/core/ImageProcessingService.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
import type { DriveFolder } from '@/models/entities/DriveFolder.js'; import type { MiDriveFolder } from '@/models/entities/DriveFolder.js';
import { createTemp } from '@/misc/create-temp.js'; import { createTemp } from '@/misc/create-temp.js';
import DriveChart from '@/core/chart/charts/drive.js'; import DriveChart from '@/core/chart/charts/drive.js';
import PerUserDriveChart from '@/core/chart/charts/per-user-drive.js'; import PerUserDriveChart from '@/core/chart/charts/per-user-drive.js';
@ -45,7 +45,7 @@ import { isMimeImage } from '@/misc/is-mime-image.js';
type AddFileArgs = { type AddFileArgs = {
/** User who wish to add file */ /** User who wish to add file */
user: { id: User['id']; host: User['host'] } | null; user: { id: MiUser['id']; host: MiUser['host'] } | null;
/** File path */ /** File path */
path: string; path: string;
/** Name */ /** Name */
@ -73,8 +73,8 @@ type AddFileArgs = {
type UploadFromUrlArgs = { type UploadFromUrlArgs = {
url: string; url: string;
user: { id: User['id']; host: User['host'] } | null; user: { id: MiUser['id']; host: MiUser['host'] } | null;
folderId?: DriveFolder['id'] | null; folderId?: MiDriveFolder['id'] | null;
uri?: string | null; uri?: string | null;
sensitive?: boolean; sensitive?: boolean;
force?: boolean; force?: boolean;
@ -138,7 +138,7 @@ export class DriveService {
* @param size Size for original * @param size Size for original
*/ */
@bindThis @bindThis
private async save(file: DriveFile, path: string, name: string, type: string, hash: string, size: number): Promise<DriveFile> { private async save(file: MiDriveFile, path: string, name: string, type: string, hash: string, size: number): Promise<MiDriveFile> {
// thunbnail, webpublic を必要なら生成 // thunbnail, webpublic を必要なら生成
const alts = await this.generateAlts(path, type, !file.uri); const alts = await this.generateAlts(path, type, !file.uri);
@ -405,7 +405,7 @@ export class DriveService {
// Expire oldest file (without avatar or banner) of remote user // Expire oldest file (without avatar or banner) of remote user
@bindThis @bindThis
private async expireOldFile(user: RemoteUser, driveCapacity: number) { private async expireOldFile(user: MiRemoteUser, driveCapacity: number) {
const q = this.driveFilesRepository.createQueryBuilder('file') const q = this.driveFilesRepository.createQueryBuilder('file')
.where('file.userId = :userId', { userId: user.id }) .where('file.userId = :userId', { userId: user.id })
.andWhere('file.isLink = FALSE'); .andWhere('file.isLink = FALSE');
@ -451,7 +451,7 @@ export class DriveService {
requestIp = null, requestIp = null,
requestHeaders = null, requestHeaders = null,
ext = null, ext = null,
}: AddFileArgs): Promise<DriveFile> { }: AddFileArgs): Promise<MiDriveFile> {
let skipNsfwCheck = false; let skipNsfwCheck = false;
const instance = await this.metaService.fetch(); const instance = await this.metaService.fetch();
const userRoleNSFW = user && (await this.roleService.getUserPolicies(user.id)).alwaysMarkNsfw; const userRoleNSFW = user && (await this.roleService.getUserPolicies(user.id)).alwaysMarkNsfw;
@ -520,7 +520,7 @@ export class DriveService {
if (isLocalUser) { if (isLocalUser) {
throw new IdentifiableError('c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6', 'No free space.'); throw new IdentifiableError('c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6', 'No free space.');
} }
await this.expireOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as RemoteUser, driveCapacity - info.size); await this.expireOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as MiRemoteUser, driveCapacity - info.size);
} }
} }
//#endregion //#endregion
@ -558,7 +558,7 @@ export class DriveService {
const folder = await fetchFolder(); const folder = await fetchFolder();
let file = new DriveFile(); let file = new MiDriveFile();
file.id = this.idService.genId(); file.id = this.idService.genId();
file.createdAt = new Date(); file.createdAt = new Date();
file.userId = user ? user.id : null; file.userId = user ? user.id : null;
@ -614,7 +614,7 @@ export class DriveService {
file = await this.driveFilesRepository.findOneBy({ file = await this.driveFilesRepository.findOneBy({
uri: file.uri!, uri: file.uri!,
userId: user ? user.id : IsNull(), userId: user ? user.id : IsNull(),
}) as DriveFile; }) as MiDriveFile;
} else { } else {
this.registerLogger.error(err as Error); this.registerLogger.error(err as Error);
throw err; throw err;
@ -648,7 +648,7 @@ export class DriveService {
} }
@bindThis @bindThis
public async deleteFile(file: DriveFile, isExpired = false) { public async deleteFile(file: MiDriveFile, isExpired = false) {
if (file.storedInternal) { if (file.storedInternal) {
this.internalStorageService.del(file.accessKey!); this.internalStorageService.del(file.accessKey!);
@ -675,7 +675,7 @@ export class DriveService {
} }
@bindThis @bindThis
public async deleteFileSync(file: DriveFile, isExpired = false) { public async deleteFileSync(file: MiDriveFile, isExpired = false) {
if (file.storedInternal) { if (file.storedInternal) {
this.internalStorageService.del(file.accessKey!); this.internalStorageService.del(file.accessKey!);
@ -706,7 +706,7 @@ export class DriveService {
} }
@bindThis @bindThis
private async deletePostProcess(file: DriveFile, isExpired = false) { private async deletePostProcess(file: MiDriveFile, isExpired = false) {
// リモートファイル期限切れ削除後は直リンクにする // リモートファイル期限切れ削除後は直リンクにする
if (isExpired && file.userHost !== null && file.uri != null) { if (isExpired && file.userHost !== null && file.uri != null) {
this.driveFilesRepository.update(file.id, { this.driveFilesRepository.update(file.id, {
@ -769,7 +769,7 @@ export class DriveService {
comment = null, comment = null,
requestIp = null, requestIp = null,
requestHeaders = null, requestHeaders = null,
}: UploadFromUrlArgs): Promise<DriveFile> { }: UploadFromUrlArgs): Promise<MiDriveFile> {
// Create temp file // Create temp file
const [path, cleanup] = await createTemp(); const [path, cleanup] = await createTemp();

View File

@ -6,7 +6,7 @@
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import type { InstancesRepository } from '@/models/index.js'; import type { InstancesRepository } from '@/models/index.js';
import type { Instance } from '@/models/entities/Instance.js'; import type { MiInstance } from '@/models/entities/Instance.js';
import { MemoryKVCache, RedisKVCache } from '@/misc/cache.js'; import { MemoryKVCache, RedisKVCache } from '@/misc/cache.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -15,7 +15,7 @@ import { bindThis } from '@/decorators.js';
@Injectable() @Injectable()
export class FederatedInstanceService implements OnApplicationShutdown { export class FederatedInstanceService implements OnApplicationShutdown {
public federatedInstanceCache: RedisKVCache<Instance | null>; public federatedInstanceCache: RedisKVCache<MiInstance | null>;
constructor( constructor(
@Inject(DI.redis) @Inject(DI.redis)
@ -27,7 +27,7 @@ export class FederatedInstanceService implements OnApplicationShutdown {
private utilityService: UtilityService, private utilityService: UtilityService,
private idService: IdService, private idService: IdService,
) { ) {
this.federatedInstanceCache = new RedisKVCache<Instance | null>(this.redisClient, 'federatedInstance', { this.federatedInstanceCache = new RedisKVCache<MiInstance | null>(this.redisClient, 'federatedInstance', {
lifetime: 1000 * 60 * 30, // 30m lifetime: 1000 * 60 * 30, // 30m
memoryCacheLifetime: 1000 * 60 * 3, // 3m memoryCacheLifetime: 1000 * 60 * 3, // 3m
fetcher: (key) => this.instancesRepository.findOneBy({ host: key }), fetcher: (key) => this.instancesRepository.findOneBy({ host: key }),
@ -46,7 +46,7 @@ export class FederatedInstanceService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async fetch(host: string): Promise<Instance> { public async fetch(host: string): Promise<MiInstance> {
host = this.utilityService.toPuny(host); host = this.utilityService.toPuny(host);
const cached = await this.federatedInstanceCache.get(host); const cached = await this.federatedInstanceCache.get(host);
@ -70,7 +70,7 @@ export class FederatedInstanceService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async update(id: Instance['id'], data: Partial<Instance>): Promise<void> { public async update(id: MiInstance['id'], data: Partial<MiInstance>): Promise<void> {
const result = await this.instancesRepository.createQueryBuilder().update() const result = await this.instancesRepository.createQueryBuilder().update()
.set(data) .set(data)
.where('id = :id', { id }) .where('id = :id', { id })

View File

@ -8,7 +8,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { JSDOM } from 'jsdom'; import { JSDOM } from 'jsdom';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import type { Instance } from '@/models/entities/Instance.js'; import type { MiInstance } from '@/models/entities/Instance.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { LoggerService } from '@/core/LoggerService.js'; import { LoggerService } from '@/core/LoggerService.js';
@ -62,7 +62,7 @@ export class FetchInstanceMetadataService {
} }
@bindThis @bindThis
public async fetchInstanceMetadata(instance: Instance, force = false): Promise<void> { public async fetchInstanceMetadata(instance: MiInstance, force = false): Promise<void> {
const host = instance.host; const host = instance.host;
// Acquire mutex to ensure no parallel runs // Acquire mutex to ensure no parallel runs
if (!await this.tryLock(host)) return; if (!await this.tryLock(host)) return;
@ -123,7 +123,7 @@ export class FetchInstanceMetadataService {
} }
@bindThis @bindThis
private async fetchNodeinfo(instance: Instance): Promise<NodeInfo> { private async fetchNodeinfo(instance: MiInstance): Promise<NodeInfo> {
this.logger.info(`Fetching nodeinfo of ${instance.host} ...`); this.logger.info(`Fetching nodeinfo of ${instance.host} ...`);
try { try {
@ -142,10 +142,10 @@ export class FetchInstanceMetadataService {
const links = wellknown.links as any[]; const links = wellknown.links as any[];
const lnik1_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/1.0'); const link1_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/1.0');
const lnik2_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.0'); const link2_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.0');
const lnik2_1 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.1'); const link2_1 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.1');
const link = lnik2_1 ?? lnik2_0 ?? lnik1_0; const link = link2_1 ?? link2_0 ?? link1_0;
if (link == null) { if (link == null) {
throw new Error('No nodeinfo link provided'); throw new Error('No nodeinfo link provided');
@ -167,7 +167,7 @@ export class FetchInstanceMetadataService {
} }
@bindThis @bindThis
private async fetchDom(instance: Instance): Promise<DOMWindow['document']> { private async fetchDom(instance: MiInstance): Promise<DOMWindow['document']> {
this.logger.info(`Fetching HTML of ${instance.host} ...`); this.logger.info(`Fetching HTML of ${instance.host} ...`);
const url = 'https://' + instance.host; const url = 'https://' + instance.host;
@ -181,7 +181,7 @@ export class FetchInstanceMetadataService {
} }
@bindThis @bindThis
private async fetchManifest(instance: Instance): Promise<Record<string, unknown> | null> { private async fetchManifest(instance: MiInstance): Promise<Record<string, unknown> | null> {
const url = 'https://' + instance.host; const url = 'https://' + instance.host;
const manifestUrl = url + '/manifest.json'; const manifestUrl = url + '/manifest.json';
@ -192,7 +192,7 @@ export class FetchInstanceMetadataService {
} }
@bindThis @bindThis
private async fetchFaviconUrl(instance: Instance, doc: DOMWindow['document'] | null): Promise<string | null> { private async fetchFaviconUrl(instance: MiInstance, doc: DOMWindow['document'] | null): Promise<string | null> {
const url = 'https://' + instance.host; const url = 'https://' + instance.host;
if (doc) { if (doc) {
@ -218,7 +218,7 @@ export class FetchInstanceMetadataService {
} }
@bindThis @bindThis
private async fetchIconUrl(instance: Instance, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> { private async fetchIconUrl(instance: MiInstance, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
if (manifest && manifest.icons && manifest.icons.length > 0 && manifest.icons[0].src) { if (manifest && manifest.icons && manifest.icons.length > 0 && manifest.icons[0].src) {
const url = 'https://' + instance.host; const url = 'https://' + instance.host;
return (new URL(manifest.icons[0].src, url)).href; return (new URL(manifest.icons[0].src, url)).href;

View File

@ -5,10 +5,10 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import type { UserList } from '@/models/entities/UserList.js'; import type { MiUserList } from '@/models/entities/UserList.js';
import type { Antenna } from '@/models/entities/Antenna.js'; import type { MiAntenna } from '@/models/entities/Antenna.js';
import type { import type {
StreamChannels, StreamChannels,
AdminStreamTypes, AdminStreamTypes,
@ -25,7 +25,7 @@ import type { Packed } from '@/misc/json-schema.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { Role } from '@/models/index.js'; import { MiRole } from '@/models/index.js';
@Injectable() @Injectable()
export class GlobalEventService { export class GlobalEventService {
@ -61,17 +61,17 @@ export class GlobalEventService {
} }
@bindThis @bindThis
public publishMainStream<K extends keyof MainStreamTypes>(userId: User['id'], type: K, value?: MainStreamTypes[K]): void { public publishMainStream<K extends keyof MainStreamTypes>(userId: MiUser['id'], type: K, value?: MainStreamTypes[K]): void {
this.publish(`mainStream:${userId}`, type, typeof value === 'undefined' ? null : value); this.publish(`mainStream:${userId}`, type, typeof value === 'undefined' ? null : value);
} }
@bindThis @bindThis
public publishDriveStream<K extends keyof DriveStreamTypes>(userId: User['id'], type: K, value?: DriveStreamTypes[K]): void { public publishDriveStream<K extends keyof DriveStreamTypes>(userId: MiUser['id'], type: K, value?: DriveStreamTypes[K]): void {
this.publish(`driveStream:${userId}`, type, typeof value === 'undefined' ? null : value); this.publish(`driveStream:${userId}`, type, typeof value === 'undefined' ? null : value);
} }
@bindThis @bindThis
public publishNoteStream<K extends keyof NoteStreamTypes>(noteId: Note['id'], type: K, value?: NoteStreamTypes[K]): void { public publishNoteStream<K extends keyof NoteStreamTypes>(noteId: MiNote['id'], type: K, value?: NoteStreamTypes[K]): void {
this.publish(`noteStream:${noteId}`, type, { this.publish(`noteStream:${noteId}`, type, {
id: noteId, id: noteId,
body: value, body: value,
@ -79,17 +79,17 @@ export class GlobalEventService {
} }
@bindThis @bindThis
public publishUserListStream<K extends keyof UserListStreamTypes>(listId: UserList['id'], type: K, value?: UserListStreamTypes[K]): void { public publishUserListStream<K extends keyof UserListStreamTypes>(listId: MiUserList['id'], type: K, value?: UserListStreamTypes[K]): void {
this.publish(`userListStream:${listId}`, type, typeof value === 'undefined' ? null : value); this.publish(`userListStream:${listId}`, type, typeof value === 'undefined' ? null : value);
} }
@bindThis @bindThis
public publishAntennaStream<K extends keyof AntennaStreamTypes>(antennaId: Antenna['id'], type: K, value?: AntennaStreamTypes[K]): void { public publishAntennaStream<K extends keyof AntennaStreamTypes>(antennaId: MiAntenna['id'], type: K, value?: AntennaStreamTypes[K]): void {
this.publish(`antennaStream:${antennaId}`, type, typeof value === 'undefined' ? null : value); this.publish(`antennaStream:${antennaId}`, type, typeof value === 'undefined' ? null : value);
} }
@bindThis @bindThis
public publishRoleTimelineStream<K extends keyof RoleTimelineStreamTypes>(roleId: Role['id'], type: K, value?: RoleTimelineStreamTypes[K]): void { public publishRoleTimelineStream<K extends keyof RoleTimelineStreamTypes>(roleId: MiRole['id'], type: K, value?: RoleTimelineStreamTypes[K]): void {
this.publish(`roleTimelineStream:${roleId}`, type, typeof value === 'undefined' ? null : value); this.publish(`roleTimelineStream:${roleId}`, type, typeof value === 'undefined' ? null : value);
} }
@ -99,7 +99,7 @@ export class GlobalEventService {
} }
@bindThis @bindThis
public publishAdminStream<K extends keyof AdminStreamTypes>(userId: User['id'], type: K, value?: AdminStreamTypes[K]): void { public publishAdminStream<K extends keyof AdminStreamTypes>(userId: MiUser['id'], type: K, value?: AdminStreamTypes[K]): void {
this.publish(`adminStream:${userId}`, type, typeof value === 'undefined' ? null : value); this.publish(`adminStream:${userId}`, type, typeof value === 'undefined' ? null : value);
} }
} }

View File

@ -5,10 +5,10 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import type { Hashtag } from '@/models/entities/Hashtag.js'; import type { MiHashtag } from '@/models/entities/Hashtag.js';
import type { HashtagsRepository } from '@/models/index.js'; import type { HashtagsRepository } from '@/models/index.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -25,14 +25,14 @@ export class HashtagService {
} }
@bindThis @bindThis
public async updateHashtags(user: { id: User['id']; host: User['host']; }, tags: string[]) { public async updateHashtags(user: { id: MiUser['id']; host: MiUser['host']; }, tags: string[]) {
for (const tag of tags) { for (const tag of tags) {
await this.updateHashtag(user, tag); await this.updateHashtag(user, tag);
} }
} }
@bindThis @bindThis
public async updateUsertags(user: User, tags: string[]) { public async updateUsertags(user: MiUser, tags: string[]) {
for (const tag of tags) { for (const tag of tags) {
await this.updateHashtag(user, tag, true, true); await this.updateHashtag(user, tag, true, true);
} }
@ -43,7 +43,7 @@ export class HashtagService {
} }
@bindThis @bindThis
public async updateHashtag(user: { id: User['id']; host: User['host']; }, tag: string, isUserAttached = false, inc = true) { public async updateHashtag(user: { id: MiUser['id']; host: MiUser['host']; }, tag: string, isUserAttached = false, inc = true) {
tag = normalizeForSearch(tag); tag = normalizeForSearch(tag);
const index = await this.hashtagsRepository.findOneBy({ name: tag }); const index = await this.hashtagsRepository.findOneBy({ name: tag });
@ -123,7 +123,7 @@ export class HashtagService {
attachedLocalUsersCount: this.userEntityService.isLocalUser(user) ? 1 : 0, attachedLocalUsersCount: this.userEntityService.isLocalUser(user) ? 1 : 0,
attachedRemoteUserIds: this.userEntityService.isRemoteUser(user) ? [user.id] : [], attachedRemoteUserIds: this.userEntityService.isRemoteUser(user) ? [user.id] : [],
attachedRemoteUsersCount: this.userEntityService.isRemoteUser(user) ? 1 : 0, attachedRemoteUsersCount: this.userEntityService.isRemoteUser(user) ? 1 : 0,
} as Hashtag); } as MiHashtag);
} else { } else {
this.hashtagsRepository.insert({ this.hashtagsRepository.insert({
id: this.idService.genId(), id: this.idService.genId(),
@ -140,7 +140,7 @@ export class HashtagService {
attachedLocalUsersCount: 0, attachedLocalUsersCount: 0,
attachedRemoteUserIds: [], attachedRemoteUserIds: [],
attachedRemoteUsersCount: 0, attachedRemoteUsersCount: 0,
} as Hashtag); } as MiHashtag);
} }
} }
} }

View File

@ -53,12 +53,14 @@ export class HttpRequestService {
keepAlive: true, keepAlive: true,
keepAliveMsecs: 30 * 1000, keepAliveMsecs: 30 * 1000,
lookup: cache.lookup as unknown as net.LookupFunction, lookup: cache.lookup as unknown as net.LookupFunction,
localAddress: config.outgoingAddress,
}); });
this.https = new https.Agent({ this.https = new https.Agent({
keepAlive: true, keepAlive: true,
keepAliveMsecs: 30 * 1000, keepAliveMsecs: 30 * 1000,
lookup: cache.lookup as unknown as net.LookupFunction, lookup: cache.lookup as unknown as net.LookupFunction,
localAddress: config.outgoingAddress,
}); });
const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128); const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128);
@ -71,6 +73,7 @@ export class HttpRequestService {
maxFreeSockets: 256, maxFreeSockets: 256,
scheduling: 'lifo', scheduling: 'lifo',
proxy: config.proxy, proxy: config.proxy,
localAddress: config.outgoingAddress,
}) })
: this.http; : this.http;
@ -82,6 +85,7 @@ export class HttpRequestService {
maxFreeSockets: 256, maxFreeSockets: 256,
scheduling: 'lifo', scheduling: 'lifo',
proxy: config.proxy, proxy: config.proxy,
localAddress: config.outgoingAddress,
}) })
: this.https; : this.https;
} }

View File

@ -5,7 +5,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { IsNull } from 'typeorm'; import { IsNull } from 'typeorm';
import type { LocalUser } from '@/models/entities/User.js'; import type { MiLocalUser } from '@/models/entities/User.js';
import type { UsersRepository } from '@/models/index.js'; import type { UsersRepository } from '@/models/index.js';
import { MemorySingleCache } from '@/misc/cache.js'; import { MemorySingleCache } from '@/misc/cache.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -16,7 +16,7 @@ const ACTOR_USERNAME = 'instance.actor' as const;
@Injectable() @Injectable()
export class InstanceActorService { export class InstanceActorService {
private cache: MemorySingleCache<LocalUser>; private cache: MemorySingleCache<MiLocalUser>;
constructor( constructor(
@Inject(DI.usersRepository) @Inject(DI.usersRepository)
@ -24,24 +24,24 @@ export class InstanceActorService {
private createSystemUserService: CreateSystemUserService, private createSystemUserService: CreateSystemUserService,
) { ) {
this.cache = new MemorySingleCache<LocalUser>(Infinity); this.cache = new MemorySingleCache<MiLocalUser>(Infinity);
} }
@bindThis @bindThis
public async getInstanceActor(): Promise<LocalUser> { public async getInstanceActor(): Promise<MiLocalUser> {
const cached = this.cache.get(); const cached = this.cache.get();
if (cached) return cached; if (cached) return cached;
const user = await this.usersRepository.findOneBy({ const user = await this.usersRepository.findOneBy({
host: IsNull(), host: IsNull(),
username: ACTOR_USERNAME, username: ACTOR_USERNAME,
}) as LocalUser | undefined; }) as MiLocalUser | undefined;
if (user) { if (user) {
this.cache.set(user); this.cache.set(user);
return user; return user;
} else { } else {
const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME) as LocalUser; const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME) as MiLocalUser;
this.cache.set(created); this.cache.set(created);
return created; return created;
} }

View File

@ -7,7 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { Meta } from '@/models/entities/Meta.js'; import { MiMeta } from '@/models/entities/Meta.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { StreamMessages } from '@/server/api/stream/types.js'; import { StreamMessages } from '@/server/api/stream/types.js';
@ -15,7 +15,7 @@ import type { OnApplicationShutdown } from '@nestjs/common';
@Injectable() @Injectable()
export class MetaService implements OnApplicationShutdown { export class MetaService implements OnApplicationShutdown {
private cache: Meta | undefined; private cache: MiMeta | undefined;
private intervalId: NodeJS.Timer; private intervalId: NodeJS.Timer;
constructor( constructor(
@ -59,12 +59,12 @@ export class MetaService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async fetch(noCache = false): Promise<Meta> { public async fetch(noCache = false): Promise<MiMeta> {
if (!noCache && this.cache) return this.cache; if (!noCache && this.cache) return this.cache;
return await this.db.transaction(async transactionalEntityManager => { return await this.db.transaction(async transactionalEntityManager => {
// 過去のバグでレコードが複数出来てしまっている可能性があるので新しいIDを優先する // 過去のバグでレコードが複数出来てしまっている可能性があるので新しいIDを優先する
const metas = await transactionalEntityManager.find(Meta, { const metas = await transactionalEntityManager.find(MiMeta, {
order: { order: {
id: 'DESC', id: 'DESC',
}, },
@ -79,13 +79,13 @@ export class MetaService implements OnApplicationShutdown {
// metaが空のときfetchMetaが同時に呼ばれるとここが同時に呼ばれてしまうことがあるのでフェイルセーフなupsertを使う // metaが空のときfetchMetaが同時に呼ばれるとここが同時に呼ばれてしまうことがあるのでフェイルセーフなupsertを使う
const saved = await transactionalEntityManager const saved = await transactionalEntityManager
.upsert( .upsert(
Meta, MiMeta,
{ {
id: 'x', id: 'x',
}, },
['id'], ['id'],
) )
.then((x) => transactionalEntityManager.findOneByOrFail(Meta, x.identifiers[0])); .then((x) => transactionalEntityManager.findOneByOrFail(MiMeta, x.identifiers[0]));
this.cache = saved; this.cache = saved;
return saved; return saved;
@ -94,9 +94,9 @@ export class MetaService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async update(data: Partial<Meta>): Promise<Meta> { public async update(data: Partial<MiMeta>): Promise<MiMeta> {
const updated = await this.db.transaction(async transactionalEntityManager => { const updated = await this.db.transaction(async transactionalEntityManager => {
const metas = await transactionalEntityManager.find(Meta, { const metas = await transactionalEntityManager.find(MiMeta, {
order: { order: {
id: 'DESC', id: 'DESC',
}, },
@ -105,9 +105,9 @@ export class MetaService implements OnApplicationShutdown {
const meta = metas[0]; const meta = metas[0];
if (meta) { if (meta) {
await transactionalEntityManager.update(Meta, meta.id, data); await transactionalEntityManager.update(MiMeta, meta.id, data);
const metas = await transactionalEntityManager.find(Meta, { const metas = await transactionalEntityManager.find(MiMeta, {
order: { order: {
id: 'DESC', id: 'DESC',
}, },
@ -115,7 +115,7 @@ export class MetaService implements OnApplicationShutdown {
return metas[0]; return metas[0];
} else { } else {
return await transactionalEntityManager.save(Meta, data); return await transactionalEntityManager.save(MiMeta, data);
} }
}); });

View File

@ -6,7 +6,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { ModerationLogsRepository } from '@/models/index.js'; import type { ModerationLogsRepository } from '@/models/index.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -21,7 +21,7 @@ export class ModerationLogService {
} }
@bindThis @bindThis
public async insertModerationLog(moderator: { id: User['id'] }, type: string, info?: Record<string, any>) { public async insertModerationLog(moderator: { id: MiUser['id'] }, type: string, info?: Record<string, any>) {
await this.moderationLogsRepository.insert({ await this.moderationLogsRepository.insert({
id: this.idService.genId(), id: this.idService.genId(),
createdAt: new Date(), createdAt: new Date(),

View File

@ -13,21 +13,21 @@ import { extractMentions } from '@/misc/extract-mentions.js';
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js'; import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
import { extractHashtags } from '@/misc/extract-hashtags.js'; import { extractHashtags } from '@/misc/extract-hashtags.js';
import type { IMentionedRemoteUsers } from '@/models/entities/Note.js'; import type { IMentionedRemoteUsers } from '@/models/entities/Note.js';
import { Note } from '@/models/entities/Note.js'; import { MiNote } from '@/models/entities/Note.js';
import type { ChannelsRepository, InstancesRepository, MutedNotesRepository, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js'; import type { ChannelsRepository, InstancesRepository, MutedNotesRepository, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MiDriveFile } from '@/models/entities/DriveFile.js';
import type { App } from '@/models/entities/App.js'; import type { MiApp } from '@/models/entities/App.js';
import { concat } from '@/misc/prelude/array.js'; import { concat } from '@/misc/prelude/array.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import type { User, LocalUser, RemoteUser } from '@/models/entities/User.js'; import type { MiUser, MiLocalUser, MiRemoteUser } from '@/models/entities/User.js';
import type { IPoll } from '@/models/entities/Poll.js'; import type { IPoll } from '@/models/entities/Poll.js';
import { Poll } from '@/models/entities/Poll.js'; import { MiPoll } from '@/models/entities/Poll.js';
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
import { checkWordMute } from '@/misc/check-word-mute.js'; import { checkWordMute } from '@/misc/check-word-mute.js';
import type { Channel } from '@/models/entities/Channel.js'; import type { MiChannel } from '@/models/entities/Channel.js';
import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js';
import { MemorySingleCache } from '@/misc/cache.js'; import { MemorySingleCache } from '@/misc/cache.js';
import type { UserProfile } from '@/models/entities/UserProfile.js'; import type { MiUserProfile } from '@/models/entities/UserProfile.js';
import { RelayService } from '@/core/RelayService.js'; import { RelayService } from '@/core/RelayService.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -54,23 +54,23 @@ import { RoleService } from '@/core/RoleService.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { SearchService } from '@/core/SearchService.js'; import { SearchService } from '@/core/SearchService.js';
const mutedWordsCache = new MemorySingleCache<{ userId: UserProfile['userId']; mutedWords: UserProfile['mutedWords']; }[]>(1000 * 60 * 5); const mutedWordsCache = new MemorySingleCache<{ userId: MiUserProfile['userId']; mutedWords: MiUserProfile['mutedWords']; }[]>(1000 * 60 * 5);
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention'; type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
class NotificationManager { class NotificationManager {
private notifier: { id: User['id']; }; private notifier: { id: MiUser['id']; };
private note: Note; private note: MiNote;
private queue: { private queue: {
target: LocalUser['id']; target: MiLocalUser['id'];
reason: NotificationType; reason: NotificationType;
}[]; }[];
constructor( constructor(
private mutingsRepository: MutingsRepository, private mutingsRepository: MutingsRepository,
private notificationService: NotificationService, private notificationService: NotificationService,
notifier: { id: User['id']; }, notifier: { id: MiUser['id']; },
note: Note, note: MiNote,
) { ) {
this.notifier = notifier; this.notifier = notifier;
this.note = note; this.note = note;
@ -78,7 +78,7 @@ class NotificationManager {
} }
@bindThis @bindThis
public push(notifiee: LocalUser['id'], reason: NotificationType) { public push(notifiee: MiLocalUser['id'], reason: NotificationType) {
// 自分自身へは通知しない // 自分自身へは通知しない
if (this.notifier.id === notifiee) return; if (this.notifier.id === notifiee) return;
@ -119,32 +119,32 @@ class NotificationManager {
} }
type MinimumUser = { type MinimumUser = {
id: User['id']; id: MiUser['id'];
host: User['host']; host: MiUser['host'];
username: User['username']; username: MiUser['username'];
uri: User['uri']; uri: MiUser['uri'];
}; };
type Option = { type Option = {
createdAt?: Date | null; createdAt?: Date | null;
name?: string | null; name?: string | null;
text?: string | null; text?: string | null;
reply?: Note | null; reply?: MiNote | null;
renote?: Note | null; renote?: MiNote | null;
files?: DriveFile[] | null; files?: MiDriveFile[] | null;
poll?: IPoll | null; poll?: IPoll | null;
localOnly?: boolean | null; localOnly?: boolean | null;
reactionAcceptance?: Note['reactionAcceptance']; reactionAcceptance?: MiNote['reactionAcceptance'];
cw?: string | null; cw?: string | null;
visibility?: string; visibility?: string;
visibleUsers?: MinimumUser[] | null; visibleUsers?: MinimumUser[] | null;
channel?: Channel | null; channel?: MiChannel | null;
apMentions?: MinimumUser[] | null; apMentions?: MinimumUser[] | null;
apHashtags?: string[] | null; apHashtags?: string[] | null;
apEmojis?: string[] | null; apEmojis?: string[] | null;
uri?: string | null; uri?: string | null;
url?: string | null; url?: string | null;
app?: App | null; app?: MiApp | null;
}; };
@Injectable() @Injectable()
@ -211,12 +211,12 @@ export class NoteCreateService implements OnApplicationShutdown {
@bindThis @bindThis
public async create(user: { public async create(user: {
id: User['id']; id: MiUser['id'];
username: User['username']; username: MiUser['username'];
host: User['host']; host: MiUser['host'];
createdAt: User['createdAt']; createdAt: MiUser['createdAt'];
isBot: User['isBot']; isBot: MiUser['isBot'];
}, data: Option, silent = false): Promise<Note> { }, data: Option, silent = false): Promise<MiNote> {
// チャンネル外にリプライしたら対象のスコープに合わせる // チャンネル外にリプライしたら対象のスコープに合わせる
// (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで)
if (data.reply && data.channel && data.reply.channelId !== data.channel.id) { if (data.reply && data.channel && data.reply.channelId !== data.channel.id) {
@ -348,8 +348,8 @@ export class NoteCreateService implements OnApplicationShutdown {
} }
@bindThis @bindThis
private async insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) { private async insertNote(user: { id: MiUser['id']; host: MiUser['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) {
const insert = new Note({ const insert = new MiNote({
id: this.idService.genId(data.createdAt!), id: this.idService.genId(data.createdAt!),
createdAt: data.createdAt!, createdAt: data.createdAt!,
fileIds: data.files ? data.files.map(file => file.id) : [], fileIds: data.files ? data.files.map(file => file.id) : [],
@ -411,9 +411,9 @@ export class NoteCreateService implements OnApplicationShutdown {
if (insert.hasPoll) { if (insert.hasPoll) {
// Start transaction // Start transaction
await this.db.transaction(async transactionalEntityManager => { await this.db.transaction(async transactionalEntityManager => {
await transactionalEntityManager.insert(Note, insert); await transactionalEntityManager.insert(MiNote, insert);
const poll = new Poll({ const poll = new MiPoll({
noteId: insert.id, noteId: insert.id,
choices: data.poll!.choices, choices: data.poll!.choices,
expiresAt: data.poll!.expiresAt, expiresAt: data.poll!.expiresAt,
@ -424,7 +424,7 @@ export class NoteCreateService implements OnApplicationShutdown {
userHost: user.host, userHost: user.host,
}); });
await transactionalEntityManager.insert(Poll, poll); await transactionalEntityManager.insert(MiPoll, poll);
}); });
} else { } else {
await this.notesRepository.insert(insert); await this.notesRepository.insert(insert);
@ -446,12 +446,12 @@ export class NoteCreateService implements OnApplicationShutdown {
} }
@bindThis @bindThis
private async postNoteCreated(note: Note, user: { private async postNoteCreated(note: MiNote, user: {
id: User['id']; id: MiUser['id'];
username: User['username']; username: MiUser['username'];
host: User['host']; host: MiUser['host'];
createdAt: User['createdAt']; createdAt: MiUser['createdAt'];
isBot: User['isBot']; isBot: MiUser['isBot'];
}, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) { }, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) {
const meta = await this.metaService.fetch(); const meta = await this.metaService.fetch();
@ -625,7 +625,7 @@ export class NoteCreateService implements OnApplicationShutdown {
// メンションされたリモートユーザーに配送 // メンションされたリモートユーザーに配送
for (const u of mentionedUsers.filter(u => this.userEntityService.isRemoteUser(u))) { for (const u of mentionedUsers.filter(u => this.userEntityService.isRemoteUser(u))) {
dm.addDirectRecipe(u as RemoteUser); dm.addDirectRecipe(u as MiRemoteUser);
} }
// 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送 // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送
@ -703,7 +703,7 @@ export class NoteCreateService implements OnApplicationShutdown {
} }
@bindThis @bindThis
private incRenoteCount(renote: Note) { private incRenoteCount(renote: MiNote) {
this.notesRepository.createQueryBuilder().update() this.notesRepository.createQueryBuilder().update()
.set({ .set({
renoteCount: () => '"renoteCount" + 1', renoteCount: () => '"renoteCount" + 1',
@ -714,7 +714,7 @@ export class NoteCreateService implements OnApplicationShutdown {
} }
@bindThis @bindThis
private async createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) { private async createMentionedEvents(mentionedUsers: MinimumUser[], note: MiNote, nm: NotificationManager) {
for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) { for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) {
const isThreadMuted = await this.noteThreadMutingsRepository.exist({ const isThreadMuted = await this.noteThreadMutingsRepository.exist({
where: { where: {
@ -746,12 +746,12 @@ export class NoteCreateService implements OnApplicationShutdown {
} }
@bindThis @bindThis
private saveReply(reply: Note, note: Note) { private saveReply(reply: MiNote, note: MiNote) {
this.notesRepository.increment({ id: reply.id }, 'repliesCount', 1); this.notesRepository.increment({ id: reply.id }, 'repliesCount', 1);
} }
@bindThis @bindThis
private async renderNoteOrRenoteActivity(data: Option, note: Note) { private async renderNoteOrRenoteActivity(data: Option, note: MiNote) {
if (data.localOnly) return null; if (data.localOnly) return null;
const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0) const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0)
@ -762,14 +762,14 @@ export class NoteCreateService implements OnApplicationShutdown {
} }
@bindThis @bindThis
private index(note: Note) { private index(note: MiNote) {
if (note.text == null && note.cw == null) return; if (note.text == null && note.cw == null) return;
this.searchService.indexNote(note); this.searchService.indexNote(note);
} }
@bindThis @bindThis
private incNotesCountOfUser(user: { id: User['id']; }) { private incNotesCountOfUser(user: { id: MiUser['id']; }) {
this.usersRepository.createQueryBuilder().update() this.usersRepository.createQueryBuilder().update()
.set({ .set({
updatedAt: new Date(), updatedAt: new Date(),
@ -780,13 +780,13 @@ export class NoteCreateService implements OnApplicationShutdown {
} }
@bindThis @bindThis
private async extractMentionedUsers(user: { host: User['host']; }, tokens: mfm.MfmNode[]): Promise<User[]> { private async extractMentionedUsers(user: { host: MiUser['host']; }, tokens: mfm.MfmNode[]): Promise<MiUser[]> {
if (tokens == null) return []; if (tokens == null) return [];
const mentions = extractMentions(tokens); const mentions = extractMentions(tokens);
let mentionedUsers = (await Promise.all(mentions.map(m => let mentionedUsers = (await Promise.all(mentions.map(m =>
this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null), this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null),
))).filter(x => x != null) as User[]; ))).filter(x => x != null) as MiUser[];
// Drop duplicate users // Drop duplicate users
mentionedUsers = mentionedUsers.filter((u, i, self) => mentionedUsers = mentionedUsers.filter((u, i, self) =>

View File

@ -5,8 +5,8 @@
import { Brackets, In } from 'typeorm'; import { Brackets, In } from 'typeorm';
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import type { User, LocalUser, RemoteUser } from '@/models/entities/User.js'; import type { MiUser, MiLocalUser, MiRemoteUser } from '@/models/entities/User.js';
import type { Note, IMentionedRemoteUsers } from '@/models/entities/Note.js'; import type { MiNote, IMentionedRemoteUsers } from '@/models/entities/Note.js';
import type { InstancesRepository, NotesRepository, UsersRepository } from '@/models/index.js'; import type { InstancesRepository, NotesRepository, UsersRepository } from '@/models/index.js';
import { RelayService } from '@/core/RelayService.js'; import { RelayService } from '@/core/RelayService.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
@ -58,7 +58,7 @@ export class NoteDeleteService {
* @param user 稿 * @param user 稿
* @param note 稿 * @param note 稿
*/ */
async delete(user: { id: User['id']; uri: User['uri']; host: User['host']; isBot: User['isBot']; }, note: Note, quiet = false) { async delete(user: { id: MiUser['id']; uri: MiUser['uri']; host: MiUser['host']; isBot: MiUser['isBot']; }, note: MiNote, quiet = false) {
const deletedAt = new Date(); const deletedAt = new Date();
const cascadingNotes = await this.findCascadingNotes(note); const cascadingNotes = await this.findCascadingNotes(note);
@ -79,7 +79,7 @@ export class NoteDeleteService {
//#region ローカルの投稿なら削除アクティビティを配送 //#region ローカルの投稿なら削除アクティビティを配送
if (this.userEntityService.isLocalUser(user) && !note.localOnly) { if (this.userEntityService.isLocalUser(user) && !note.localOnly) {
let renote: Note | null = null; let renote: MiNote | null = null;
// if deletd note is renote // if deletd note is renote
if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) { if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) {
@ -134,8 +134,8 @@ export class NoteDeleteService {
} }
@bindThis @bindThis
private async findCascadingNotes(note: Note): Promise<Note[]> { private async findCascadingNotes(note: MiNote): Promise<MiNote[]> {
const recursive = async (noteId: string): Promise<Note[]> => { const recursive = async (noteId: string): Promise<MiNote[]> => {
const query = this.notesRepository.createQueryBuilder('note') const query = this.notesRepository.createQueryBuilder('note')
.where('note.replyId = :noteId', { noteId }) .where('note.replyId = :noteId', { noteId })
.orWhere(new Brackets(q => { .orWhere(new Brackets(q => {
@ -151,13 +151,13 @@ export class NoteDeleteService {
].flat(); ].flat();
}; };
const cascadingNotes: Note[] = await recursive(note.id); const cascadingNotes: MiNote[] = await recursive(note.id);
return cascadingNotes; return cascadingNotes;
} }
@bindThis @bindThis
private async getMentionedRemoteUsers(note: Note) { private async getMentionedRemoteUsers(note: MiNote) {
const where = [] as any[]; const where = [] as any[];
// mention / reply / dm // mention / reply / dm
@ -179,11 +179,11 @@ export class NoteDeleteService {
return await this.usersRepository.find({ return await this.usersRepository.find({
where, where,
}) as RemoteUser[]; }) as MiRemoteUser[];
} }
@bindThis @bindThis
private async deliverToConcerned(user: { id: LocalUser['id']; host: null; }, note: Note, content: any) { private async deliverToConcerned(user: { id: MiLocalUser['id']; host: null; }, note: MiNote, content: any) {
this.apDeliverManagerService.deliverToFollowers(user, content); this.apDeliverManagerService.deliverToFollowers(user, content);
this.relayService.deliverToRelays(user, content); this.relayService.deliverToRelays(user, content);
const remoteUsers = await this.getMentionedRemoteUsers(note); const remoteUsers = await this.getMentionedRemoteUsers(note);

View File

@ -7,10 +7,10 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { NotesRepository, UserNotePiningsRepository, UsersRepository } from '@/models/index.js'; import type { NotesRepository, UserNotePiningsRepository, UsersRepository } from '@/models/index.js';
import { IdentifiableError } from '@/misc/identifiable-error.js'; import { IdentifiableError } from '@/misc/identifiable-error.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import type { UserNotePining } from '@/models/entities/UserNotePining.js'; import type { MiUserNotePining } from '@/models/entities/UserNotePining.js';
import { RelayService } from '@/core/RelayService.js'; import { RelayService } from '@/core/RelayService.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
@ -49,7 +49,7 @@ export class NotePiningService {
* @param noteId * @param noteId
*/ */
@bindThis @bindThis
public async addPinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) { public async addPinned(user: { id: MiUser['id']; host: MiUser['host']; }, noteId: MiNote['id']) {
// Fetch pinee // Fetch pinee
const note = await this.notesRepository.findOneBy({ const note = await this.notesRepository.findOneBy({
id: noteId, id: noteId,
@ -75,7 +75,7 @@ export class NotePiningService {
createdAt: new Date(), createdAt: new Date(),
userId: user.id, userId: user.id,
noteId: note.id, noteId: note.id,
} as UserNotePining); } as MiUserNotePining);
// Deliver to remote followers // Deliver to remote followers
if (this.userEntityService.isLocalUser(user)) { if (this.userEntityService.isLocalUser(user)) {
@ -89,7 +89,7 @@ export class NotePiningService {
* @param noteId * @param noteId
*/ */
@bindThis @bindThis
public async removePinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) { public async removePinned(user: { id: MiUser['id']; host: MiUser['host']; }, noteId: MiNote['id']) {
// Fetch unpinee // Fetch unpinee
const note = await this.notesRepository.findOneBy({ const note = await this.notesRepository.findOneBy({
id: noteId, id: noteId,
@ -112,7 +112,7 @@ export class NotePiningService {
} }
@bindThis @bindThis
public async deliverPinnedChange(userId: User['id'], noteId: Note['id'], isAddition: boolean) { public async deliverPinnedChange(userId: MiUser['id'], noteId: MiNote['id'], isAddition: boolean) {
const user = await this.usersRepository.findOneBy({ id: userId }); const user = await this.usersRepository.findOneBy({ id: userId });
if (user == null) throw new Error('user not found'); if (user == null) throw new Error('user not found');

View File

@ -7,9 +7,9 @@ import { setTimeout } from 'node:timers/promises';
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import { In } from 'typeorm'; import { In } from 'typeorm';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import type { Packed } from '@/misc/json-schema.js'; import type { Packed } from '@/misc/json-schema.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import type { NoteUnreadsRepository, MutingsRepository, NoteThreadMutingsRepository } from '@/models/index.js'; import type { NoteUnreadsRepository, MutingsRepository, NoteThreadMutingsRepository } from '@/models/index.js';
@ -35,7 +35,7 @@ export class NoteReadService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async insertNoteUnread(userId: User['id'], note: Note, params: { public async insertNoteUnread(userId: MiUser['id'], note: MiNote, params: {
// NOTE: isSpecifiedがtrueならisMentionedは必ずfalse // NOTE: isSpecifiedがtrueならisMentionedは必ずfalse
isSpecified: boolean; isSpecified: boolean;
isMentioned: boolean; isMentioned: boolean;
@ -84,11 +84,11 @@ export class NoteReadService implements OnApplicationShutdown {
@bindThis @bindThis
public async read( public async read(
userId: User['id'], userId: MiUser['id'],
notes: (Note | Packed<'Note'>)[], notes: (MiNote | Packed<'Note'>)[],
): Promise<void> { ): Promise<void> {
const readMentions: (Note | Packed<'Note'>)[] = []; const readMentions: (MiNote | Packed<'Note'>)[] = [];
const readSpecifiedNotes: (Note | Packed<'Note'>)[] = []; const readSpecifiedNotes: (MiNote | Packed<'Note'>)[] = [];
for (const note of notes) { for (const note of notes) {
if (note.mentions && note.mentions.includes(userId)) { if (note.mentions && note.mentions.includes(userId)) {

View File

@ -9,8 +9,8 @@ import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import { In } from 'typeorm'; import { In } from 'typeorm';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { UsersRepository } from '@/models/index.js'; import type { UsersRepository } from '@/models/index.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import type { Notification } from '@/models/entities/Notification.js'; import type { MiNotification } from '@/models/entities/Notification.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import { PushNotificationService } from '@/core/PushNotificationService.js'; import { PushNotificationService } from '@/core/PushNotificationService.js';
@ -39,7 +39,7 @@ export class NotificationService implements OnApplicationShutdown {
@bindThis @bindThis
public async readAllNotification( public async readAllNotification(
userId: User['id'], userId: MiUser['id'],
force = false, force = false,
) { ) {
const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${userId}`); const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${userId}`);
@ -61,17 +61,17 @@ export class NotificationService implements OnApplicationShutdown {
} }
@bindThis @bindThis
private postReadAllNotifications(userId: User['id']) { private postReadAllNotifications(userId: MiUser['id']) {
this.globalEventService.publishMainStream(userId, 'readAllNotifications'); this.globalEventService.publishMainStream(userId, 'readAllNotifications');
this.pushNotificationService.pushNotification(userId, 'readAllNotifications', undefined); this.pushNotificationService.pushNotification(userId, 'readAllNotifications', undefined);
} }
@bindThis @bindThis
public async createNotification( public async createNotification(
notifieeId: User['id'], notifieeId: MiUser['id'],
type: Notification['type'], type: MiNotification['type'],
data: Partial<Notification>, data: Partial<MiNotification>,
): Promise<Notification | null> { ): Promise<MiNotification | null> {
const profile = await this.cacheService.userProfileCache.fetch(notifieeId); const profile = await this.cacheService.userProfileCache.fetch(notifieeId);
const isMuted = profile.mutingNotificationTypes.includes(type); const isMuted = profile.mutingNotificationTypes.includes(type);
if (isMuted) return null; if (isMuted) return null;
@ -92,7 +92,7 @@ export class NotificationService implements OnApplicationShutdown {
createdAt: new Date(), createdAt: new Date(),
type: type, type: type,
...data, ...data,
} as Notification; } as MiNotification;
const redisIdPromise = this.redisClient.xadd( const redisIdPromise = this.redisClient.xadd(
`notificationTimeline:${notifieeId}`, `notificationTimeline:${notifieeId}`,
@ -126,7 +126,7 @@ export class NotificationService implements OnApplicationShutdown {
// TODO: locale ファイルをクライアント用とサーバー用で分けたい // TODO: locale ファイルをクライアント用とサーバー用で分けたい
@bindThis @bindThis
private async emailNotificationFollow(userId: User['id'], follower: User) { private async emailNotificationFollow(userId: MiUser['id'], follower: MiUser) {
/* /*
const userProfile = await UserProfiles.findOneByOrFail({ userId: userId }); const userProfile = await UserProfiles.findOneByOrFail({ userId: userId });
if (!userProfile.email || !userProfile.emailNotificationTypes.includes('follow')) return; if (!userProfile.email || !userProfile.emailNotificationTypes.includes('follow')) return;
@ -138,7 +138,7 @@ export class NotificationService implements OnApplicationShutdown {
} }
@bindThis @bindThis
private async emailNotificationReceiveFollowRequest(userId: User['id'], follower: User) { private async emailNotificationReceiveFollowRequest(userId: MiUser['id'], follower: MiUser) {
/* /*
const userProfile = await UserProfiles.findOneByOrFail({ userId: userId }); const userProfile = await UserProfiles.findOneByOrFail({ userId: userId });
if (!userProfile.email || !userProfile.emailNotificationTypes.includes('receiveFollowRequest')) return; if (!userProfile.email || !userProfile.emailNotificationTypes.includes('receiveFollowRequest')) return;

View File

@ -5,8 +5,8 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { NotesRepository, UsersRepository, PollsRepository, PollVotesRepository, User } from '@/models/index.js'; import type { NotesRepository, UsersRepository, PollsRepository, PollVotesRepository, MiUser } from '@/models/index.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { RelayService } from '@/core/RelayService.js'; import { RelayService } from '@/core/RelayService.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
@ -42,7 +42,7 @@ export class PollService {
} }
@bindThis @bindThis
public async vote(user: User, note: Note, choice: number) { public async vote(user: MiUser, note: MiNote, choice: number) {
const poll = await this.pollsRepository.findOneBy({ noteId: note.id }); const poll = await this.pollsRepository.findOneBy({ noteId: note.id });
if (poll == null) throw new Error('poll not found'); if (poll == null) throw new Error('poll not found');
@ -92,7 +92,7 @@ export class PollService {
} }
@bindThis @bindThis
public async deliverQuestionUpdate(noteId: Note['id']) { public async deliverQuestionUpdate(noteId: MiNote['id']) {
const note = await this.notesRepository.findOneBy({ id: noteId }); const note = await this.notesRepository.findOneBy({ id: noteId });
if (note == null) throw new Error('note not found'); if (note == null) throw new Error('note not found');

View File

@ -5,7 +5,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import type { UsersRepository } from '@/models/index.js'; import type { UsersRepository } from '@/models/index.js';
import type { LocalUser } from '@/models/entities/User.js'; import type { MiLocalUser } from '@/models/entities/User.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -21,9 +21,9 @@ export class ProxyAccountService {
} }
@bindThis @bindThis
public async fetch(): Promise<LocalUser | null> { public async fetch(): Promise<MiLocalUser | null> {
const meta = await this.metaService.fetch(); const meta = await this.metaService.fetch();
if (meta.proxyAccountId == null) return null; if (meta.proxyAccountId == null) return null;
return await this.usersRepository.findOneByOrFail({ id: meta.proxyAccountId }) as LocalUser; return await this.usersRepository.findOneByOrFail({ id: meta.proxyAccountId }) as MiLocalUser;
} }
} }

View File

@ -10,7 +10,7 @@ import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type { Packed } from '@/misc/json-schema.js'; import type { Packed } from '@/misc/json-schema.js';
import { getNoteSummary } from '@/misc/get-note-summary.js'; import { getNoteSummary } from '@/misc/get-note-summary.js';
import type { SwSubscription, SwSubscriptionsRepository } from '@/models/index.js'; import type { MiSwSubscription, SwSubscriptionsRepository } from '@/models/index.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { RedisKVCache } from '@/misc/cache.js'; import { RedisKVCache } from '@/misc/cache.js';
@ -48,7 +48,7 @@ function truncateBody<T extends keyof PushNotificationsTypes>(type: T, body: Pus
@Injectable() @Injectable()
export class PushNotificationService implements OnApplicationShutdown { export class PushNotificationService implements OnApplicationShutdown {
private subscriptionsCache: RedisKVCache<SwSubscription[]>; private subscriptionsCache: RedisKVCache<MiSwSubscription[]>;
constructor( constructor(
@Inject(DI.config) @Inject(DI.config)
@ -62,7 +62,7 @@ export class PushNotificationService implements OnApplicationShutdown {
private metaService: MetaService, private metaService: MetaService,
) { ) {
this.subscriptionsCache = new RedisKVCache<SwSubscription[]>(this.redisClient, 'userSwSubscriptions', { this.subscriptionsCache = new RedisKVCache<MiSwSubscription[]>(this.redisClient, 'userSwSubscriptions', {
lifetime: 1000 * 60 * 60 * 1, // 1h lifetime: 1000 * 60 * 60 * 1, // 1h
memoryCacheLifetime: 1000 * 60 * 3, // 3m memoryCacheLifetime: 1000 * 60 * 3, // 3m
fetcher: (key) => this.swSubscriptionsRepository.findBy({ userId: key }), fetcher: (key) => this.swSubscriptionsRepository.findBy({ userId: key }),

View File

@ -6,7 +6,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Brackets, ObjectLiteral } from 'typeorm'; import { Brackets, ObjectLiteral } from 'typeorm';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import type { UserProfilesRepository, FollowingsRepository, ChannelFollowingsRepository, MutedNotesRepository, BlockingsRepository, NoteThreadMutingsRepository, MutingsRepository, RenoteMutingsRepository } from '@/models/index.js'; import type { UserProfilesRepository, FollowingsRepository, ChannelFollowingsRepository, MutedNotesRepository, BlockingsRepository, NoteThreadMutingsRepository, MutingsRepository, RenoteMutingsRepository } from '@/models/index.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type { SelectQueryBuilder } from 'typeorm'; import type { SelectQueryBuilder } from 'typeorm';
@ -69,7 +69,7 @@ export class QueryService {
// ここでいうBlockedは被Blockedの意 // ここでいうBlockedは被Blockedの意
@bindThis @bindThis
public generateBlockedUserQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void { public generateBlockedUserQuery(q: SelectQueryBuilder<any>, me: { id: MiUser['id'] }): void {
const blockingQuery = this.blockingsRepository.createQueryBuilder('blocking') const blockingQuery = this.blockingsRepository.createQueryBuilder('blocking')
.select('blocking.blockerId') .select('blocking.blockerId')
.where('blocking.blockeeId = :blockeeId', { blockeeId: me.id }); .where('blocking.blockeeId = :blockeeId', { blockeeId: me.id });
@ -92,7 +92,7 @@ export class QueryService {
} }
@bindThis @bindThis
public generateBlockQueryForUsers(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void { public generateBlockQueryForUsers(q: SelectQueryBuilder<any>, me: { id: MiUser['id'] }): void {
const blockingQuery = this.blockingsRepository.createQueryBuilder('blocking') const blockingQuery = this.blockingsRepository.createQueryBuilder('blocking')
.select('blocking.blockeeId') .select('blocking.blockeeId')
.where('blocking.blockerId = :blockerId', { blockerId: me.id }); .where('blocking.blockerId = :blockerId', { blockerId: me.id });
@ -109,7 +109,7 @@ export class QueryService {
} }
@bindThis @bindThis
public generateChannelQuery(q: SelectQueryBuilder<any>, me?: { id: User['id'] } | null): void { public generateChannelQuery(q: SelectQueryBuilder<any>, me?: { id: MiUser['id'] } | null): void {
if (me == null) { if (me == null) {
q.andWhere('note.channelId IS NULL'); q.andWhere('note.channelId IS NULL');
} else { } else {
@ -131,7 +131,7 @@ export class QueryService {
} }
@bindThis @bindThis
public generateMutedNoteQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void { public generateMutedNoteQuery(q: SelectQueryBuilder<any>, me: { id: MiUser['id'] }): void {
const mutedQuery = this.mutedNotesRepository.createQueryBuilder('muted') const mutedQuery = this.mutedNotesRepository.createQueryBuilder('muted')
.select('muted.noteId') .select('muted.noteId')
.where('muted.userId = :userId', { userId: me.id }); .where('muted.userId = :userId', { userId: me.id });
@ -142,7 +142,7 @@ export class QueryService {
} }
@bindThis @bindThis
public generateMutedNoteThreadQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void { public generateMutedNoteThreadQuery(q: SelectQueryBuilder<any>, me: { id: MiUser['id'] }): void {
const mutedQuery = this.noteThreadMutingsRepository.createQueryBuilder('threadMuted') const mutedQuery = this.noteThreadMutingsRepository.createQueryBuilder('threadMuted')
.select('threadMuted.threadId') .select('threadMuted.threadId')
.where('threadMuted.userId = :userId', { userId: me.id }); .where('threadMuted.userId = :userId', { userId: me.id });
@ -157,7 +157,7 @@ export class QueryService {
} }
@bindThis @bindThis
public generateMutedUserQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }, exclude?: User): void { public generateMutedUserQuery(q: SelectQueryBuilder<any>, me: { id: MiUser['id'] }, exclude?: MiUser): void {
const mutingQuery = this.mutingsRepository.createQueryBuilder('muting') const mutingQuery = this.mutingsRepository.createQueryBuilder('muting')
.select('muting.muteeId') .select('muting.muteeId')
.where('muting.muterId = :muterId', { muterId: me.id }); .where('muting.muterId = :muterId', { muterId: me.id });
@ -202,7 +202,7 @@ export class QueryService {
} }
@bindThis @bindThis
public generateMutedUserQueryForUsers(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void { public generateMutedUserQueryForUsers(q: SelectQueryBuilder<any>, me: { id: MiUser['id'] }): void {
const mutingQuery = this.mutingsRepository.createQueryBuilder('muting') const mutingQuery = this.mutingsRepository.createQueryBuilder('muting')
.select('muting.muteeId') .select('muting.muteeId')
.where('muting.muterId = :muterId', { muterId: me.id }); .where('muting.muterId = :muterId', { muterId: me.id });
@ -213,7 +213,7 @@ export class QueryService {
} }
@bindThis @bindThis
public generateRepliesQuery(q: SelectQueryBuilder<any>, withReplies: boolean, me?: Pick<User, 'id'> | null): void { public generateRepliesQuery(q: SelectQueryBuilder<any>, withReplies: boolean, me?: Pick<MiUser, 'id'> | null): void {
if (me == null) { if (me == null) {
q.andWhere(new Brackets(qb => { qb q.andWhere(new Brackets(qb => { qb
.where('note.replyId IS NULL') // 返信ではない .where('note.replyId IS NULL') // 返信ではない
@ -239,7 +239,7 @@ export class QueryService {
} }
@bindThis @bindThis
public generateVisibilityQuery(q: SelectQueryBuilder<any>, me?: { id: User['id'] } | null): void { public generateVisibilityQuery(q: SelectQueryBuilder<any>, me?: { id: MiUser['id'] } | null): void {
// This code must always be synchronized with the checks in Notes.isVisibleForMe. // This code must always be synchronized with the checks in Notes.isVisibleForMe.
if (me == null) { if (me == null) {
q.andWhere(new Brackets(qb => { qb q.andWhere(new Brackets(qb => { qb
@ -279,7 +279,7 @@ export class QueryService {
} }
@bindThis @bindThis
public generateMutedUserRenotesQueryForNotes(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void { public generateMutedUserRenotesQueryForNotes(q: SelectQueryBuilder<any>, me: { id: MiUser['id'] }): void {
const mutingQuery = this.renoteMutingsRepository.createQueryBuilder('renote_muting') const mutingQuery = this.renoteMutingsRepository.createQueryBuilder('renote_muting')
.select('renote_muting.muteeId') .select('renote_muting.muteeId')
.where('renote_muting.muterId = :muterId', { muterId: me.id }); .where('renote_muting.muterId = :muterId', { muterId: me.id });

View File

@ -6,8 +6,8 @@
import { randomUUID } from 'node:crypto'; import { randomUUID } from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import type { IActivity } from '@/core/activitypub/type.js'; import type { IActivity } from '@/core/activitypub/type.js';
import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MiDriveFile } from '@/models/entities/DriveFile.js';
import type { Webhook, webhookEventTypes } from '@/models/entities/Webhook.js'; import type { MiWebhook, webhookEventTypes } from '@/models/entities/Webhook.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -237,7 +237,7 @@ export class QueueService {
} }
@bindThis @bindThis
public createImportFollowingJob(user: ThinUser, fileId: DriveFile['id']) { public createImportFollowingJob(user: ThinUser, fileId: MiDriveFile['id']) {
return this.dbQueue.add('importFollowing', { return this.dbQueue.add('importFollowing', {
user: { id: user.id }, user: { id: user.id },
fileId: fileId, fileId: fileId,
@ -254,7 +254,7 @@ export class QueueService {
} }
@bindThis @bindThis
public createImportMutingJob(user: ThinUser, fileId: DriveFile['id']) { public createImportMutingJob(user: ThinUser, fileId: MiDriveFile['id']) {
return this.dbQueue.add('importMuting', { return this.dbQueue.add('importMuting', {
user: { id: user.id }, user: { id: user.id },
fileId: fileId, fileId: fileId,
@ -265,7 +265,7 @@ export class QueueService {
} }
@bindThis @bindThis
public createImportBlockingJob(user: ThinUser, fileId: DriveFile['id']) { public createImportBlockingJob(user: ThinUser, fileId: MiDriveFile['id']) {
return this.dbQueue.add('importBlocking', { return this.dbQueue.add('importBlocking', {
user: { id: user.id }, user: { id: user.id },
fileId: fileId, fileId: fileId,
@ -298,7 +298,7 @@ export class QueueService {
} }
@bindThis @bindThis
public createImportUserListsJob(user: ThinUser, fileId: DriveFile['id']) { public createImportUserListsJob(user: ThinUser, fileId: MiDriveFile['id']) {
return this.dbQueue.add('importUserLists', { return this.dbQueue.add('importUserLists', {
user: { id: user.id }, user: { id: user.id },
fileId: fileId, fileId: fileId,
@ -309,7 +309,7 @@ export class QueueService {
} }
@bindThis @bindThis
public createImportCustomEmojisJob(user: ThinUser, fileId: DriveFile['id']) { public createImportCustomEmojisJob(user: ThinUser, fileId: MiDriveFile['id']) {
return this.dbQueue.add('importCustomEmojis', { return this.dbQueue.add('importCustomEmojis', {
user: { id: user.id }, user: { id: user.id },
fileId: fileId, fileId: fileId,
@ -412,7 +412,7 @@ export class QueueService {
} }
@bindThis @bindThis
public webhookDeliver(webhook: Webhook, type: typeof webhookEventTypes[number], content: unknown) { public webhookDeliver(webhook: MiWebhook, type: typeof webhookEventTypes[number], content: unknown) {
const data = { const data = {
type, type,
content, content,

View File

@ -7,10 +7,10 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { EmojisRepository, NoteReactionsRepository, UsersRepository, NotesRepository } from '@/models/index.js'; import type { EmojisRepository, NoteReactionsRepository, UsersRepository, NotesRepository } from '@/models/index.js';
import { IdentifiableError } from '@/misc/identifiable-error.js'; import { IdentifiableError } from '@/misc/identifiable-error.js';
import type { RemoteUser, User } from '@/models/entities/User.js'; import type { MiRemoteUser, MiUser } from '@/models/entities/User.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import type { NoteReaction } from '@/models/entities/NoteReaction.js'; import type { MiNoteReaction } from '@/models/entities/NoteReaction.js';
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import { NotificationService } from '@/core/NotificationService.js'; import { NotificationService } from '@/core/NotificationService.js';
@ -95,7 +95,7 @@ export class ReactionService {
} }
@bindThis @bindThis
public async create(user: { id: User['id']; host: User['host']; isBot: User['isBot'] }, note: Note, _reaction?: string | null) { public async create(user: { id: MiUser['id']; host: MiUser['host']; isBot: MiUser['isBot'] }, note: MiNote, _reaction?: string | null) {
// Check blocking // Check blocking
if (note.userId !== user.id) { if (note.userId !== user.id) {
const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id); const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id);
@ -146,7 +146,7 @@ export class ReactionService {
} }
} }
const record: NoteReaction = { const record: MiNoteReaction = {
id: this.idService.genId(), id: this.idService.genId(),
createdAt: new Date(), createdAt: new Date(),
noteId: note.id, noteId: note.id,
@ -231,7 +231,7 @@ export class ReactionService {
const dm = this.apDeliverManagerService.createDeliverManager(user, content); const dm = this.apDeliverManagerService.createDeliverManager(user, content);
if (note.userHost !== null) { if (note.userHost !== null) {
const reactee = await this.usersRepository.findOneBy({ id: note.userId }); const reactee = await this.usersRepository.findOneBy({ id: note.userId });
dm.addDirectRecipe(reactee as RemoteUser); dm.addDirectRecipe(reactee as MiRemoteUser);
} }
if (['public', 'home', 'followers'].includes(note.visibility)) { if (['public', 'home', 'followers'].includes(note.visibility)) {
@ -239,7 +239,7 @@ export class ReactionService {
} else if (note.visibility === 'specified') { } else if (note.visibility === 'specified') {
const visibleUsers = await Promise.all(note.visibleUserIds.map(id => this.usersRepository.findOneBy({ id }))); const visibleUsers = await Promise.all(note.visibleUserIds.map(id => this.usersRepository.findOneBy({ id })));
for (const u of visibleUsers.filter(u => u && this.userEntityService.isRemoteUser(u))) { for (const u of visibleUsers.filter(u => u && this.userEntityService.isRemoteUser(u))) {
dm.addDirectRecipe(u as RemoteUser); dm.addDirectRecipe(u as MiRemoteUser);
} }
} }
@ -249,7 +249,7 @@ export class ReactionService {
} }
@bindThis @bindThis
public async delete(user: { id: User['id']; host: User['host']; isBot: User['isBot']; }, note: Note) { public async delete(user: { id: MiUser['id']; host: MiUser['host']; isBot: MiUser['isBot']; }, note: MiNote) {
// if already unreacted // if already unreacted
const exist = await this.noteReactionsRepository.findOneBy({ const exist = await this.noteReactionsRepository.findOneBy({
noteId: note.id, noteId: note.id,
@ -289,7 +289,7 @@ export class ReactionService {
const dm = this.apDeliverManagerService.createDeliverManager(user, content); const dm = this.apDeliverManagerService.createDeliverManager(user, content);
if (note.userHost !== null) { if (note.userHost !== null) {
const reactee = await this.usersRepository.findOneBy({ id: note.userId }); const reactee = await this.usersRepository.findOneBy({ id: note.userId });
dm.addDirectRecipe(reactee as RemoteUser); dm.addDirectRecipe(reactee as MiRemoteUser);
} }
dm.addFollowersRecipe(); dm.addFollowersRecipe();
dm.execute(); dm.execute();

View File

@ -5,11 +5,11 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { IsNull } from 'typeorm'; import { IsNull } from 'typeorm';
import type { LocalUser, User } from '@/models/entities/User.js'; import type { MiLocalUser, MiUser } from '@/models/entities/User.js';
import type { RelaysRepository, UsersRepository } from '@/models/index.js'; import type { RelaysRepository, UsersRepository } from '@/models/index.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { MemorySingleCache } from '@/misc/cache.js'; import { MemorySingleCache } from '@/misc/cache.js';
import type { Relay } from '@/models/entities/Relay.js'; import type { MiRelay } from '@/models/entities/Relay.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
import { CreateSystemUserService } from '@/core/CreateSystemUserService.js'; import { CreateSystemUserService } from '@/core/CreateSystemUserService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
@ -21,7 +21,7 @@ const ACTOR_USERNAME = 'relay.actor' as const;
@Injectable() @Injectable()
export class RelayService { export class RelayService {
private relaysCache: MemorySingleCache<Relay[]>; private relaysCache: MemorySingleCache<MiRelay[]>;
constructor( constructor(
@Inject(DI.usersRepository) @Inject(DI.usersRepository)
@ -35,24 +35,24 @@ export class RelayService {
private createSystemUserService: CreateSystemUserService, private createSystemUserService: CreateSystemUserService,
private apRendererService: ApRendererService, private apRendererService: ApRendererService,
) { ) {
this.relaysCache = new MemorySingleCache<Relay[]>(1000 * 60 * 10); this.relaysCache = new MemorySingleCache<MiRelay[]>(1000 * 60 * 10);
} }
@bindThis @bindThis
private async getRelayActor(): Promise<LocalUser> { private async getRelayActor(): Promise<MiLocalUser> {
const user = await this.usersRepository.findOneBy({ const user = await this.usersRepository.findOneBy({
host: IsNull(), host: IsNull(),
username: ACTOR_USERNAME, username: ACTOR_USERNAME,
}); });
if (user) return user as LocalUser; if (user) return user as MiLocalUser;
const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME); const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME);
return created as LocalUser; return created as MiLocalUser;
} }
@bindThis @bindThis
public async addRelay(inbox: string): Promise<Relay> { public async addRelay(inbox: string): Promise<MiRelay> {
const relay = await this.relaysRepository.insert({ const relay = await this.relaysRepository.insert({
id: this.idService.genId(), id: this.idService.genId(),
inbox, inbox,
@ -87,7 +87,7 @@ export class RelayService {
} }
@bindThis @bindThis
public async listRelay(): Promise<Relay[]> { public async listRelay(): Promise<MiRelay[]> {
const relays = await this.relaysRepository.find(); const relays = await this.relaysRepository.find();
return relays; return relays;
} }
@ -111,7 +111,7 @@ export class RelayService {
} }
@bindThis @bindThis
public async deliverToRelays(user: { id: User['id']; host: null; }, activity: any): Promise<void> { public async deliverToRelays(user: { id: MiUser['id']; host: null; }, activity: any): Promise<void> {
if (activity == null) return; if (activity == null) return;
const relays = await this.relaysCache.fetch(() => this.relaysRepository.findBy({ const relays = await this.relaysCache.fetch(() => this.relaysRepository.findBy({

View File

@ -9,7 +9,7 @@ import chalk from 'chalk';
import { IsNull } from 'typeorm'; import { IsNull } from 'typeorm';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { UsersRepository } from '@/models/index.js'; import type { UsersRepository } from '@/models/index.js';
import type { LocalUser, RemoteUser } from '@/models/entities/User.js'; import type { MiLocalUser, MiRemoteUser } from '@/models/entities/User.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { UtilityService } from '@/core/UtilityService.js'; import { UtilityService } from '@/core/UtilityService.js';
@ -40,7 +40,7 @@ export class RemoteUserResolveService {
} }
@bindThis @bindThis
public async resolveUser(username: string, host: string | null): Promise<LocalUser | RemoteUser> { public async resolveUser(username: string, host: string | null): Promise<MiLocalUser | MiRemoteUser> {
const usernameLower = username.toLowerCase(); const usernameLower = username.toLowerCase();
if (host == null) { if (host == null) {
@ -51,7 +51,7 @@ export class RemoteUserResolveService {
} else { } else {
return u; return u;
} }
}) as LocalUser; }) as MiLocalUser;
} }
host = this.utilityService.toPuny(host); host = this.utilityService.toPuny(host);
@ -64,10 +64,10 @@ export class RemoteUserResolveService {
} else { } else {
return u; return u;
} }
}) as LocalUser; }) as MiLocalUser;
} }
const user = await this.usersRepository.findOneBy({ usernameLower, host }) as RemoteUser | null; const user = await this.usersRepository.findOneBy({ usernameLower, host }) as MiRemoteUser | null;
const acctLower = `${usernameLower}@${host}`; const acctLower = `${usernameLower}@${host}`;
@ -86,7 +86,7 @@ export class RemoteUserResolveService {
} else { } else {
return u; return u;
} }
})) as LocalUser; })) as MiLocalUser;
} }
} }
@ -132,7 +132,7 @@ export class RemoteUserResolveService {
if (u == null) { if (u == null) {
throw new Error('user not found'); throw new Error('user not found');
} else { } else {
return u as LocalUser | RemoteUser; return u as MiLocalUser | MiRemoteUser;
} }
}); });
} }

View File

@ -6,9 +6,9 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import { In } from 'typeorm'; import { In } from 'typeorm';
import type { Role, RoleAssignment, RoleAssignmentsRepository, RolesRepository, UsersRepository } from '@/models/index.js'; import type { MiRole, MiRoleAssignment, RoleAssignmentsRepository, RolesRepository, UsersRepository } from '@/models/index.js';
import { MemoryKVCache, MemorySingleCache } from '@/misc/cache.js'; import { MemoryKVCache, MemorySingleCache } from '@/misc/cache.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
@ -71,8 +71,8 @@ export const DEFAULT_POLICIES: RolePolicies = {
@Injectable() @Injectable()
export class RoleService implements OnApplicationShutdown { export class RoleService implements OnApplicationShutdown {
private rolesCache: MemorySingleCache<Role[]>; private rolesCache: MemorySingleCache<MiRole[]>;
private roleAssignmentByUserIdCache: MemoryKVCache<RoleAssignment[]>; private roleAssignmentByUserIdCache: MemoryKVCache<MiRoleAssignment[]>;
public static AlreadyAssignedError = class extends Error {}; public static AlreadyAssignedError = class extends Error {};
public static NotAssignedError = class extends Error {}; public static NotAssignedError = class extends Error {};
@ -101,8 +101,8 @@ export class RoleService implements OnApplicationShutdown {
) { ) {
//this.onMessage = this.onMessage.bind(this); //this.onMessage = this.onMessage.bind(this);
this.rolesCache = new MemorySingleCache<Role[]>(1000 * 60 * 60 * 1); this.rolesCache = new MemorySingleCache<MiRole[]>(1000 * 60 * 60 * 1);
this.roleAssignmentByUserIdCache = new MemoryKVCache<RoleAssignment[]>(1000 * 60 * 60 * 1); this.roleAssignmentByUserIdCache = new MemoryKVCache<MiRoleAssignment[]>(1000 * 60 * 60 * 1);
this.redisForSub.on('message', this.onMessage); this.redisForSub.on('message', this.onMessage);
} }
@ -173,7 +173,7 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
private evalCond(user: User, value: RoleCondFormulaValue): boolean { private evalCond(user: MiUser, value: RoleCondFormulaValue): boolean {
try { try {
switch (value.type) { switch (value.type) {
case 'and': { case 'and': {
@ -225,7 +225,7 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async getUserAssigns(userId: User['id']) { public async getUserAssigns(userId: MiUser['id']) {
const now = Date.now(); const now = Date.now();
let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId })); let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId }));
// 期限切れのロールを除外 // 期限切れのロールを除外
@ -234,7 +234,7 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async getUserRoles(userId: User['id']) { public async getUserRoles(userId: MiUser['id']) {
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({})); const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
const assigns = await this.getUserAssigns(userId); const assigns = await this.getUserAssigns(userId);
const assignedRoles = roles.filter(r => assigns.map(x => x.roleId).includes(r.id)); const assignedRoles = roles.filter(r => assigns.map(x => x.roleId).includes(r.id));
@ -247,7 +247,7 @@ export class RoleService implements OnApplicationShutdown {
* *
*/ */
@bindThis @bindThis
public async getUserBadgeRoles(userId: User['id']) { public async getUserBadgeRoles(userId: MiUser['id']) {
const now = Date.now(); const now = Date.now();
let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId })); let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId }));
// 期限切れのロールを除外 // 期限切れのロールを除外
@ -266,7 +266,7 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async getUserPolicies(userId: User['id'] | null): Promise<RolePolicies> { public async getUserPolicies(userId: MiUser['id'] | null): Promise<RolePolicies> {
const meta = await this.metaService.fetch(); const meta = await this.metaService.fetch();
const basePolicies = { ...DEFAULT_POLICIES, ...meta.policies }; const basePolicies = { ...DEFAULT_POLICIES, ...meta.policies };
@ -314,19 +314,19 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async isModerator(user: { id: User['id']; isRoot: User['isRoot'] } | null): Promise<boolean> { public async isModerator(user: { id: MiUser['id']; isRoot: MiUser['isRoot'] } | null): Promise<boolean> {
if (user == null) return false; if (user == null) return false;
return user.isRoot || (await this.getUserRoles(user.id)).some(r => r.isModerator || r.isAdministrator); return user.isRoot || (await this.getUserRoles(user.id)).some(r => r.isModerator || r.isAdministrator);
} }
@bindThis @bindThis
public async isAdministrator(user: { id: User['id']; isRoot: User['isRoot'] } | null): Promise<boolean> { public async isAdministrator(user: { id: MiUser['id']; isRoot: MiUser['isRoot'] } | null): Promise<boolean> {
if (user == null) return false; if (user == null) return false;
return user.isRoot || (await this.getUserRoles(user.id)).some(r => r.isAdministrator); return user.isRoot || (await this.getUserRoles(user.id)).some(r => r.isAdministrator);
} }
@bindThis @bindThis
public async isExplorable(role: { id: Role['id']} | null): Promise<boolean> { public async isExplorable(role: { id: MiRole['id']} | null): Promise<boolean> {
if (role == null) return false; if (role == null) return false;
const check = await this.rolesRepository.findOneBy({ id: role.id }); const check = await this.rolesRepository.findOneBy({ id: role.id });
if (check == null) return false; if (check == null) return false;
@ -334,7 +334,7 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async getModeratorIds(includeAdmins = true): Promise<User['id'][]> { public async getModeratorIds(includeAdmins = true): Promise<MiUser['id'][]> {
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({})); const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
const moderatorRoles = includeAdmins ? roles.filter(r => r.isModerator || r.isAdministrator) : roles.filter(r => r.isModerator); const moderatorRoles = includeAdmins ? roles.filter(r => r.isModerator || r.isAdministrator) : roles.filter(r => r.isModerator);
const assigns = moderatorRoles.length > 0 ? await this.roleAssignmentsRepository.findBy({ const assigns = moderatorRoles.length > 0 ? await this.roleAssignmentsRepository.findBy({
@ -345,7 +345,7 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async getModerators(includeAdmins = true): Promise<User[]> { public async getModerators(includeAdmins = true): Promise<MiUser[]> {
const ids = await this.getModeratorIds(includeAdmins); const ids = await this.getModeratorIds(includeAdmins);
const users = ids.length > 0 ? await this.usersRepository.findBy({ const users = ids.length > 0 ? await this.usersRepository.findBy({
id: In(ids), id: In(ids),
@ -354,7 +354,7 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async getAdministratorIds(): Promise<User['id'][]> { public async getAdministratorIds(): Promise<MiUser['id'][]> {
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({})); const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
const administratorRoles = roles.filter(r => r.isAdministrator); const administratorRoles = roles.filter(r => r.isAdministrator);
const assigns = administratorRoles.length > 0 ? await this.roleAssignmentsRepository.findBy({ const assigns = administratorRoles.length > 0 ? await this.roleAssignmentsRepository.findBy({
@ -365,7 +365,7 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async getAdministrators(): Promise<User[]> { public async getAdministrators(): Promise<MiUser[]> {
const ids = await this.getAdministratorIds(); const ids = await this.getAdministratorIds();
const users = ids.length > 0 ? await this.usersRepository.findBy({ const users = ids.length > 0 ? await this.usersRepository.findBy({
id: In(ids), id: In(ids),
@ -374,7 +374,7 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async assign(userId: User['id'], roleId: Role['id'], expiresAt: Date | null = null): Promise<void> { public async assign(userId: MiUser['id'], roleId: MiRole['id'], expiresAt: Date | null = null): Promise<void> {
const now = new Date(); const now = new Date();
const existing = await this.roleAssignmentsRepository.findOneBy({ const existing = await this.roleAssignmentsRepository.findOneBy({
@ -409,7 +409,7 @@ export class RoleService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async unassign(userId: User['id'], roleId: Role['id']): Promise<void> { public async unassign(userId: MiUser['id'], roleId: MiRole['id']): Promise<void> {
const now = new Date(); const now = new Date();
const existing = await this.roleAssignmentsRepository.findOneBy({ roleId, userId }); const existing = await this.roleAssignmentsRepository.findOneBy({ roleId, userId });

View File

@ -10,7 +10,7 @@ import { Injectable } from '@nestjs/common';
import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3'; import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage'; import { Upload } from '@aws-sdk/lib-storage';
import { NodeHttpHandler, NodeHttpHandlerOptions } from '@aws-sdk/node-http-handler'; import { NodeHttpHandler, NodeHttpHandlerOptions } from '@aws-sdk/node-http-handler';
import type { Meta } from '@/models/entities/Meta.js'; import type { MiMeta } from '@/models/entities/Meta.js';
import { HttpRequestService } from '@/core/HttpRequestService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type { DeleteObjectCommandInput, PutObjectCommandInput } from '@aws-sdk/client-s3'; import type { DeleteObjectCommandInput, PutObjectCommandInput } from '@aws-sdk/client-s3';
@ -23,7 +23,7 @@ export class S3Service {
} }
@bindThis @bindThis
public getS3Client(meta: Meta): S3Client { public getS3Client(meta: MiMeta): S3Client {
const u = meta.objectStorageEndpoint const u = meta.objectStorageEndpoint
? `${meta.objectStorageUseSSL ? 'https' : 'http'}://${meta.objectStorageEndpoint}` ? `${meta.objectStorageUseSSL ? 'https' : 'http'}://${meta.objectStorageEndpoint}`
: `${meta.objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent : `${meta.objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent
@ -50,7 +50,7 @@ export class S3Service {
} }
@bindThis @bindThis
public async upload(meta: Meta, input: PutObjectCommandInput) { public async upload(meta: MiMeta, input: PutObjectCommandInput) {
const client = this.getS3Client(meta); const client = this.getS3Client(meta);
return new Upload({ return new Upload({
client, client,
@ -62,7 +62,7 @@ export class S3Service {
} }
@bindThis @bindThis
public delete(meta: Meta, input: DeleteObjectCommandInput) { public delete(meta: MiMeta, input: DeleteObjectCommandInput) {
const client = this.getS3Client(meta); const client = this.getS3Client(meta);
return client.send(new DeleteObjectCommand(input)); return client.send(new DeleteObjectCommand(input));
} }

View File

@ -8,8 +8,8 @@ import { In } from 'typeorm';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { Note } from '@/models/entities/Note.js'; import { MiNote } from '@/models/entities/Note.js';
import { User } from '@/models/index.js'; import { MiUser } from '@/models/index.js';
import type { NotesRepository } from '@/models/index.js'; import type { NotesRepository } from '@/models/index.js';
import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
import { QueryService } from '@/core/QueryService.js'; import { QueryService } from '@/core/QueryService.js';
@ -25,6 +25,8 @@ type Q =
{ op: '<', k: K, v: number } | { op: '<', k: K, v: number } |
{ op: '>=', k: K, v: number } | { op: '>=', k: K, v: number } |
{ op: '<=', k: K, v: number } | { op: '<=', k: K, v: number } |
{ op: 'is null', k: K} |
{ op: 'is not null', k: K} |
{ op: 'and', qs: Q[] } | { op: 'and', qs: Q[] } |
{ op: 'or', qs: Q[] } | { op: 'or', qs: Q[] } |
{ op: 'not', q: Q }; { op: 'not', q: Q };
@ -50,6 +52,8 @@ function compileQuery(q: Q): string {
case '<=': return `(${q.k} <= ${compileValue(q.v)})`; case '<=': return `(${q.k} <= ${compileValue(q.v)})`;
case 'and': return q.qs.length === 0 ? '' : `(${ q.qs.map(_q => compileQuery(_q)).join(' AND ') })`; case 'and': return q.qs.length === 0 ? '' : `(${ q.qs.map(_q => compileQuery(_q)).join(' AND ') })`;
case 'or': return q.qs.length === 0 ? '' : `(${ q.qs.map(_q => compileQuery(_q)).join(' OR ') })`; case 'or': return q.qs.length === 0 ? '' : `(${ q.qs.map(_q => compileQuery(_q)).join(' OR ') })`;
case 'is null': return `(${q.k} IS NULL)`;
case 'is not null': return `(${q.k} IS NOT NULL)`;
case 'not': return `(NOT ${compileQuery(q.q)})`; case 'not': return `(NOT ${compileQuery(q.q)})`;
default: throw new Error('unrecognized query operator'); default: throw new Error('unrecognized query operator');
} }
@ -105,7 +109,7 @@ export class SearchService {
} }
@bindThis @bindThis
public async indexNote(note: Note): Promise<void> { public async indexNote(note: MiNote): Promise<void> {
if (note.text == null && note.cw == null) return; if (note.text == null && note.cw == null) return;
if (!['home', 'public'].includes(note.visibility)) return; if (!['home', 'public'].includes(note.visibility)) return;
@ -141,7 +145,7 @@ export class SearchService {
} }
@bindThis @bindThis
public async unindexNote(note: Note): Promise<void> { public async unindexNote(note: MiNote): Promise<void> {
if (!['home', 'public'].includes(note.visibility)) return; if (!['home', 'public'].includes(note.visibility)) return;
if (this.meilisearch) { if (this.meilisearch) {
@ -150,15 +154,15 @@ export class SearchService {
} }
@bindThis @bindThis
public async searchNote(q: string, me: User | null, opts: { public async searchNote(q: string, me: MiUser | null, opts: {
userId?: Note['userId'] | null; userId?: MiNote['userId'] | null;
channelId?: Note['channelId'] | null; channelId?: MiNote['channelId'] | null;
host?: string | null; host?: string | null;
}, pagination: { }, pagination: {
untilId?: Note['id']; untilId?: MiNote['id'];
sinceId?: Note['id']; sinceId?: MiNote['id'];
limit?: number; limit?: number;
}): Promise<Note[]> { }): Promise<MiNote[]> {
if (this.meilisearch) { if (this.meilisearch) {
const filter: Q = { const filter: Q = {
op: 'and', op: 'and',
@ -170,7 +174,7 @@ export class SearchService {
if (opts.channelId) filter.qs.push({ op: '=', k: 'channelId', v: opts.channelId }); if (opts.channelId) filter.qs.push({ op: '=', k: 'channelId', v: opts.channelId });
if (opts.host) { if (opts.host) {
if (opts.host === '.') { if (opts.host === '.') {
// TODO: Meilisearchが2023/05/07現在値がNULLかどうかのクエリが書けない filter.qs.push({ op: 'is null', k: 'userHost' });
} else { } else {
filter.qs.push({ op: '=', k: 'userHost', v: opts.host }); filter.qs.push({ op: '=', k: 'userHost', v: opts.host });
} }
@ -204,6 +208,14 @@ export class SearchService {
.leftJoinAndSelect('reply.user', 'replyUser') .leftJoinAndSelect('reply.user', 'replyUser')
.leftJoinAndSelect('renote.user', 'renoteUser'); .leftJoinAndSelect('renote.user', 'renoteUser');
if (opts.host) {
if (opts.host === '.') {
query.andWhere('user.host IS NULL');
} else {
query.andWhere('user.host = :host', { host: opts.host });
}
}
this.queryService.generateVisibilityQuery(query, me); this.queryService.generateVisibilityQuery(query, me);
if (me) this.queryService.generateMutedUserQuery(query, me); if (me) this.queryService.generateMutedUserQuery(query, me);
if (me) this.queryService.generateBlockedUserQuery(query, me); if (me) this.queryService.generateBlockedUserQuery(query, me);

View File

@ -9,11 +9,11 @@ import bcrypt from 'bcryptjs';
import { DataSource, IsNull } from 'typeorm'; import { DataSource, IsNull } from 'typeorm';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { UsedUsernamesRepository, UsersRepository } from '@/models/index.js'; import type { UsedUsernamesRepository, UsersRepository } from '@/models/index.js';
import { User } from '@/models/entities/User.js'; import { MiUser } from '@/models/entities/User.js';
import { UserProfile } from '@/models/entities/UserProfile.js'; import { MiUserProfile } from '@/models/entities/UserProfile.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { UserKeypair } from '@/models/entities/UserKeypair.js'; import { MiUserKeypair } from '@/models/entities/UserKeypair.js';
import { UsedUsername } from '@/models/entities/UsedUsername.js'; import { MiUsedUsername } from '@/models/entities/UsedUsername.js';
import generateUserToken from '@/misc/generate-native-user-token.js'; import generateUserToken from '@/misc/generate-native-user-token.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -43,9 +43,9 @@ export class SignupService {
@bindThis @bindThis
public async signup(opts: { public async signup(opts: {
username: User['username']; username: MiUser['username'];
password?: string | null; password?: string | null;
passwordHash?: UserProfile['password'] | null; passwordHash?: MiUserProfile['password'] | null;
host?: string | null; host?: string | null;
ignorePreservedUsernames?: boolean; ignorePreservedUsernames?: boolean;
}) { }) {
@ -108,18 +108,18 @@ export class SignupService {
err ? rej(err) : res([publicKey, privateKey]), err ? rej(err) : res([publicKey, privateKey]),
)); ));
let account!: User; let account!: MiUser;
// Start transaction // Start transaction
await this.db.transaction(async transactionalEntityManager => { await this.db.transaction(async transactionalEntityManager => {
const exist = await transactionalEntityManager.findOneBy(User, { const exist = await transactionalEntityManager.findOneBy(MiUser, {
usernameLower: username.toLowerCase(), usernameLower: username.toLowerCase(),
host: IsNull(), host: IsNull(),
}); });
if (exist) throw new Error(' the username is already used'); if (exist) throw new Error(' the username is already used');
account = await transactionalEntityManager.save(new User({ account = await transactionalEntityManager.save(new MiUser({
id: this.idService.genId(), id: this.idService.genId(),
createdAt: new Date(), createdAt: new Date(),
username: username, username: username,
@ -129,19 +129,19 @@ export class SignupService {
isRoot: isTheFirstUser, isRoot: isTheFirstUser,
})); }));
await transactionalEntityManager.save(new UserKeypair({ await transactionalEntityManager.save(new MiUserKeypair({
publicKey: keyPair[0], publicKey: keyPair[0],
privateKey: keyPair[1], privateKey: keyPair[1],
userId: account.id, userId: account.id,
})); }));
await transactionalEntityManager.save(new UserProfile({ await transactionalEntityManager.save(new MiUserProfile({
userId: account.id, userId: account.id,
autoAcceptFollowed: true, autoAcceptFollowed: true,
password: hash, password: hash,
})); }));
await transactionalEntityManager.save(new UsedUsername({ await transactionalEntityManager.save(new MiUsedUsername({
createdAt: new Date(), createdAt: new Date(),
username: username.toLowerCase(), username: username.toLowerCase(),
})); }));

View File

@ -6,8 +6,8 @@
import { Inject, Injectable, OnModuleInit } from '@nestjs/common'; import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core'; import { ModuleRef } from '@nestjs/core';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import type { Blocking } from '@/models/entities/Blocking.js'; import type { MiBlocking } from '@/models/entities/Blocking.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -58,7 +58,7 @@ export class UserBlockingService implements OnModuleInit {
} }
@bindThis @bindThis
public async block(blocker: User, blockee: User, silent = false) { public async block(blocker: MiUser, blockee: MiUser, silent = false) {
await Promise.all([ await Promise.all([
this.cancelRequest(blocker, blockee, silent), this.cancelRequest(blocker, blockee, silent),
this.cancelRequest(blockee, blocker, silent), this.cancelRequest(blockee, blocker, silent),
@ -74,7 +74,7 @@ export class UserBlockingService implements OnModuleInit {
blockerId: blocker.id, blockerId: blocker.id,
blockee, blockee,
blockeeId: blockee.id, blockeeId: blockee.id,
} as Blocking; } as MiBlocking;
await this.blockingsRepository.insert(blocking); await this.blockingsRepository.insert(blocking);
@ -93,7 +93,7 @@ export class UserBlockingService implements OnModuleInit {
} }
@bindThis @bindThis
private async cancelRequest(follower: User, followee: User, silent = false) { private async cancelRequest(follower: MiUser, followee: MiUser, silent = false) {
const request = await this.followRequestsRepository.findOneBy({ const request = await this.followRequestsRepository.findOneBy({
followeeId: followee.id, followeeId: followee.id,
followerId: follower.id, followerId: follower.id,
@ -143,7 +143,7 @@ export class UserBlockingService implements OnModuleInit {
} }
@bindThis @bindThis
private async removeFromList(listOwner: User, user: User) { private async removeFromList(listOwner: MiUser, user: MiUser) {
const userLists = await this.userListsRepository.findBy({ const userLists = await this.userListsRepository.findBy({
userId: listOwner.id, userId: listOwner.id,
}); });
@ -157,7 +157,7 @@ export class UserBlockingService implements OnModuleInit {
} }
@bindThis @bindThis
public async unblock(blocker: User, blockee: User) { public async unblock(blocker: MiUser, blockee: MiUser) {
const blocking = await this.blockingsRepository.findOneBy({ const blocking = await this.blockingsRepository.findOneBy({
blockerId: blocker.id, blockerId: blocker.id,
blockeeId: blockee.id, blockeeId: blockee.id,
@ -191,7 +191,7 @@ export class UserBlockingService implements OnModuleInit {
} }
@bindThis @bindThis
public async checkBlocked(blockerId: User['id'], blockeeId: User['id']): Promise<boolean> { public async checkBlocked(blockerId: MiUser['id'], blockeeId: MiUser['id']): Promise<boolean> {
return (await this.cacheService.userBlockingCache.fetch(blockerId)).has(blockeeId); return (await this.cacheService.userBlockingCache.fetch(blockerId)).has(blockeeId);
} }
} }

View File

@ -6,7 +6,7 @@
import { Inject, Injectable, OnModuleInit, forwardRef } from '@nestjs/common'; import { Inject, Injectable, OnModuleInit, forwardRef } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core'; import { ModuleRef } from '@nestjs/core';
import { IsNull } from 'typeorm'; import { IsNull } from 'typeorm';
import type { LocalUser, PartialLocalUser, PartialRemoteUser, RemoteUser, User } from '@/models/entities/User.js'; import type { MiLocalUser, MiPartialLocalUser, MiPartialRemoteUser, MiRemoteUser, MiUser } from '@/models/entities/User.js';
import { IdentifiableError } from '@/misc/identifiable-error.js'; import { IdentifiableError } from '@/misc/identifiable-error.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js'; import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
@ -32,16 +32,16 @@ import Logger from '../logger.js';
const logger = new Logger('following/create'); const logger = new Logger('following/create');
type Local = LocalUser | { type Local = MiLocalUser | {
id: LocalUser['id']; id: MiLocalUser['id'];
host: LocalUser['host']; host: MiLocalUser['host'];
uri: LocalUser['uri'] uri: MiLocalUser['uri']
}; };
type Remote = RemoteUser | { type Remote = MiRemoteUser | {
id: RemoteUser['id']; id: MiRemoteUser['id'];
host: RemoteUser['host']; host: MiRemoteUser['host'];
uri: RemoteUser['uri']; uri: MiRemoteUser['uri'];
inbox: RemoteUser['inbox']; inbox: MiRemoteUser['inbox'];
}; };
type Both = Local | Remote; type Both = Local | Remote;
@ -91,11 +91,11 @@ export class UserFollowingService implements OnModuleInit {
} }
@bindThis @bindThis
public async follow(_follower: { id: User['id'] }, _followee: { id: User['id'] }, requestId?: string, silent = false): Promise<void> { public async follow(_follower: { id: MiUser['id'] }, _followee: { id: MiUser['id'] }, requestId?: string, silent = false): Promise<void> {
const [follower, followee] = await Promise.all([ const [follower, followee] = await Promise.all([
this.usersRepository.findOneByOrFail({ id: _follower.id }), this.usersRepository.findOneByOrFail({ id: _follower.id }),
this.usersRepository.findOneByOrFail({ id: _followee.id }), this.usersRepository.findOneByOrFail({ id: _followee.id }),
]) as [LocalUser | RemoteUser, LocalUser | RemoteUser]; ]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser];
// check blocking // check blocking
const [blocking, blocked] = await Promise.all([ const [blocking, blocked] = await Promise.all([
@ -180,10 +180,10 @@ export class UserFollowingService implements OnModuleInit {
@bindThis @bindThis
private async insertFollowingDoc( private async insertFollowingDoc(
followee: { followee: {
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'] id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox']
}, },
follower: { follower: {
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'] id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox']
}, },
silent = false, silent = false,
): Promise<void> { ): Promise<void> {
@ -312,10 +312,10 @@ export class UserFollowingService implements OnModuleInit {
@bindThis @bindThis
public async unfollow( public async unfollow(
follower: { follower: {
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
}, },
followee: { followee: {
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
}, },
silent = false, silent = false,
): Promise<void> { ): Promise<void> {
@ -358,21 +358,21 @@ export class UserFollowingService implements OnModuleInit {
} }
if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower as PartialLocalUser, followee as PartialRemoteUser), follower)); const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower as MiPartialLocalUser, followee as MiPartialRemoteUser), follower));
this.queueService.deliver(follower, content, followee.inbox, false); this.queueService.deliver(follower, content, followee.inbox, false);
} }
if (this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower)) { if (this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower)) {
// local user has null host // local user has null host
const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower as PartialRemoteUser, followee as PartialLocalUser), followee)); const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower as MiPartialRemoteUser, followee as MiPartialLocalUser), followee));
this.queueService.deliver(followee, content, follower.inbox, false); this.queueService.deliver(followee, content, follower.inbox, false);
} }
} }
@bindThis @bindThis
private async decrementFollowing( private async decrementFollowing(
follower: User, follower: MiUser,
followee: User, followee: MiUser,
): Promise<void> { ): Promise<void> {
this.globalEventService.publishInternalEvent('unfollow', { followerId: follower.id, followeeId: followee.id }); this.globalEventService.publishInternalEvent('unfollow', { followerId: follower.id, followeeId: followee.id });
@ -444,10 +444,10 @@ export class UserFollowingService implements OnModuleInit {
@bindThis @bindThis
public async createFollowRequest( public async createFollowRequest(
follower: { follower: {
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
}, },
followee: { followee: {
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
}, },
requestId?: string, requestId?: string,
): Promise<void> { ): Promise<void> {
@ -494,7 +494,7 @@ export class UserFollowingService implements OnModuleInit {
} }
if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
const content = this.apRendererService.addContext(this.apRendererService.renderFollow(follower as PartialLocalUser, followee as PartialRemoteUser, requestId ?? `${this.config.url}/follows/${followRequest.id}`)); const content = this.apRendererService.addContext(this.apRendererService.renderFollow(follower as MiPartialLocalUser, followee as MiPartialRemoteUser, requestId ?? `${this.config.url}/follows/${followRequest.id}`));
this.queueService.deliver(follower, content, followee.inbox, false); this.queueService.deliver(follower, content, followee.inbox, false);
} }
} }
@ -502,14 +502,14 @@ export class UserFollowingService implements OnModuleInit {
@bindThis @bindThis
public async cancelFollowRequest( public async cancelFollowRequest(
followee: { followee: {
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox'] id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']
}, },
follower: { follower: {
id: User['id']; host: User['host']; uri: User['host'] id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']
}, },
): Promise<void> { ): Promise<void> {
if (this.userEntityService.isRemoteUser(followee)) { if (this.userEntityService.isRemoteUser(followee)) {
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower as PartialLocalUser | PartialRemoteUser, followee as PartialRemoteUser), follower)); const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower as MiPartialLocalUser | MiPartialRemoteUser, followee as MiPartialRemoteUser), follower));
if (this.userEntityService.isLocalUser(follower)) { // 本来このチェックは不要だけどTSに怒られるので if (this.userEntityService.isLocalUser(follower)) { // 本来このチェックは不要だけどTSに怒られるので
this.queueService.deliver(follower, content, followee.inbox, false); this.queueService.deliver(follower, content, followee.inbox, false);
@ -540,9 +540,9 @@ export class UserFollowingService implements OnModuleInit {
@bindThis @bindThis
public async acceptFollowRequest( public async acceptFollowRequest(
followee: { followee: {
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
}, },
follower: User, follower: MiUser,
): Promise<void> { ): Promise<void> {
const request = await this.followRequestsRepository.findOneBy({ const request = await this.followRequestsRepository.findOneBy({
followeeId: followee.id, followeeId: followee.id,
@ -556,7 +556,7 @@ export class UserFollowingService implements OnModuleInit {
await this.insertFollowingDoc(followee, follower); await this.insertFollowingDoc(followee, follower);
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee as PartialLocalUser, request.requestId!), 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.queueService.deliver(followee, content, follower.inbox, false);
} }
@ -568,7 +568,7 @@ export class UserFollowingService implements OnModuleInit {
@bindThis @bindThis
public async acceptAllFollowRequests( public async acceptAllFollowRequests(
user: { user: {
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
}, },
): Promise<void> { ): Promise<void> {
const requests = await this.followRequestsRepository.findBy({ const requests = await this.followRequestsRepository.findBy({

View File

@ -5,16 +5,16 @@
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import type { UserKeypairsRepository } from '@/models/index.js'; import type { UserKeypairsRepository } from '@/models/index.js';
import { RedisKVCache } from '@/misc/cache.js'; import { RedisKVCache } from '@/misc/cache.js';
import type { UserKeypair } from '@/models/entities/UserKeypair.js'; import type { MiUserKeypair } from '@/models/entities/UserKeypair.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@Injectable() @Injectable()
export class UserKeypairService implements OnApplicationShutdown { export class UserKeypairService implements OnApplicationShutdown {
private cache: RedisKVCache<UserKeypair>; private cache: RedisKVCache<MiUserKeypair>;
constructor( constructor(
@Inject(DI.redis) @Inject(DI.redis)
@ -23,7 +23,7 @@ export class UserKeypairService implements OnApplicationShutdown {
@Inject(DI.userKeypairsRepository) @Inject(DI.userKeypairsRepository)
private userKeypairsRepository: UserKeypairsRepository, private userKeypairsRepository: UserKeypairsRepository,
) { ) {
this.cache = new RedisKVCache<UserKeypair>(this.redisClient, 'userKeypair', { this.cache = new RedisKVCache<MiUserKeypair>(this.redisClient, 'userKeypair', {
lifetime: 1000 * 60 * 60 * 24, // 24h lifetime: 1000 * 60 * 60 * 24, // 24h
memoryCacheLifetime: Infinity, memoryCacheLifetime: Infinity,
fetcher: (key) => this.userKeypairsRepository.findOneByOrFail({ userId: key }), fetcher: (key) => this.userKeypairsRepository.findOneByOrFail({ userId: key }),
@ -33,7 +33,7 @@ export class UserKeypairService implements OnApplicationShutdown {
} }
@bindThis @bindThis
public async getUserKeypair(userId: User['id']): Promise<UserKeypair> { public async getUserKeypair(userId: MiUser['id']): Promise<MiUserKeypair> {
return await this.cache.fetch(userId); return await this.cache.fetch(userId);
} }

View File

@ -5,9 +5,9 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import type { UserListJoiningsRepository } from '@/models/index.js'; import type { UserListJoiningsRepository } from '@/models/index.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import type { UserList } from '@/models/entities/UserList.js'; import type { MiUserList } from '@/models/entities/UserList.js';
import type { UserListJoining } from '@/models/entities/UserListJoining.js'; import type { MiUserListJoining } from '@/models/entities/UserListJoining.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -35,7 +35,7 @@ export class UserListService {
} }
@bindThis @bindThis
public async push(target: User, list: UserList, me: User) { public async push(target: MiUser, list: MiUserList, me: MiUser) {
const currentCount = await this.userListJoiningsRepository.countBy({ const currentCount = await this.userListJoiningsRepository.countBy({
userListId: list.id, userListId: list.id,
}); });
@ -48,7 +48,7 @@ export class UserListService {
createdAt: new Date(), createdAt: new Date(),
userId: target.id, userId: target.id,
userListId: list.id, userListId: list.id,
} as UserListJoining); } as MiUserListJoining);
this.globalEventService.publishUserListStream(list.id, 'userAdded', await this.userEntityService.pack(target)); this.globalEventService.publishUserListStream(list.id, 'userAdded', await this.userEntityService.pack(target));

View File

@ -5,9 +5,9 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { In } from 'typeorm'; import { In } from 'typeorm';
import type { MutingsRepository, Muting } from '@/models/index.js'; import type { MutingsRepository, MiMuting } from '@/models/index.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { CacheService } from '@/core/CacheService.js'; import { CacheService } from '@/core/CacheService.js';
@ -24,7 +24,7 @@ export class UserMutingService {
} }
@bindThis @bindThis
public async mute(user: User, target: User, expiresAt: Date | null = null): Promise<void> { public async mute(user: MiUser, target: MiUser, expiresAt: Date | null = null): Promise<void> {
await this.mutingsRepository.insert({ await this.mutingsRepository.insert({
id: this.idService.genId(), id: this.idService.genId(),
createdAt: new Date(), createdAt: new Date(),
@ -37,7 +37,7 @@ export class UserMutingService {
} }
@bindThis @bindThis
public async unmute(mutings: Muting[]): Promise<void> { public async unmute(mutings: MiMuting[]): Promise<void> {
if (mutings.length === 0) return; if (mutings.length === 0) return;
await this.mutingsRepository.delete({ await this.mutingsRepository.delete({

View File

@ -6,7 +6,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Not, IsNull } from 'typeorm'; import { Not, IsNull } from 'typeorm';
import type { FollowingsRepository } from '@/models/index.js'; import type { FollowingsRepository } from '@/models/index.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -28,7 +28,7 @@ export class UserSuspendService {
} }
@bindThis @bindThis
public async doPostSuspend(user: { id: User['id']; host: User['host'] }): Promise<void> { public async doPostSuspend(user: { id: MiUser['id']; host: MiUser['host'] }): Promise<void> {
this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true }); this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true });
if (this.userEntityService.isLocalUser(user)) { if (this.userEntityService.isLocalUser(user)) {
@ -58,7 +58,7 @@ export class UserSuspendService {
} }
@bindThis @bindThis
public async doPostUnsuspend(user: User): Promise<void> { public async doPostUnsuspend(user: MiUser): Promise<void> {
this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: false }); this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: false });
if (this.userEntityService.isLocalUser(user)) { if (this.userEntityService.isLocalUser(user)) {

View File

@ -6,7 +6,7 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import type { WebhooksRepository } from '@/models/index.js'; import type { WebhooksRepository } from '@/models/index.js';
import type { Webhook } from '@/models/entities/Webhook.js'; import type { MiWebhook } from '@/models/entities/Webhook.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { StreamMessages } from '@/server/api/stream/types.js'; import { StreamMessages } from '@/server/api/stream/types.js';
@ -15,7 +15,7 @@ import type { OnApplicationShutdown } from '@nestjs/common';
@Injectable() @Injectable()
export class WebhookService implements OnApplicationShutdown { export class WebhookService implements OnApplicationShutdown {
private webhooksFetched = false; private webhooksFetched = false;
private webhooks: Webhook[] = []; private webhooks: MiWebhook[] = [];
constructor( constructor(
@Inject(DI.redisForSub) @Inject(DI.redisForSub)

View File

@ -5,7 +5,7 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import promiseLimit from 'promise-limit'; import promiseLimit from 'promise-limit';
import type { RemoteUser, User } from '@/models/entities/User.js'; import type { MiRemoteUser, MiUser } from '@/models/entities/User.js';
import { concat, unique } from '@/misc/prelude/array.js'; import { concat, unique } from '@/misc/prelude/array.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { getApIds } from './type.js'; import { getApIds } from './type.js';
@ -17,8 +17,8 @@ type Visibility = 'public' | 'home' | 'followers' | 'specified';
type AudienceInfo = { type AudienceInfo = {
visibility: Visibility, visibility: Visibility,
mentionedUsers: User[], mentionedUsers: MiUser[],
visibleUsers: User[], visibleUsers: MiUser[],
}; };
type GroupedAudience = Record<'public' | 'followers' | 'other', string[]>; type GroupedAudience = Record<'public' | 'followers' | 'other', string[]>;
@ -31,16 +31,16 @@ export class ApAudienceService {
} }
@bindThis @bindThis
public async parseAudience(actor: RemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise<AudienceInfo> { public async parseAudience(actor: MiRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise<AudienceInfo> {
const toGroups = this.groupingAudience(getApIds(to), actor); const toGroups = this.groupingAudience(getApIds(to), actor);
const ccGroups = this.groupingAudience(getApIds(cc), actor); const ccGroups = this.groupingAudience(getApIds(cc), actor);
const others = unique(concat([toGroups.other, ccGroups.other])); const others = unique(concat([toGroups.other, ccGroups.other]));
const limit = promiseLimit<User | null>(2); const limit = promiseLimit<MiUser | null>(2);
const mentionedUsers = (await Promise.all( const mentionedUsers = (await Promise.all(
others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))), others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))),
)).filter((x): x is User => x != null); )).filter((x): x is MiUser => x != null);
if (toGroups.public.length > 0) { if (toGroups.public.length > 0) {
return { return {
@ -74,7 +74,7 @@ export class ApAudienceService {
} }
@bindThis @bindThis
private groupingAudience(ids: string[], actor: RemoteUser): GroupedAudience { private groupingAudience(ids: string[], actor: MiRemoteUser): GroupedAudience {
const groups: GroupedAudience = { const groups: GroupedAudience = {
public: [], public: [],
followers: [], followers: [],
@ -106,7 +106,7 @@ export class ApAudienceService {
} }
@bindThis @bindThis
private isFollowers(id: string, actor: RemoteUser): boolean { private isFollowers(id: string, actor: MiRemoteUser): boolean {
return id === (actor.followersUri ?? `${actor.uri}/followers`); return id === (actor.followersUri ?? `${actor.uri}/followers`);
} }
} }

View File

@ -8,11 +8,11 @@ import { DI } from '@/di-symbols.js';
import type { NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js'; import type { NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { MemoryKVCache } from '@/misc/cache.js'; import { MemoryKVCache } from '@/misc/cache.js';
import type { UserPublickey } from '@/models/entities/UserPublickey.js'; import type { MiUserPublickey } from '@/models/entities/UserPublickey.js';
import { CacheService } from '@/core/CacheService.js'; import { CacheService } from '@/core/CacheService.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { LocalUser, RemoteUser } from '@/models/entities/User.js'; import { MiLocalUser, MiRemoteUser } from '@/models/entities/User.js';
import { getApId } from './type.js'; import { getApId } from './type.js';
import { ApPersonService } from './models/ApPersonService.js'; import { ApPersonService } from './models/ApPersonService.js';
import type { IObject } from './type.js'; import type { IObject } from './type.js';
@ -35,8 +35,8 @@ export type UriParseResult = {
@Injectable() @Injectable()
export class ApDbResolverService implements OnApplicationShutdown { export class ApDbResolverService implements OnApplicationShutdown {
private publicKeyCache: MemoryKVCache<UserPublickey | null>; private publicKeyCache: MemoryKVCache<MiUserPublickey | null>;
private publicKeyByUserIdCache: MemoryKVCache<UserPublickey | null>; private publicKeyByUserIdCache: MemoryKVCache<MiUserPublickey | null>;
constructor( constructor(
@Inject(DI.config) @Inject(DI.config)
@ -54,8 +54,8 @@ export class ApDbResolverService implements OnApplicationShutdown {
private cacheService: CacheService, private cacheService: CacheService,
private apPersonService: ApPersonService, private apPersonService: ApPersonService,
) { ) {
this.publicKeyCache = new MemoryKVCache<UserPublickey | null>(Infinity); this.publicKeyCache = new MemoryKVCache<MiUserPublickey | null>(Infinity);
this.publicKeyByUserIdCache = new MemoryKVCache<UserPublickey | null>(Infinity); this.publicKeyByUserIdCache = new MemoryKVCache<MiUserPublickey | null>(Infinity);
} }
@bindThis @bindThis
@ -78,7 +78,7 @@ export class ApDbResolverService implements OnApplicationShutdown {
* AP Note => Misskey Note in DB * AP Note => Misskey Note in DB
*/ */
@bindThis @bindThis
public async getNoteFromApId(value: string | IObject): Promise<Note | null> { public async getNoteFromApId(value: string | IObject): Promise<MiNote | null> {
const parsed = this.parseUri(value); const parsed = this.parseUri(value);
if (parsed.local) { if (parsed.local) {
@ -98,7 +98,7 @@ export class ApDbResolverService implements OnApplicationShutdown {
* AP Person => Misskey User in DB * AP Person => Misskey User in DB
*/ */
@bindThis @bindThis
public async getUserFromApId(value: string | IObject): Promise<LocalUser | RemoteUser | null> { public async getUserFromApId(value: string | IObject): Promise<MiLocalUser | MiRemoteUser | null> {
const parsed = this.parseUri(value); const parsed = this.parseUri(value);
if (parsed.local) { if (parsed.local) {
@ -107,12 +107,12 @@ export class ApDbResolverService implements OnApplicationShutdown {
return await this.cacheService.userByIdCache.fetchMaybe( return await this.cacheService.userByIdCache.fetchMaybe(
parsed.id, parsed.id,
() => this.usersRepository.findOneBy({ id: parsed.id }).then(x => x ?? undefined), () => this.usersRepository.findOneBy({ id: parsed.id }).then(x => x ?? undefined),
) as LocalUser | undefined ?? null; ) as MiLocalUser | undefined ?? null;
} else { } else {
return await this.cacheService.uriPersonCache.fetch( return await this.cacheService.uriPersonCache.fetch(
parsed.uri, parsed.uri,
() => this.usersRepository.findOneBy({ uri: parsed.uri }), () => this.usersRepository.findOneBy({ uri: parsed.uri }),
) as RemoteUser | null; ) as MiRemoteUser | null;
} }
} }
@ -121,8 +121,8 @@ export class ApDbResolverService implements OnApplicationShutdown {
*/ */
@bindThis @bindThis
public async getAuthUserFromKeyId(keyId: string): Promise<{ public async getAuthUserFromKeyId(keyId: string): Promise<{
user: RemoteUser; user: MiRemoteUser;
key: UserPublickey; key: MiUserPublickey;
} | null> { } | null> {
const key = await this.publicKeyCache.fetch(keyId, async () => { const key = await this.publicKeyCache.fetch(keyId, async () => {
const key = await this.userPublickeysRepository.findOneBy({ const key = await this.userPublickeysRepository.findOneBy({
@ -137,7 +137,7 @@ export class ApDbResolverService implements OnApplicationShutdown {
if (key == null) return null; if (key == null) return null;
return { return {
user: await this.cacheService.findUserById(key.userId) as RemoteUser, user: await this.cacheService.findUserById(key.userId) as MiRemoteUser,
key, key,
}; };
} }
@ -147,10 +147,10 @@ export class ApDbResolverService implements OnApplicationShutdown {
*/ */
@bindThis @bindThis
public async getAuthUserFromApId(uri: string): Promise<{ public async getAuthUserFromApId(uri: string): Promise<{
user: RemoteUser; user: MiRemoteUser;
key: UserPublickey | null; key: MiUserPublickey | null;
} | null> { } | null> {
const user = await this.apPersonService.resolvePerson(uri) as RemoteUser; const user = await this.apPersonService.resolvePerson(uri) as MiRemoteUser;
const key = await this.publicKeyByUserIdCache.fetch( const key = await this.publicKeyByUserIdCache.fetch(
user.id, user.id,

View File

@ -7,7 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { IsNull, Not } from 'typeorm'; import { IsNull, Not } from 'typeorm';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { FollowingsRepository } from '@/models/index.js'; import type { FollowingsRepository } from '@/models/index.js';
import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js'; import type { MiLocalUser, MiRemoteUser, MiUser } from '@/models/entities/User.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -24,7 +24,7 @@ interface IFollowersRecipe extends IRecipe {
interface IDirectRecipe extends IRecipe { interface IDirectRecipe extends IRecipe {
type: 'Direct'; type: 'Direct';
to: RemoteUser; to: MiRemoteUser;
} }
const isFollowers = (recipe: IRecipe): recipe is IFollowersRecipe => const isFollowers = (recipe: IRecipe): recipe is IFollowersRecipe =>
@ -51,7 +51,7 @@ class DeliverManager {
private followingsRepository: FollowingsRepository, private followingsRepository: FollowingsRepository,
private queueService: QueueService, private queueService: QueueService,
actor: { id: User['id']; host: null; }, actor: { id: MiUser['id']; host: null; },
activity: IActivity | null, activity: IActivity | null,
) { ) {
// 型で弾いてはいるが一応ローカルユーザーかチェック // 型で弾いてはいるが一応ローカルユーザーかチェック
@ -82,7 +82,7 @@ class DeliverManager {
* @param to To * @param to To
*/ */
@bindThis @bindThis
public addDirectRecipe(to: RemoteUser): void { public addDirectRecipe(to: MiRemoteUser): void {
const recipe: IDirectRecipe = { const recipe: IDirectRecipe = {
type: 'Direct', type: 'Direct',
to, to,
@ -165,7 +165,7 @@ export class ApDeliverManagerService {
* @param activity Activity * @param activity Activity
*/ */
@bindThis @bindThis
public async deliverToFollowers(actor: { id: LocalUser['id']; host: null; }, activity: IActivity): Promise<void> { public async deliverToFollowers(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity): Promise<void> {
const manager = new DeliverManager( const manager = new DeliverManager(
this.userEntityService, this.userEntityService,
this.followingsRepository, this.followingsRepository,
@ -184,7 +184,7 @@ export class ApDeliverManagerService {
* @param to Target user * @param to Target user
*/ */
@bindThis @bindThis
public async deliverToUser(actor: { id: LocalUser['id']; host: null; }, activity: IActivity, to: RemoteUser): Promise<void> { public async deliverToUser(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity, to: MiRemoteUser): Promise<void> {
const manager = new DeliverManager( const manager = new DeliverManager(
this.userEntityService, this.userEntityService,
this.followingsRepository, this.followingsRepository,
@ -197,7 +197,7 @@ export class ApDeliverManagerService {
} }
@bindThis @bindThis
public createDeliverManager(actor: { id: User['id']; host: null; }, activity: IActivity | null): DeliverManager { public createDeliverManager(actor: { id: MiUser['id']; host: null; }, activity: IActivity | null): DeliverManager {
return new DeliverManager( return new DeliverManager(
this.userEntityService, this.userEntityService,
this.followingsRepository, this.followingsRepository,

View File

@ -26,7 +26,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/index.js'; import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/index.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type { RemoteUser } from '@/models/entities/User.js'; import type { MiRemoteUser } from '@/models/entities/User.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 { 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 { ApNoteService } from './models/ApNoteService.js';
import { ApLoggerService } from './ApLoggerService.js'; import { ApLoggerService } from './ApLoggerService.js';
@ -87,7 +87,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
public async performActivity(actor: RemoteUser, activity: IObject): Promise<void> { public async performActivity(actor: MiRemoteUser, activity: IObject): Promise<void> {
if (isCollectionOrOrderedCollection(activity)) { if (isCollectionOrOrderedCollection(activity)) {
const resolver = this.apResolverService.createResolver(); const resolver = this.apResolverService.createResolver();
for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) { for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) {
@ -115,7 +115,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
public async performOneActivity(actor: RemoteUser, activity: IObject): Promise<void> { public async performOneActivity(actor: MiRemoteUser, activity: IObject): Promise<void> {
if (actor.isSuspended) return; if (actor.isSuspended) return;
if (isCreate(activity)) { if (isCreate(activity)) {
@ -152,7 +152,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async follow(actor: RemoteUser, activity: IFollow): Promise<string> { private async follow(actor: MiRemoteUser, activity: IFollow): Promise<string> {
const followee = await this.apDbResolverService.getUserFromApId(activity.object); const followee = await this.apDbResolverService.getUserFromApId(activity.object);
if (followee == null) { if (followee == null) {
@ -169,7 +169,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async like(actor: RemoteUser, activity: ILike): Promise<string> { private async like(actor: MiRemoteUser, activity: ILike): Promise<string> {
const targetUri = getApId(activity.object); const targetUri = getApId(activity.object);
const note = await this.apNoteService.fetchNote(targetUri); const note = await this.apNoteService.fetchNote(targetUri);
@ -187,7 +187,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async accept(actor: RemoteUser, activity: IAccept): Promise<string> { private async accept(actor: MiRemoteUser, activity: IAccept): Promise<string> {
const uri = activity.id ?? activity; const uri = activity.id ?? activity;
this.logger.info(`Accept: ${uri}`); this.logger.info(`Accept: ${uri}`);
@ -205,7 +205,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async acceptFollow(actor: RemoteUser, activity: IFollow): Promise<string> { private async acceptFollow(actor: MiRemoteUser, activity: IFollow): Promise<string> {
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
const follower = await this.apDbResolverService.getUserFromApId(activity.actor); const follower = await this.apDbResolverService.getUserFromApId(activity.actor);
@ -229,7 +229,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async add(actor: RemoteUser, activity: IAdd): Promise<void> { private async add(actor: MiRemoteUser, activity: IAdd): Promise<void> {
if (actor.uri !== activity.actor) { if (actor.uri !== activity.actor) {
throw new Error('invalid actor'); throw new Error('invalid actor');
} }
@ -249,7 +249,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async announce(actor: RemoteUser, activity: IAnnounce): Promise<void> { private async announce(actor: MiRemoteUser, activity: IAnnounce): Promise<void> {
const uri = getApId(activity); const uri = getApId(activity);
this.logger.info(`Announce: ${uri}`); this.logger.info(`Announce: ${uri}`);
@ -260,7 +260,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async announceNote(actor: RemoteUser, activity: IAnnounce, targetUri: string): Promise<void> { private async announceNote(actor: MiRemoteUser, activity: IAnnounce, targetUri: string): Promise<void> {
const uri = getApId(activity); const uri = getApId(activity);
if (actor.isSuspended) { if (actor.isSuspended) {
@ -320,7 +320,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async block(actor: RemoteUser, activity: IBlock): Promise<string> { private async block(actor: MiRemoteUser, activity: IBlock): Promise<string> {
// ※ activity.objectにブロック対象があり、それは存在するローカルユーザーのはず // ※ activity.objectにブロック対象があり、それは存在するローカルユーザーのはず
const blockee = await this.apDbResolverService.getUserFromApId(activity.object); const blockee = await this.apDbResolverService.getUserFromApId(activity.object);
@ -338,7 +338,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async create(actor: RemoteUser, activity: ICreate): Promise<void> { private async create(actor: MiRemoteUser, activity: ICreate): Promise<void> {
const uri = getApId(activity); const uri = getApId(activity);
this.logger.info(`Create: ${uri}`); this.logger.info(`Create: ${uri}`);
@ -374,7 +374,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async createNote(resolver: Resolver, actor: RemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<string> { private async createNote(resolver: Resolver, actor: MiRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<string> {
const uri = getApId(note); const uri = getApId(note);
if (typeof note === 'object') { if (typeof note === 'object') {
@ -409,7 +409,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async delete(actor: RemoteUser, activity: IDelete): Promise<string> { private async delete(actor: MiRemoteUser, activity: IDelete): Promise<string> {
if (actor.uri !== activity.actor) { if (actor.uri !== activity.actor) {
throw new Error('invalid actor'); throw new Error('invalid actor');
} }
@ -451,7 +451,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async deleteActor(actor: RemoteUser, uri: string): Promise<string> { private async deleteActor(actor: MiRemoteUser, uri: string): Promise<string> {
this.logger.info(`Deleting the Actor: ${uri}`); this.logger.info(`Deleting the Actor: ${uri}`);
if (actor.uri !== uri) { if (actor.uri !== uri) {
@ -475,7 +475,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async deleteNote(actor: RemoteUser, uri: string): Promise<string> { private async deleteNote(actor: MiRemoteUser, uri: string): Promise<string> {
this.logger.info(`Deleting the Note: ${uri}`); this.logger.info(`Deleting the Note: ${uri}`);
const unlock = await this.appLockService.getApLock(uri); const unlock = await this.appLockService.getApLock(uri);
@ -499,7 +499,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async flag(actor: RemoteUser, activity: IFlag): Promise<string> { private async flag(actor: MiRemoteUser, activity: IFlag): Promise<string> {
// objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので // objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので
// 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する // 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する
const uris = getApIds(activity.object); const uris = getApIds(activity.object);
@ -527,7 +527,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async reject(actor: RemoteUser, activity: IReject): Promise<string> { private async reject(actor: MiRemoteUser, activity: IReject): Promise<string> {
const uri = activity.id ?? activity; const uri = activity.id ?? activity;
this.logger.info(`Reject: ${uri}`); this.logger.info(`Reject: ${uri}`);
@ -545,7 +545,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async rejectFollow(actor: RemoteUser, activity: IFollow): Promise<string> { private async rejectFollow(actor: MiRemoteUser, activity: IFollow): Promise<string> {
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
const follower = await this.apDbResolverService.getUserFromApId(activity.actor); const follower = await this.apDbResolverService.getUserFromApId(activity.actor);
@ -569,7 +569,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async remove(actor: RemoteUser, activity: IRemove): Promise<void> { private async remove(actor: MiRemoteUser, activity: IRemove): Promise<void> {
if (actor.uri !== activity.actor) { if (actor.uri !== activity.actor) {
throw new Error('invalid actor'); throw new Error('invalid actor');
} }
@ -589,7 +589,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async undo(actor: RemoteUser, activity: IUndo): Promise<string> { private async undo(actor: MiRemoteUser, activity: IUndo): Promise<string> {
if (actor.uri !== activity.actor) { if (actor.uri !== activity.actor) {
throw new Error('invalid actor'); throw new Error('invalid actor');
} }
@ -616,7 +616,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async undoAccept(actor: RemoteUser, activity: IAccept): Promise<string> { private async undoAccept(actor: MiRemoteUser, activity: IAccept): Promise<string> {
const follower = await this.apDbResolverService.getUserFromApId(activity.object); const follower = await this.apDbResolverService.getUserFromApId(activity.object);
if (follower == null) { if (follower == null) {
return 'skip: follower not found'; return 'skip: follower not found';
@ -638,7 +638,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async undoAnnounce(actor: RemoteUser, activity: IAnnounce): Promise<string> { private async undoAnnounce(actor: MiRemoteUser, activity: IAnnounce): Promise<string> {
const uri = getApId(activity); const uri = getApId(activity);
const note = await this.notesRepository.findOneBy({ const note = await this.notesRepository.findOneBy({
@ -653,7 +653,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async undoBlock(actor: RemoteUser, activity: IBlock): Promise<string> { private async undoBlock(actor: MiRemoteUser, activity: IBlock): Promise<string> {
const blockee = await this.apDbResolverService.getUserFromApId(activity.object); const blockee = await this.apDbResolverService.getUserFromApId(activity.object);
if (blockee == null) { if (blockee == null) {
@ -669,7 +669,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async undoFollow(actor: RemoteUser, activity: IFollow): Promise<string> { private async undoFollow(actor: MiRemoteUser, activity: IFollow): Promise<string> {
const followee = await this.apDbResolverService.getUserFromApId(activity.object); const followee = await this.apDbResolverService.getUserFromApId(activity.object);
if (followee == null) { if (followee == null) {
return 'skip: followee not found'; return 'skip: followee not found';
@ -707,7 +707,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async undoLike(actor: RemoteUser, activity: ILike): Promise<string> { private async undoLike(actor: MiRemoteUser, activity: ILike): Promise<string> {
const targetUri = getApId(activity.object); const targetUri = getApId(activity.object);
const note = await this.apNoteService.fetchNote(targetUri); const note = await this.apNoteService.fetchNote(targetUri);
@ -722,7 +722,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async update(actor: RemoteUser, activity: IUpdate): Promise<string> { private async update(actor: MiRemoteUser, activity: IUpdate): Promise<string> {
if (actor.uri !== activity.actor) { if (actor.uri !== activity.actor) {
return 'skip: invalid actor'; return 'skip: invalid actor';
} }
@ -748,7 +748,7 @@ export class ApInboxService {
} }
@bindThis @bindThis
private async move(actor: RemoteUser, activity: IMove): Promise<string> { private async move(actor: MiRemoteUser, activity: IMove): Promise<string> {
// fetch the new and old accounts // fetch the new and old accounts
const targetUri = getApHrefNullable(activity.target); const targetUri = getApHrefNullable(activity.target);
if (!targetUri) return 'skip: invalid activity target'; if (!targetUri) return 'skip: invalid activity target';

View File

@ -6,7 +6,7 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import * as mfm from 'mfm-js'; import * as mfm from 'mfm-js';
import { MfmService } from '@/core/MfmService.js'; import { MfmService } from '@/core/MfmService.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { extractApHashtagObjects } from './models/tag.js'; import { extractApHashtagObjects } from './models/tag.js';
import type { IObject } from './type.js'; import type { IObject } from './type.js';
@ -25,7 +25,7 @@ export class ApMfmService {
} }
@bindThis @bindThis
public getNoteHtml(note: Note): string | null { public getNoteHtml(note: MiNote): string | null {
if (!note.text) return ''; if (!note.text) return '';
return this.mfmService.toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers)); return this.mfmService.toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers));
} }

View File

@ -9,20 +9,20 @@ import { In } from 'typeorm';
import * as mfm from 'mfm-js'; import * as mfm from 'mfm-js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type { PartialLocalUser, LocalUser, PartialRemoteUser, RemoteUser, User } from '@/models/entities/User.js'; import type { MiPartialLocalUser, MiLocalUser, MiPartialRemoteUser, MiRemoteUser, MiUser } from '@/models/entities/User.js';
import type { IMentionedRemoteUsers, Note } from '@/models/entities/Note.js'; import type { IMentionedRemoteUsers, MiNote } from '@/models/entities/Note.js';
import type { Blocking } from '@/models/entities/Blocking.js'; import type { MiBlocking } from '@/models/entities/Blocking.js';
import type { Relay } from '@/models/entities/Relay.js'; import type { MiRelay } from '@/models/entities/Relay.js';
import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MiDriveFile } from '@/models/entities/DriveFile.js';
import type { NoteReaction } from '@/models/entities/NoteReaction.js'; import type { MiNoteReaction } from '@/models/entities/NoteReaction.js';
import type { Emoji } from '@/models/entities/Emoji.js'; import type { MiEmoji } from '@/models/entities/Emoji.js';
import type { Poll } from '@/models/entities/Poll.js'; import type { MiPoll } from '@/models/entities/Poll.js';
import type { PollVote } from '@/models/entities/PollVote.js'; import type { MiPollVote } from '@/models/entities/PollVote.js';
import { UserKeypairService } from '@/core/UserKeypairService.js'; import { UserKeypairService } from '@/core/UserKeypairService.js';
import { MfmService } from '@/core/MfmService.js'; import { MfmService } from '@/core/MfmService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import type { UserKeypair } from '@/models/entities/UserKeypair.js'; import type { MiUserKeypair } from '@/models/entities/UserKeypair.js';
import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository } from '@/models/index.js'; import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository } from '@/models/index.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js';
@ -63,7 +63,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderAccept(object: string | IObject, user: { id: User['id']; host: null }): IAccept { public renderAccept(object: string | IObject, user: { id: MiUser['id']; host: null }): IAccept {
return { return {
type: 'Accept', type: 'Accept',
actor: this.userEntityService.genLocalUserUri(user.id), actor: this.userEntityService.genLocalUserUri(user.id),
@ -72,7 +72,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderAdd(user: LocalUser, target: string | IObject | undefined, object: string | IObject): IAdd { public renderAdd(user: MiLocalUser, target: string | IObject | undefined, object: string | IObject): IAdd {
return { return {
type: 'Add', type: 'Add',
actor: this.userEntityService.genLocalUserUri(user.id), actor: this.userEntityService.genLocalUserUri(user.id),
@ -82,7 +82,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderAnnounce(object: string | IObject, note: Note): IAnnounce { public renderAnnounce(object: string | IObject, note: MiNote): IAnnounce {
const attributedTo = this.userEntityService.genLocalUserUri(note.userId); const attributedTo = this.userEntityService.genLocalUserUri(note.userId);
let to: string[] = []; let to: string[] = [];
@ -118,7 +118,7 @@ export class ApRendererService {
* @param block The block to be rendered. The blockee relation must be loaded. * @param block The block to be rendered. The blockee relation must be loaded.
*/ */
@bindThis @bindThis
public renderBlock(block: Blocking): IBlock { public renderBlock(block: MiBlocking): IBlock {
if (block.blockee?.uri == null) { if (block.blockee?.uri == null) {
throw new Error('renderBlock: missing blockee uri'); throw new Error('renderBlock: missing blockee uri');
} }
@ -132,7 +132,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderCreate(object: IObject, note: Note): ICreate { public renderCreate(object: IObject, note: MiNote): ICreate {
const activity: ICreate = { const activity: ICreate = {
id: `${this.config.url}/notes/${note.id}/activity`, id: `${this.config.url}/notes/${note.id}/activity`,
actor: this.userEntityService.genLocalUserUri(note.userId), actor: this.userEntityService.genLocalUserUri(note.userId),
@ -148,7 +148,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderDelete(object: IObject | string, user: { id: User['id']; host: null }): IDelete { public renderDelete(object: IObject | string, user: { id: MiUser['id']; host: null }): IDelete {
return { return {
type: 'Delete', type: 'Delete',
actor: this.userEntityService.genLocalUserUri(user.id), actor: this.userEntityService.genLocalUserUri(user.id),
@ -158,7 +158,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderDocument(file: DriveFile): IApDocument { public renderDocument(file: MiDriveFile): IApDocument {
return { return {
type: 'Document', type: 'Document',
mediaType: file.webpublicType ?? file.type, mediaType: file.webpublicType ?? file.type,
@ -168,7 +168,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderEmoji(emoji: Emoji): IApEmoji { public renderEmoji(emoji: MiEmoji): IApEmoji {
return { return {
id: `${this.config.url}/emojis/${emoji.name}`, id: `${this.config.url}/emojis/${emoji.name}`,
type: 'Emoji', type: 'Emoji',
@ -185,7 +185,7 @@ export class ApRendererService {
// to anonymise reporters, the reporting actor must be a system user // to anonymise reporters, the reporting actor must be a system user
@bindThis @bindThis
public renderFlag(user: LocalUser, object: IObject | string, content: string): IFlag { public renderFlag(user: MiLocalUser, object: IObject | string, content: string): IFlag {
return { return {
type: 'Flag', type: 'Flag',
actor: this.userEntityService.genLocalUserUri(user.id), actor: this.userEntityService.genLocalUserUri(user.id),
@ -195,7 +195,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderFollowRelay(relay: Relay, relayActor: LocalUser): IFollow { public renderFollowRelay(relay: MiRelay, relayActor: MiLocalUser): IFollow {
return { return {
id: `${this.config.url}/activities/follow-relay/${relay.id}`, id: `${this.config.url}/activities/follow-relay/${relay.id}`,
type: 'Follow', type: 'Follow',
@ -209,15 +209,15 @@ export class ApRendererService {
* @param id Follower|Followee ID * @param id Follower|Followee ID
*/ */
@bindThis @bindThis
public async renderFollowUser(id: User['id']): Promise<string> { public async renderFollowUser(id: MiUser['id']): Promise<string> {
const user = await this.usersRepository.findOneByOrFail({ id: id }) as PartialLocalUser | PartialRemoteUser; const user = await this.usersRepository.findOneByOrFail({ id: id }) as MiPartialLocalUser | MiPartialRemoteUser;
return this.userEntityService.getUserUri(user); return this.userEntityService.getUserUri(user);
} }
@bindThis @bindThis
public renderFollow( public renderFollow(
follower: PartialLocalUser | PartialRemoteUser, follower: MiPartialLocalUser | MiPartialRemoteUser,
followee: PartialLocalUser | PartialRemoteUser, followee: MiPartialLocalUser | MiPartialRemoteUser,
requestId?: string, requestId?: string,
): IFollow { ): IFollow {
return { return {
@ -238,7 +238,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderImage(file: DriveFile): IApImage { public renderImage(file: MiDriveFile): IApImage {
return { return {
type: 'Image', type: 'Image',
url: this.driveFileEntityService.getPublicUrl(file), url: this.driveFileEntityService.getPublicUrl(file),
@ -248,7 +248,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderKey(user: LocalUser, key: UserKeypair, postfix?: string): IKey { public renderKey(user: MiLocalUser, key: MiUserKeypair, postfix?: string): IKey {
return { return {
id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`, id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`,
type: 'Key', type: 'Key',
@ -261,7 +261,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }): Promise<ILike> { public async renderLike(noteReaction: MiNoteReaction, note: { uri: string | null }): Promise<ILike> {
const reaction = noteReaction.reaction; const reaction = noteReaction.reaction;
const object: ILike = { const object: ILike = {
@ -284,18 +284,18 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderMention(mention: PartialLocalUser | PartialRemoteUser): IApMention { public renderMention(mention: MiPartialLocalUser | MiPartialRemoteUser): IApMention {
return { return {
type: 'Mention', type: 'Mention',
href: this.userEntityService.getUserUri(mention), href: this.userEntityService.getUserUri(mention),
name: this.userEntityService.isRemoteUser(mention) ? `@${mention.username}@${mention.host}` : `@${(mention as LocalUser).username}`, name: this.userEntityService.isRemoteUser(mention) ? `@${mention.username}@${mention.host}` : `@${(mention as MiLocalUser).username}`,
}; };
} }
@bindThis @bindThis
public renderMove( public renderMove(
src: PartialLocalUser | PartialRemoteUser, src: MiPartialLocalUser | MiPartialRemoteUser,
dst: PartialLocalUser | PartialRemoteUser, dst: MiPartialLocalUser | MiPartialRemoteUser,
): IMove { ): IMove {
const actor = this.userEntityService.getUserUri(src); const actor = this.userEntityService.getUserUri(src);
const target = this.userEntityService.getUserUri(dst); const target = this.userEntityService.getUserUri(dst);
@ -309,15 +309,15 @@ export class ApRendererService {
} }
@bindThis @bindThis
public async renderNote(note: Note, dive = true): Promise<IPost> { public async renderNote(note: MiNote, dive = true): Promise<IPost> {
const getPromisedFiles = async (ids: string[]): Promise<DriveFile[]> => { const getPromisedFiles = async (ids: string[]): Promise<MiDriveFile[]> => {
if (ids.length === 0) return []; if (ids.length === 0) return [];
const items = await this.driveFilesRepository.findBy({ id: In(ids) }); const items = await this.driveFilesRepository.findBy({ id: In(ids) });
return ids.map(id => items.find(item => item.id === id)).filter((item): item is DriveFile => item != null); return ids.map(id => items.find(item => item.id === id)).filter((item): item is MiDriveFile => item != null);
}; };
let inReplyTo; let inReplyTo;
let inReplyToNote: Note | null; let inReplyToNote: MiNote | null;
if (note.replyId) { if (note.replyId) {
inReplyToNote = await this.notesRepository.findOneBy({ id: note.replyId }); inReplyToNote = await this.notesRepository.findOneBy({ id: note.replyId });
@ -376,12 +376,12 @@ export class ApRendererService {
}) : []; }) : [];
const hashtagTags = note.tags.map(tag => this.renderHashtag(tag)); const hashtagTags = note.tags.map(tag => this.renderHashtag(tag));
const mentionTags = mentionedUsers.map(u => this.renderMention(u as LocalUser | RemoteUser)); const mentionTags = mentionedUsers.map(u => this.renderMention(u as MiLocalUser | MiRemoteUser));
const files = await getPromisedFiles(note.fileIds); const files = await getPromisedFiles(note.fileIds);
const text = note.text ?? ''; const text = note.text ?? '';
let poll: Poll | null = null; let poll: MiPoll | null = null;
if (note.hasPoll) { if (note.hasPoll) {
poll = await this.pollsRepository.findOneBy({ noteId: note.id }); poll = await this.pollsRepository.findOneBy({ noteId: note.id });
@ -449,7 +449,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public async renderPerson(user: LocalUser) { public async renderPerson(user: MiLocalUser) {
const id = this.userEntityService.genLocalUserUri(user.id); const id = this.userEntityService.genLocalUserUri(user.id);
const isSystem = user.username.includes('.'); const isSystem = user.username.includes('.');
@ -523,7 +523,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll): IQuestion { public renderQuestion(user: { id: MiUser['id'] }, note: MiNote, poll: MiPoll): IQuestion {
return { return {
type: 'Question', type: 'Question',
id: `${this.config.url}/questions/${note.id}`, id: `${this.config.url}/questions/${note.id}`,
@ -541,7 +541,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderReject(object: string | IObject, user: { id: User['id'] }): IReject { public renderReject(object: string | IObject, user: { id: MiUser['id'] }): IReject {
return { return {
type: 'Reject', type: 'Reject',
actor: this.userEntityService.genLocalUserUri(user.id), actor: this.userEntityService.genLocalUserUri(user.id),
@ -550,7 +550,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderRemove(user: { id: User['id'] }, target: string | IObject | undefined, object: string | IObject): IRemove { public renderRemove(user: { id: MiUser['id'] }, target: string | IObject | undefined, object: string | IObject): IRemove {
return { return {
type: 'Remove', type: 'Remove',
actor: this.userEntityService.genLocalUserUri(user.id), actor: this.userEntityService.genLocalUserUri(user.id),
@ -568,7 +568,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderUndo(object: string | IObject, user: { id: User['id'] }): IUndo { public renderUndo(object: string | IObject, user: { id: MiUser['id'] }): IUndo {
const id = typeof object !== 'string' && typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined; const id = typeof object !== 'string' && typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined;
return { return {
@ -581,7 +581,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderUpdate(object: string | IObject, user: { id: User['id'] }): IUpdate { public renderUpdate(object: string | IObject, user: { id: MiUser['id'] }): IUpdate {
return { return {
id: `${this.config.url}/users/${user.id}#updates/${new Date().getTime()}`, id: `${this.config.url}/users/${user.id}#updates/${new Date().getTime()}`,
actor: this.userEntityService.genLocalUserUri(user.id), actor: this.userEntityService.genLocalUserUri(user.id),
@ -593,7 +593,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: RemoteUser): ICreate { public renderVote(user: { id: MiUser['id'] }, vote: MiPollVote, note: MiNote, poll: MiPoll, pollOwner: MiRemoteUser): ICreate {
return { return {
id: `${this.config.url}/users/${user.id}#votes/${vote.id}/activity`, id: `${this.config.url}/users/${user.id}#votes/${vote.id}/activity`,
actor: this.userEntityService.genLocalUserUri(user.id), actor: this.userEntityService.genLocalUserUri(user.id),
@ -651,7 +651,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
public async attachLdSignature(activity: any, user: { id: User['id']; host: null; }): Promise<IActivity> { public async attachLdSignature(activity: any, user: { id: MiUser['id']; host: null; }): Promise<IActivity> {
const keypair = await this.userKeypairService.getUserKeypair(user.id); const keypair = await this.userKeypairService.getUserKeypair(user.id);
const ldSignature = this.ldSignatureService.use(); const ldSignature = this.ldSignatureService.use();
@ -710,7 +710,7 @@ export class ApRendererService {
} }
@bindThis @bindThis
private async getEmojis(names: string[]): Promise<Emoji[]> { private async getEmojis(names: string[]): Promise<MiEmoji[]> {
if (names.length === 0) return []; if (names.length === 0) return [];
const allEmojis = await this.customEmojiService.localEmojisCache.fetch(); const allEmojis = await this.customEmojiService.localEmojisCache.fetch();

View File

@ -8,7 +8,7 @@ import { URL } from 'node:url';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { UserKeypairService } from '@/core/UserKeypairService.js'; import { UserKeypairService } from '@/core/UserKeypairService.js';
import { HttpRequestService } from '@/core/HttpRequestService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js';
import { LoggerService } from '@/core/LoggerService.js'; import { LoggerService } from '@/core/LoggerService.js';
@ -145,7 +145,7 @@ export class ApRequestService {
} }
@bindThis @bindThis
public async signedPost(user: { id: User['id'] }, url: string, object: unknown): Promise<void> { public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown): Promise<void> {
const body = JSON.stringify(object); const body = JSON.stringify(object);
const keypair = await this.userKeypairService.getUserKeypair(user.id); const keypair = await this.userKeypairService.getUserKeypair(user.id);
@ -174,7 +174,7 @@ export class ApRequestService {
* @param url URL to fetch * @param url URL to fetch
*/ */
@bindThis @bindThis
public async signedGet(url: string, user: { id: User['id'] }): Promise<unknown> { public async signedGet(url: string, user: { id: MiUser['id'] }): Promise<unknown> {
const keypair = await this.userKeypairService.getUserKeypair(user.id); const keypair = await this.userKeypairService.getUserKeypair(user.id);
const req = ApRequestCreator.createSignedGet({ const req = ApRequestCreator.createSignedGet({

View File

@ -4,7 +4,7 @@
*/ */
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import type { LocalUser, RemoteUser } from '@/models/entities/User.js'; import type { MiLocalUser, MiRemoteUser } from '@/models/entities/User.js';
import { InstanceActorService } from '@/core/InstanceActorService.js'; import { InstanceActorService } from '@/core/InstanceActorService.js';
import type { NotesRepository, PollsRepository, NoteReactionsRepository, UsersRepository } from '@/models/index.js'; import type { NotesRepository, PollsRepository, NoteReactionsRepository, UsersRepository } from '@/models/index.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
@ -23,7 +23,7 @@ import type { IObject, ICollection, IOrderedCollection } from './type.js';
export class Resolver { export class Resolver {
private history: Set<string>; private history: Set<string>;
private user?: LocalUser; private user?: MiLocalUser;
private logger: Logger; private logger: Logger;
constructor( constructor(
@ -134,7 +134,7 @@ export class Resolver {
}); });
case 'users': case 'users':
return this.usersRepository.findOneByOrFail({ id: parsed.id }) return this.usersRepository.findOneByOrFail({ id: parsed.id })
.then(user => this.apRendererService.renderPerson(user as LocalUser)); .then(user => this.apRendererService.renderPerson(user as MiLocalUser));
case 'questions': case 'questions':
// Polls are indexed by the note they are attached to. // Polls are indexed by the note they are attached to.
return Promise.all([ return Promise.all([
@ -152,7 +152,7 @@ export class Resolver {
return Promise.all( return Promise.all(
[parsed.id, parsed.rest].map(id => this.usersRepository.findOneByOrFail({ id })), [parsed.id, parsed.rest].map(id => this.usersRepository.findOneByOrFail({ id })),
) )
.then(([follower, followee]) => this.apRendererService.addContext(this.apRendererService.renderFollow(follower as LocalUser | RemoteUser, followee as LocalUser | RemoteUser, url))); .then(([follower, followee]) => this.apRendererService.addContext(this.apRendererService.renderFollow(follower as MiLocalUser | MiRemoteUser, followee as MiLocalUser | MiRemoteUser, url)));
default: default:
throw new Error(`resolveLocal: type ${parsed.type} unhandled`); throw new Error(`resolveLocal: type ${parsed.type} unhandled`);
} }

View File

@ -6,8 +6,8 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { DriveFilesRepository } from '@/models/index.js'; import type { DriveFilesRepository } from '@/models/index.js';
import type { RemoteUser } from '@/models/entities/User.js'; import type { MiRemoteUser } from '@/models/entities/User.js';
import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MiDriveFile } from '@/models/entities/DriveFile.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { truncate } from '@/misc/truncate.js'; import { truncate } from '@/misc/truncate.js';
import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/const.js'; import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/const.js';
@ -39,7 +39,7 @@ export class ApImageService {
* Imageを作成します * Imageを作成します
*/ */
@bindThis @bindThis
public async createImage(actor: RemoteUser, value: string | IObject): Promise<DriveFile> { public async createImage(actor: MiRemoteUser, value: string | IObject): Promise<MiDriveFile> {
// 投稿者が凍結されていたらスキップ // 投稿者が凍結されていたらスキップ
if (actor.isSuspended) { if (actor.isSuspended) {
throw new Error('actor has been suspended'); throw new Error('actor has been suspended');
@ -90,7 +90,7 @@ export class ApImageService {
* Misskeyに登録しそれを返します * Misskeyに登録しそれを返します
*/ */
@bindThis @bindThis
public async resolveImage(actor: RemoteUser, value: string | IObject): Promise<DriveFile> { public async resolveImage(actor: MiRemoteUser, value: string | IObject): Promise<MiDriveFile> {
// TODO // TODO
// リモートサーバーからフェッチしてきて登録 // リモートサーバーからフェッチしてきて登録

View File

@ -5,7 +5,7 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import promiseLimit from 'promise-limit'; import promiseLimit from 'promise-limit';
import type { User } from '@/models/index.js'; import type { MiUser } from '@/models/index.js';
import { toArray, unique } from '@/misc/prelude/array.js'; import { toArray, unique } from '@/misc/prelude/array.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { isMention } from '../type.js'; import { isMention } from '../type.js';
@ -21,13 +21,13 @@ export class ApMentionService {
} }
@bindThis @bindThis
public async extractApMentions(tags: IObject | IObject[] | null | undefined, resolver: Resolver): Promise<User[]> { public async extractApMentions(tags: IObject | IObject[] | null | undefined, resolver: Resolver): Promise<MiUser[]> {
const hrefs = unique(this.extractApMentionObjects(tags).map(x => x.href)); const hrefs = unique(this.extractApMentionObjects(tags).map(x => x.href));
const limit = promiseLimit<User | null>(2); const limit = promiseLimit<MiUser | null>(2);
const mentionedUsers = (await Promise.all( const mentionedUsers = (await Promise.all(
hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))), hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))),
)).filter((x): x is User => x != null); )).filter((x): x is MiUser => x != null);
return mentionedUsers; return mentionedUsers;
} }

View File

@ -9,13 +9,13 @@ import { In } from 'typeorm';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { PollsRepository, EmojisRepository } from '@/models/index.js'; import type { PollsRepository, EmojisRepository } from '@/models/index.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type { RemoteUser } from '@/models/entities/User.js'; import type { MiRemoteUser } from '@/models/entities/User.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { toArray, toSingle, unique } from '@/misc/prelude/array.js'; import { toArray, toSingle, unique } from '@/misc/prelude/array.js';
import type { Emoji } from '@/models/entities/Emoji.js'; import type { MiEmoji } from '@/models/entities/Emoji.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MiDriveFile } from '@/models/entities/DriveFile.js';
import { NoteCreateService } from '@/core/NoteCreateService.js'; import { NoteCreateService } from '@/core/NoteCreateService.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
@ -101,7 +101,7 @@ export class ApNoteService {
* Misskeyに対象のNoteが登録されていればそれを返します * Misskeyに対象のNoteが登録されていればそれを返します
*/ */
@bindThis @bindThis
public async fetchNote(object: string | IObject): Promise<Note | null> { public async fetchNote(object: string | IObject): Promise<MiNote | null> {
return await this.apDbResolverService.getNoteFromApId(object); return await this.apDbResolverService.getNoteFromApId(object);
} }
@ -109,7 +109,7 @@ export class ApNoteService {
* Noteを作成します * Noteを作成します
*/ */
@bindThis @bindThis
public async createNote(value: string | IObject, resolver?: Resolver, silent = false): Promise<Note | null> { public async createNote(value: string | IObject, resolver?: Resolver, silent = false): Promise<MiNote | null> {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
if (resolver == null) resolver = this.apResolverService.createResolver(); if (resolver == null) resolver = this.apResolverService.createResolver();
@ -131,13 +131,13 @@ export class ApNoteService {
this.logger.debug(`Note fetched: ${JSON.stringify(note, null, 2)}`); this.logger.debug(`Note fetched: ${JSON.stringify(note, null, 2)}`);
if (note.id && !checkHttps(note.id)) { if (note.id && !checkHttps(note.id)) {
throw new Error('unexpected shcema of note.id: ' + note.id); throw new Error('unexpected schema of note.id: ' + note.id);
} }
const url = getOneApHrefNullable(note.url); const url = getOneApHrefNullable(note.url);
if (url && !checkHttps(url)) { if (url && !checkHttps(url)) {
throw new Error('unexpected shcema of note url: ' + url); throw new Error('unexpected schema of note url: ' + url);
} }
this.logger.info(`Creating the Note: ${note.id}`); this.logger.info(`Creating the Note: ${note.id}`);
@ -147,7 +147,7 @@ export class ApNoteService {
throw new Error('invalid note.attributedTo: ' + note.attributedTo); throw new Error('invalid note.attributedTo: ' + note.attributedTo);
} }
const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo), resolver) as RemoteUser; const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo), resolver) as MiRemoteUser;
// 投稿者が凍結されていたらスキップ // 投稿者が凍結されていたらスキップ
if (actor.isSuspended) { if (actor.isSuspended) {
@ -172,7 +172,7 @@ export class ApNoteService {
// 添付ファイル // 添付ファイル
// TODO: attachmentは必ずしもImageではない // TODO: attachmentは必ずしもImageではない
// TODO: attachmentは必ずしも配列ではない // TODO: attachmentは必ずしも配列ではない
const limit = promiseLimit<DriveFile>(2); const limit = promiseLimit<MiDriveFile>(2);
const files = (await Promise.all(toArray(note.attachment).map(attach => ( const files = (await Promise.all(toArray(note.attachment).map(attach => (
limit(() => this.apImageService.resolveImage(actor, { limit(() => this.apImageService.resolveImage(actor, {
...attach, ...attach,
@ -181,7 +181,7 @@ export class ApNoteService {
)))); ))));
// リプライ // リプライ
const reply: Note | null = note.inReplyTo const reply: MiNote | null = note.inReplyTo
? await this.resolveNote(note.inReplyTo, { resolver }) ? await this.resolveNote(note.inReplyTo, { resolver })
.then(x => { .then(x => {
if (x == null) { if (x == null) {
@ -198,11 +198,11 @@ export class ApNoteService {
: null; : null;
// 引用 // 引用
let quote: Note | undefined | null = null; let quote: MiNote | undefined | null = null;
if (note._misskey_quote ?? note.quoteUrl) { if (note._misskey_quote ?? note.quoteUrl) {
const tryResolveNote = async (uri: string): Promise< const tryResolveNote = async (uri: string): Promise<
| { status: 'ok'; res: Note } | { status: 'ok'; res: MiNote }
| { status: 'permerror' | 'temperror' } | { status: 'permerror' | 'temperror' }
> => { > => {
if (!/^https?:/.test(uri)) return { status: 'permerror' }; if (!/^https?:/.test(uri)) return { status: 'permerror' };
@ -220,7 +220,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((x): x is string => typeof x === 'string'));
const results = await Promise.all(uris.map(tryResolveNote)); const results = await Promise.all(uris.map(tryResolveNote));
quote = results.filter((x): x is { status: 'ok', res: Note } => x.status === 'ok').map(x => x.res).at(0); quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0);
if (!quote) { if (!quote) {
if (results.some(x => x.status === 'temperror')) { if (results.some(x => x.status === 'temperror')) {
throw new Error('quote resolve failed'); throw new Error('quote resolve failed');
@ -271,24 +271,36 @@ export class ApNoteService {
const poll = await this.apQuestionService.extractPollFromQuestion(note, resolver).catch(() => undefined); const poll = await this.apQuestionService.extractPollFromQuestion(note, resolver).catch(() => undefined);
return await this.noteCreateService.create(actor, { try {
createdAt: note.published ? new Date(note.published) : null, return await this.noteCreateService.create(actor, {
files, createdAt: note.published ? new Date(note.published) : null,
reply, files,
renote: quote, reply,
name: note.name, renote: quote,
cw, name: note.name,
text, cw,
localOnly: false, text,
visibility, localOnly: false,
visibleUsers, visibility,
apMentions, visibleUsers,
apHashtags, apMentions,
apEmojis, apHashtags,
poll, apEmojis,
uri: note.id, poll,
url: url, uri: note.id,
}, silent); url: url,
}, silent);
} catch (err: any) {
if (err.name !== 'duplicated') {
throw err;
}
this.logger.info('The note is already inserted while creating itself, reading again');
const duplicate = await this.fetchNote(value);
if (!duplicate) {
throw new Error('The note creation failed with duplication error even when there is no duplication');
}
return duplicate;
}
} }
/** /**
@ -298,7 +310,7 @@ export class ApNoteService {
* Misskeyに登録しそれを返します * Misskeyに登録しそれを返します
*/ */
@bindThis @bindThis
public async resolveNote(value: string | IObject, options: { sentFrom?: URL, resolver?: Resolver } = {}): Promise<Note | null> { public async resolveNote(value: string | IObject, options: { sentFrom?: URL, resolver?: Resolver } = {}): Promise<MiNote | null> {
const uri = getApId(value); const uri = getApId(value);
// ブロックしていたら中断 // ブロックしていたら中断
@ -330,7 +342,7 @@ export class ApNoteService {
} }
@bindThis @bindThis
public async extractEmojis(tags: IObject | IObject[], host: string): Promise<Emoji[]> { public async extractEmojis(tags: IObject | IObject[], host: string): Promise<MiEmoji[]> {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
host = this.utilityService.toPuny(host); host = this.utilityService.toPuny(host);

View File

@ -10,26 +10,26 @@ import { ModuleRef } from '@nestjs/core';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { FollowingsRepository, InstancesRepository, UserProfilesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js'; import type { FollowingsRepository, InstancesRepository, UserProfilesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import type { LocalUser, RemoteUser } from '@/models/entities/User.js'; import type { MiLocalUser, MiRemoteUser } from '@/models/entities/User.js';
import { User } from '@/models/entities/User.js'; import { MiUser } from '@/models/entities/User.js';
import { truncate } from '@/misc/truncate.js'; import { truncate } from '@/misc/truncate.js';
import type { CacheService } from '@/core/CacheService.js'; import type { CacheService } from '@/core/CacheService.js';
import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js';
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import type { IdService } from '@/core/IdService.js'; import type { IdService } from '@/core/IdService.js';
import type { MfmService } from '@/core/MfmService.js'; import type { MfmService } from '@/core/MfmService.js';
import { toArray } from '@/misc/prelude/array.js'; import { toArray } from '@/misc/prelude/array.js';
import type { GlobalEventService } from '@/core/GlobalEventService.js'; import type { GlobalEventService } from '@/core/GlobalEventService.js';
import type { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; import type { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import type { FetchInstanceMetadataService } from '@/core/FetchInstanceMetadataService.js'; import type { FetchInstanceMetadataService } from '@/core/FetchInstanceMetadataService.js';
import { UserProfile } from '@/models/entities/UserProfile.js'; import { MiUserProfile } from '@/models/entities/UserProfile.js';
import { UserPublickey } from '@/models/entities/UserPublickey.js'; import { MiUserPublickey } from '@/models/entities/UserPublickey.js';
import type UsersChart from '@/core/chart/charts/users.js'; import type UsersChart from '@/core/chart/charts/users.js';
import type InstanceChart from '@/core/chart/charts/instance.js'; import type InstanceChart from '@/core/chart/charts/instance.js';
import type { HashtagService } from '@/core/HashtagService.js'; import type { HashtagService } from '@/core/HashtagService.js';
import { UserNotePining } from '@/models/entities/UserNotePining.js'; import { MiUserNotePining } from '@/models/entities/UserNotePining.js';
import { StatusError } from '@/misc/status-error.js'; import { StatusError } from '@/misc/status-error.js';
import type { UtilityService } from '@/core/UtilityService.js'; import type { UtilityService } from '@/core/UtilityService.js';
import type { UserEntityService } from '@/core/entities/UserEntityService.js'; import type { UserEntityService } from '@/core/entities/UserEntityService.js';
@ -201,20 +201,20 @@ export class ApPersonService implements OnModuleInit {
* Misskeyに対象のPersonが登録されていればそれを返しnullを返します * Misskeyに対象のPersonが登録されていればそれを返しnullを返します
*/ */
@bindThis @bindThis
public async fetchPerson(uri: string): Promise<LocalUser | RemoteUser | null> { public async fetchPerson(uri: string): Promise<MiLocalUser | MiRemoteUser | null> {
const cached = this.cacheService.uriPersonCache.get(uri) as LocalUser | RemoteUser | null | undefined; const cached = this.cacheService.uriPersonCache.get(uri) as MiLocalUser | MiRemoteUser | null | undefined;
if (cached) return cached; if (cached) return cached;
// URIがこのサーバーを指しているならデータベースからフェッチ // URIがこのサーバーを指しているならデータベースからフェッチ
if (uri.startsWith(`${this.config.url}/`)) { if (uri.startsWith(`${this.config.url}/`)) {
const id = uri.split('/').pop(); const id = uri.split('/').pop();
const u = await this.usersRepository.findOneBy({ id }) as LocalUser | null; const u = await this.usersRepository.findOneBy({ id }) as MiLocalUser | null;
if (u) this.cacheService.uriPersonCache.set(uri, u); if (u) this.cacheService.uriPersonCache.set(uri, u);
return u; return u;
} }
//#region このサーバーに既に登録されていたらそれを返す //#region このサーバーに既に登録されていたらそれを返す
const exist = await this.usersRepository.findOneBy({ uri }) as LocalUser | RemoteUser | null; const exist = await this.usersRepository.findOneBy({ uri }) as MiLocalUser | MiRemoteUser | null;
if (exist) { if (exist) {
this.cacheService.uriPersonCache.set(uri, exist); this.cacheService.uriPersonCache.set(uri, exist);
@ -225,7 +225,7 @@ export class ApPersonService implements OnModuleInit {
return null; return null;
} }
private async resolveAvatarAndBanner(user: RemoteUser, icon: any, image: any): Promise<Pick<RemoteUser, 'avatarId' | 'bannerId' | 'avatarUrl' | 'bannerUrl' | 'avatarBlurhash' | 'bannerBlurhash'>> { private async resolveAvatarAndBanner(user: MiRemoteUser, icon: any, image: any): Promise<Pick<MiRemoteUser, 'avatarId' | 'bannerId' | 'avatarUrl' | 'bannerUrl' | 'avatarBlurhash' | 'bannerBlurhash'>> {
const [avatar, banner] = await Promise.all([icon, image].map(img => { const [avatar, banner] = await Promise.all([icon, image].map(img => {
if (img == null) return null; if (img == null) return null;
if (user == null) throw new Error('failed to create user: user is null'); if (user == null) throw new Error('failed to create user: user is null');
@ -246,7 +246,7 @@ export class ApPersonService implements OnModuleInit {
* Personを作成します * Personを作成します
*/ */
@bindThis @bindThis
public async createPerson(uri: string, resolver?: Resolver): Promise<RemoteUser> { public async createPerson(uri: string, resolver?: Resolver): Promise<MiRemoteUser> {
if (typeof uri !== 'string') throw new Error('uri is not string'); if (typeof uri !== 'string') throw new Error('uri is not string');
if (uri.startsWith(this.config.url)) { if (uri.startsWith(this.config.url)) {
@ -280,7 +280,7 @@ export class ApPersonService implements OnModuleInit {
} }
// Create user // Create user
let user: RemoteUser | null = null; let user: MiRemoteUser | null = null;
//#region カスタム絵文字取得 //#region カスタム絵文字取得
const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], host) const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], host)
@ -294,7 +294,7 @@ export class ApPersonService implements OnModuleInit {
try { try {
// Start transaction // Start transaction
await this.db.transaction(async transactionalEntityManager => { await this.db.transaction(async transactionalEntityManager => {
user = await transactionalEntityManager.save(new User({ user = await transactionalEntityManager.save(new MiUser({
id: this.idService.genId(), id: this.idService.genId(),
avatarId: null, avatarId: null,
bannerId: null, bannerId: null,
@ -318,9 +318,9 @@ export class ApPersonService implements OnModuleInit {
isBot, isBot,
isCat: (person as any).isCat === true, isCat: (person as any).isCat === true,
emojis, emojis,
})) as RemoteUser; })) as MiRemoteUser;
await transactionalEntityManager.save(new UserProfile({ await transactionalEntityManager.save(new MiUserProfile({
userId: user.id, userId: user.id,
description: person.summary ? this.apMfmService.htmlToMfm(truncate(person.summary, summaryLength), person.tag) : null, description: person.summary ? this.apMfmService.htmlToMfm(truncate(person.summary, summaryLength), person.tag) : null,
url, url,
@ -331,7 +331,7 @@ export class ApPersonService implements OnModuleInit {
})); }));
if (person.publicKey) { if (person.publicKey) {
await transactionalEntityManager.save(new UserPublickey({ await transactionalEntityManager.save(new MiUserPublickey({
userId: user.id, userId: user.id,
keyId: person.publicKey.id, keyId: person.publicKey.id,
keyPem: person.publicKey.publicKeyPem, keyPem: person.publicKey.publicKeyPem,
@ -345,7 +345,7 @@ export class ApPersonService implements OnModuleInit {
const u = await this.usersRepository.findOneBy({ uri: person.id }); const u = await this.usersRepository.findOneBy({ uri: person.id });
if (u == null) throw new Error('already registered'); if (u == null) throw new Error('already registered');
user = u as RemoteUser; user = u as MiRemoteUser;
} else { } else {
this.logger.error(e instanceof Error ? e : new Error(e as string)); this.logger.error(e instanceof Error ? e : new Error(e as string));
throw e; throw e;
@ -407,7 +407,7 @@ export class ApPersonService implements OnModuleInit {
if (uri.startsWith(`${this.config.url}/`)) return; if (uri.startsWith(`${this.config.url}/`)) return;
//#region このサーバーに既に登録されているか //#region このサーバーに既に登録されているか
const exist = await this.fetchPerson(uri) as RemoteUser | null; const exist = await this.fetchPerson(uri) as MiRemoteUser | null;
if (exist === null) return; if (exist === null) return;
//#endregion //#endregion
@ -456,7 +456,7 @@ export class ApPersonService implements OnModuleInit {
alsoKnownAs: person.alsoKnownAs ?? null, alsoKnownAs: person.alsoKnownAs ?? null,
isExplorable: person.discoverable, isExplorable: person.discoverable,
...(await this.resolveAvatarAndBanner(exist, person.icon, person.image).catch(() => ({}))), ...(await this.resolveAvatarAndBanner(exist, person.icon, person.image).catch(() => ({}))),
} as Partial<RemoteUser> & Pick<RemoteUser, 'isBot' | 'isCat' | 'isLocked' | 'movedToUri' | 'alsoKnownAs' | 'isExplorable'>; } as Partial<MiRemoteUser> & Pick<MiRemoteUser, 'isBot' | 'isCat' | 'isLocked' | 'movedToUri' | 'alsoKnownAs' | 'isExplorable'>;
const moving = ((): boolean => { const moving = ((): boolean => {
// 移行先がない→ある // 移行先がない→ある
@ -542,7 +542,7 @@ export class ApPersonService implements OnModuleInit {
* Misskeyに登録しそれを返します * Misskeyに登録しそれを返します
*/ */
@bindThis @bindThis
public async resolvePerson(uri: string, resolver?: Resolver): Promise<LocalUser | RemoteUser> { public async resolvePerson(uri: string, resolver?: Resolver): Promise<MiLocalUser | MiRemoteUser> {
//#region このサーバーに既に登録されていたらそれを返す //#region このサーバーに既に登録されていたらそれを返す
const exist = await this.fetchPerson(uri); const exist = await this.fetchPerson(uri);
if (exist) return exist; if (exist) return exist;
@ -572,7 +572,7 @@ export class ApPersonService implements OnModuleInit {
} }
@bindThis @bindThis
public async updateFeatured(userId: User['id'], resolver?: Resolver): Promise<void> { public async updateFeatured(userId: MiUser['id'], resolver?: Resolver): Promise<void> {
const user = await this.usersRepository.findOneByOrFail({ id: userId }); const user = await this.usersRepository.findOneByOrFail({ id: userId });
if (!this.userEntityService.isRemoteUser(user)) return; if (!this.userEntityService.isRemoteUser(user)) return;
if (!user.featured) return; if (!user.featured) return;
@ -590,7 +590,7 @@ export class ApPersonService implements OnModuleInit {
const items = await Promise.all(toArray(unresolvedItems).map(x => _resolver.resolve(x))); const items = await Promise.all(toArray(unresolvedItems).map(x => _resolver.resolve(x)));
// Resolve and regist Notes // Resolve and regist Notes
const limit = promiseLimit<Note | null>(2); const limit = promiseLimit<MiNote | null>(2);
const featuredNotes = await Promise.all(items const featuredNotes = await Promise.all(items
.filter(item => getApType(item) === 'Note') // TODO: Noteでなくてもいいかも .filter(item => getApType(item) === 'Note') // TODO: Noteでなくてもいいかも
.slice(0, 5) .slice(0, 5)
@ -600,13 +600,13 @@ export class ApPersonService implements OnModuleInit {
})))); }))));
await this.db.transaction(async transactionalEntityManager => { await this.db.transaction(async transactionalEntityManager => {
await transactionalEntityManager.delete(UserNotePining, { userId: user.id }); await transactionalEntityManager.delete(MiUserNotePining, { userId: user.id });
// とりあえずidを別の時間で生成して順番を維持 // とりあえずidを別の時間で生成して順番を維持
let td = 0; let td = 0;
for (const note of featuredNotes.filter((note): note is Note => note != null)) { for (const note of featuredNotes.filter((note): note is MiNote => note != null)) {
td -= 1000; td -= 1000;
transactionalEntityManager.insert(UserNotePining, { transactionalEntityManager.insert(MiUserNotePining, {
id: this.idService.genId(new Date(Date.now() + td)), id: this.idService.genId(new Date(Date.now() + td)),
createdAt: new Date(), createdAt: new Date(),
userId: user.id, userId: user.id,
@ -622,7 +622,7 @@ export class ApPersonService implements OnModuleInit {
* @param movePreventUris URIにsrc.movedToUriが含まれる場合 * @param movePreventUris URIにsrc.movedToUriが含まれる場合
*/ */
@bindThis @bindThis
private async processRemoteMove(src: RemoteUser, movePreventUris: string[] = []): Promise<string> { private async processRemoteMove(src: MiRemoteUser, movePreventUris: string[] = []): Promise<string> {
if (!src.movedToUri) return 'skip: no movedToUri'; if (!src.movedToUri) return 'skip: no movedToUri';
if (src.uri === src.movedToUri) return 'skip: movedTo itself (src)'; // if (src.uri === src.movedToUri) return 'skip: movedTo itself (src)'; //
if (movePreventUris.length > 10) return 'skip: too many moves'; if (movePreventUris.length > 10) return 'skip: too many moves';
@ -632,7 +632,7 @@ export class ApPersonService implements OnModuleInit {
if (dst && this.userEntityService.isLocalUser(dst)) { if (dst && this.userEntityService.isLocalUser(dst)) {
// targetがローカルユーザーだった場合データベースから引っ張ってくる // targetがローカルユーザーだった場合データベースから引っ張ってくる
dst = await this.usersRepository.findOneByOrFail({ uri: src.movedToUri }) as LocalUser; dst = await this.usersRepository.findOneByOrFail({ uri: src.movedToUri }) as MiLocalUser;
} else if (dst) { } else if (dst) {
if (movePreventUris.includes(src.movedToUri)) return 'skip: circular move'; if (movePreventUris.includes(src.movedToUri)) return 'skip: circular move';

View File

@ -6,7 +6,7 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import Chart from '../core.js'; import Chart from '../core.js';
@ -21,9 +21,8 @@ const year = 1000 * 60 * 60 * 24 * 365;
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class ActiveUsersChart extends Chart<typeof schema> { export default class ActiveUsersChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,
@ -43,7 +42,7 @@ export default class ActiveUsersChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async read(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise<void> { public async read(user: { id: MiUser['id'], host: null, createdAt: MiUser['createdAt'] }): Promise<void> {
await this.commit({ await this.commit({
'read': [user.id], 'read': [user.id],
'registeredWithinWeek': (Date.now() - user.createdAt.getTime() < week) ? [user.id] : [], 'registeredWithinWeek': (Date.now() - user.createdAt.getTime() < week) ? [user.id] : [],
@ -56,7 +55,7 @@ export default class ActiveUsersChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async write(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise<void> { public async write(user: { id: MiUser['id'], host: null, createdAt: MiUser['createdAt'] }): Promise<void> {
await this.commit({ await this.commit({
'write': [user.id], 'write': [user.id],
}); });

View File

@ -16,9 +16,8 @@ import type { KVs } from '../core.js';
/** /**
* Chart about ActivityPub requests * Chart about ActivityPub requests
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class ApRequestChart extends Chart<typeof schema> { export default class ApRequestChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,

View File

@ -5,7 +5,7 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MiDriveFile } from '@/models/entities/DriveFile.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -17,9 +17,8 @@ import type { KVs } from '../core.js';
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class DriveChart extends Chart<typeof schema> { export default class DriveChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,
@ -39,7 +38,7 @@ export default class DriveChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async update(file: DriveFile, isAdditional: boolean): Promise<void> { public async update(file: MiDriveFile, isAdditional: boolean): Promise<void> {
const fileSizeKb = file.size / 1000; const fileSizeKb = file.size / 1000;
await this.commit(file.userHost === null ? { await this.commit(file.userHost === null ? {
'local.incCount': isAdditional ? 1 : 0, 'local.incCount': isAdditional ? 1 : 0,

View File

@ -18,9 +18,8 @@ import type { KVs } from '../core.js';
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class FederationChart extends Chart<typeof schema> { export default class FederationChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,

View File

@ -6,8 +6,8 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import type { DriveFilesRepository, FollowingsRepository, UsersRepository, NotesRepository } from '@/models/index.js'; import type { DriveFilesRepository, FollowingsRepository, UsersRepository, NotesRepository } from '@/models/index.js';
import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MiDriveFile } from '@/models/entities/DriveFile.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { UtilityService } from '@/core/UtilityService.js'; import { UtilityService } from '@/core/UtilityService.js';
@ -20,9 +20,8 @@ import type { KVs } from '../core.js';
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class InstanceChart extends Chart<typeof schema> { export default class InstanceChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,
@ -98,7 +97,7 @@ export default class InstanceChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async updateNote(host: string, note: Note, isAdditional: boolean): Promise<void> { public async updateNote(host: string, note: MiNote, isAdditional: boolean): Promise<void> {
await this.commit({ await this.commit({
'notes.total': isAdditional ? 1 : -1, 'notes.total': isAdditional ? 1 : -1,
'notes.inc': isAdditional ? 1 : 0, 'notes.inc': isAdditional ? 1 : 0,
@ -129,7 +128,7 @@ export default class InstanceChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async updateDrive(file: DriveFile, isAdditional: boolean): Promise<void> { public async updateDrive(file: MiDriveFile, isAdditional: boolean): Promise<void> {
const fileSizeKb = file.size / 1000; const fileSizeKb = file.size / 1000;
await this.commit({ await this.commit({
'drive.totalFiles': isAdditional ? 1 : -1, 'drive.totalFiles': isAdditional ? 1 : -1,

View File

@ -6,7 +6,7 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { Not, IsNull, DataSource } from 'typeorm'; import { Not, IsNull, DataSource } from 'typeorm';
import type { NotesRepository } from '@/models/index.js'; import type { NotesRepository } from '@/models/index.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -18,9 +18,8 @@ import type { KVs } from '../core.js';
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class NotesChart extends Chart<typeof schema> { export default class NotesChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,
@ -51,7 +50,7 @@ export default class NotesChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async update(note: Note, isAdditional: boolean): Promise<void> { public async update(note: MiNote, isAdditional: boolean): Promise<void> {
const prefix = note.userHost === null ? 'local' : 'remote'; const prefix = note.userHost === null ? 'local' : 'remote';
await this.commit({ await this.commit({

View File

@ -6,7 +6,7 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import type { DriveFilesRepository } from '@/models/index.js'; import type { DriveFilesRepository } from '@/models/index.js';
import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MiDriveFile } from '@/models/entities/DriveFile.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
@ -19,9 +19,8 @@ import type { KVs } from '../core.js';
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class PerUserDriveChart extends Chart<typeof schema> { export default class PerUserDriveChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,
@ -53,7 +52,7 @@ export default class PerUserDriveChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async update(file: DriveFile, isAdditional: boolean): Promise<void> { public async update(file: MiDriveFile, isAdditional: boolean): Promise<void> {
const fileSizeKb = file.size / 1000; const fileSizeKb = file.size / 1000;
await this.commit({ await this.commit({
'totalCount': isAdditional ? 1 : -1, 'totalCount': isAdditional ? 1 : -1,

View File

@ -5,7 +5,7 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { Not, IsNull, DataSource } from 'typeorm'; import { Not, IsNull, DataSource } from 'typeorm';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
@ -19,9 +19,8 @@ import type { KVs } from '../core.js';
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class PerUserFollowingChart extends Chart<typeof schema> { export default class PerUserFollowingChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,
@ -62,7 +61,7 @@ export default class PerUserFollowingChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async update(follower: { id: User['id']; host: User['host']; }, followee: { id: User['id']; host: User['host']; }, isFollow: boolean): Promise<void> { public async update(follower: { id: MiUser['id']; host: MiUser['host']; }, followee: { id: MiUser['id']; host: MiUser['host']; }, isFollow: boolean): Promise<void> {
const prefixFollower = this.userEntityService.isLocalUser(follower) ? 'local' : 'remote'; const prefixFollower = this.userEntityService.isLocalUser(follower) ? 'local' : 'remote';
const prefixFollowee = this.userEntityService.isLocalUser(followee) ? 'local' : 'remote'; const prefixFollowee = this.userEntityService.isLocalUser(followee) ? 'local' : 'remote';

View File

@ -5,8 +5,8 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { NotesRepository } from '@/models/index.js'; import type { NotesRepository } from '@/models/index.js';
@ -19,9 +19,8 @@ import type { KVs } from '../core.js';
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class PerUserNotesChart extends Chart<typeof schema> { export default class PerUserNotesChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,
@ -50,7 +49,7 @@ export default class PerUserNotesChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public update(user: { id: User['id'] }, note: Note, isAdditional: boolean): void { public update(user: { id: MiUser['id'] }, note: MiNote, isAdditional: boolean): void {
this.commit({ this.commit({
'total': isAdditional ? 1 : -1, 'total': isAdditional ? 1 : -1,
'inc': isAdditional ? 1 : 0, 'inc': isAdditional ? 1 : 0,

View File

@ -5,7 +5,7 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
@ -17,9 +17,8 @@ import type { KVs } from '../core.js';
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class PerUserPvChart extends Chart<typeof schema> { export default class PerUserPvChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,
@ -39,7 +38,7 @@ export default class PerUserPvChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async commitByUser(user: { id: User['id'] }, key: string): Promise<void> { public async commitByUser(user: { id: MiUser['id'] }, key: string): Promise<void> {
await this.commit({ await this.commit({
'upv.user': [key], 'upv.user': [key],
'pv.user': 1, 'pv.user': 1,
@ -47,7 +46,7 @@ export default class PerUserPvChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async commitByVisitor(user: { id: User['id'] }, key: string): Promise<void> { public async commitByVisitor(user: { id: MiUser['id'] }, key: string): Promise<void> {
await this.commit({ await this.commit({
'upv.visitor': [key], 'upv.visitor': [key],
'pv.visitor': 1, 'pv.visitor': 1,

View File

@ -5,8 +5,8 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import type { Note } from '@/models/entities/Note.js'; import type { MiNote } from '@/models/entities/Note.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
@ -19,9 +19,8 @@ import type { KVs } from '../core.js';
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class PerUserReactionsChart extends Chart<typeof schema> { export default class PerUserReactionsChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,
@ -42,7 +41,7 @@ export default class PerUserReactionsChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async update(user: { id: User['id'], host: User['host'] }, note: Note): Promise<void> { public async update(user: { id: MiUser['id'], host: MiUser['host'] }, note: MiNote): Promise<void> {
const prefix = this.userEntityService.isLocalUser(user) ? 'local' : 'remote'; const prefix = this.userEntityService.isLocalUser(user) ? 'local' : 'remote';
this.commit({ this.commit({
[`${prefix}.count`]: 1, [`${prefix}.count`]: 1,

View File

@ -16,9 +16,8 @@ import type { KVs } from '../core.js';
/** /**
* For testing * For testing
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class TestGroupedChart extends Chart<typeof schema> { export default class TestGroupedChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
private total = {} as Record<string, number>; private total = {} as Record<string, number>;
constructor( constructor(

View File

@ -16,9 +16,8 @@ import type { KVs } from '../core.js';
/** /**
* For testing * For testing
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class TestIntersectionChart extends Chart<typeof schema> { export default class TestIntersectionChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,

View File

@ -16,9 +16,8 @@ import type { KVs } from '../core.js';
/** /**
* For testing * For testing
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class TestUniqueChart extends Chart<typeof schema> { export default class TestUniqueChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,

View File

@ -16,9 +16,8 @@ import type { KVs } from '../core.js';
/** /**
* For testing * For testing
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class TestChart extends Chart<typeof schema> { export default class TestChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
public total = 0; // publicにするのはテストのため public total = 0; // publicにするのはテストのため
constructor( constructor(

View File

@ -5,7 +5,7 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { Not, IsNull, DataSource } from 'typeorm'; import { Not, IsNull, DataSource } from 'typeorm';
import type { User } from '@/models/entities/User.js'; import type { MiUser } from '@/models/entities/User.js';
import { AppLockService } from '@/core/AppLockService.js'; import { AppLockService } from '@/core/AppLockService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
@ -19,9 +19,8 @@ import type { KVs } from '../core.js';
/** /**
* *
*/ */
// eslint-disable-next-line import/no-default-export
@Injectable() @Injectable()
export default class UsersChart extends Chart<typeof schema> { export default class UsersChart extends Chart<typeof schema> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.db) @Inject(DI.db)
private db: DataSource, private db: DataSource,
@ -53,7 +52,7 @@ export default class UsersChart extends Chart<typeof schema> {
} }
@bindThis @bindThis
public async update(user: { id: User['id'], host: User['host'] }, isAdditional: boolean): Promise<void> { public async update(user: { id: MiUser['id'], host: MiUser['host'] }, isAdditional: boolean): Promise<void> {
const prefix = this.userEntityService.isLocalUser(user) ? 'local' : 'remote'; const prefix = this.userEntityService.isLocalUser(user) ? 'local' : 'remote';
await this.commit({ await this.commit({

View File

@ -7,7 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type { AbuseUserReportsRepository } from '@/models/index.js'; import type { AbuseUserReportsRepository } from '@/models/index.js';
import { awaitAll } from '@/misc/prelude/await-all.js'; import { awaitAll } from '@/misc/prelude/await-all.js';
import type { AbuseUserReport } from '@/models/entities/AbuseUserReport.js'; import type { MiAbuseUserReport } from '@/models/entities/AbuseUserReport.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { UserEntityService } from './UserEntityService.js'; import { UserEntityService } from './UserEntityService.js';
@ -23,7 +23,7 @@ export class AbuseUserReportEntityService {
@bindThis @bindThis
public async pack( public async pack(
src: AbuseUserReport['id'] | AbuseUserReport, src: MiAbuseUserReport['id'] | MiAbuseUserReport,
) { ) {
const report = typeof src === 'object' ? src : await this.abuseUserReportsRepository.findOneByOrFail({ id: src }); const report = typeof src === 'object' ? src : await this.abuseUserReportsRepository.findOneByOrFail({ id: src });

Some files were not shown because too many files have changed in this diff Show More