commit
e57b536767
2
.github/workflows/api-misskey-js.yml
vendored
2
.github/workflows/api-misskey-js.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.0.0
|
uses: actions/checkout@v4.1.0
|
||||||
|
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
|
|
||||||
|
|
2
.github/workflows/check_copyright_year.yml
vendored
2
.github/workflows/check_copyright_year.yml
vendored
|
@ -10,7 +10,7 @@ jobs:
|
||||||
check_copyright_year:
|
check_copyright_year:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.0.0
|
- uses: actions/checkout@v4.1.0
|
||||||
- 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!"
|
||||||
|
|
2
.github/workflows/docker-develop.yml
vendored
2
.github/workflows/docker-develop.yml
vendored
|
@ -13,7 +13,7 @@ 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@v4.0.0
|
uses: actions/checkout@v4.1.0
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v3.0.0
|
uses: docker/setup-buildx-action@v3.0.0
|
||||||
|
|
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
|
@ -12,7 +12,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v4.0.0
|
uses: actions/checkout@v4.1.0
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v3.0.0
|
uses: docker/setup-buildx-action@v3.0.0
|
||||||
|
|
2
.github/workflows/dockle.yml
vendored
2
.github/workflows/dockle.yml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
DOCKER_CONTENT_TRUST: 1
|
DOCKER_CONTENT_TRUST: 1
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.0.0
|
- uses: actions/checkout@v4.1.0
|
||||||
- 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
|
||||||
|
|
6
.github/workflows/lint.yml
vendored
6
.github/workflows/lint.yml
vendored
|
@ -11,7 +11,7 @@ jobs:
|
||||||
pnpm_install:
|
pnpm_install:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.0.0
|
- uses: actions/checkout@v4.1.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
|
@ -38,7 +38,7 @@ jobs:
|
||||||
- sw
|
- sw
|
||||||
- misskey-js
|
- misskey-js
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.0.0
|
- uses: actions/checkout@v4.1.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
|
@ -64,7 +64,7 @@ jobs:
|
||||||
- backend
|
- backend
|
||||||
- misskey-js
|
- misskey-js
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.0.0
|
- uses: actions/checkout@v4.1.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
2
.github/workflows/pr-preview-deploy.yml
vendored
2
.github/workflows/pr-preview-deploy.yml
vendored
|
@ -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@v4.0.0
|
uses: actions/checkout@v4.1.0
|
||||||
with:
|
with:
|
||||||
ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge'
|
ref: 'refs/pull/${{ github.event.client_payload.pull_request.number }}/merge'
|
||||||
|
|
||||||
|
|
2
.github/workflows/test-backend.yml
vendored
2
.github/workflows/test-backend.yml
vendored
|
@ -29,7 +29,7 @@ jobs:
|
||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.0.0
|
- uses: actions/checkout@v4.1.0
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
|
|
4
.github/workflows/test-frontend.yml
vendored
4
.github/workflows/test-frontend.yml
vendored
|
@ -16,7 +16,7 @@ jobs:
|
||||||
node-version: [20.5.1]
|
node-version: [20.5.1]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.0.0
|
- uses: actions/checkout@v4.1.0
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
|
@ -68,7 +68,7 @@ jobs:
|
||||||
- 56312:6379
|
- 56312:6379
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.0.0
|
- uses: actions/checkout@v4.1.0
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
# https://github.com/cypress-io/cypress-docker-images/issues/150
|
# https://github.com/cypress-io/cypress-docker-images/issues/150
|
||||||
|
|
2
.github/workflows/test-misskey-js.yml
vendored
2
.github/workflows/test-misskey-js.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.0.0
|
uses: actions/checkout@v4.1.0
|
||||||
|
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
|
|
||||||
|
|
2
.github/workflows/test-production.yml
vendored
2
.github/workflows/test-production.yml
vendored
|
@ -19,7 +19,7 @@ jobs:
|
||||||
node-version: [20.5.1]
|
node-version: [20.5.1]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.0.0
|
- uses: actions/checkout@v4.1.0
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -12,7 +12,19 @@
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## 2023.9.0 (unreleased)
|
## 2023.9.1
|
||||||
|
|
||||||
|
### General
|
||||||
|
- Enhance: モデレーションログ機能の強化
|
||||||
|
|
||||||
|
### Client
|
||||||
|
- Fix: ノートのメニューにある「詳細」ボタンの表示がログイン/ログアウト状態で統一されていない問題を修正
|
||||||
|
|
||||||
|
### Server
|
||||||
|
- Fix: お知らせのページネーションが機能しない
|
||||||
|
- Fix: 「ユーザーの新規投稿」の通知設定を切り替えるとサーバー内部エラーが出る
|
||||||
|
|
||||||
|
## 2023.9.0
|
||||||
|
|
||||||
### Note
|
### Note
|
||||||
- meilisearchを使用する場合、v1.2以上が必要です
|
- meilisearchを使用する場合、v1.2以上が必要です
|
||||||
|
@ -98,6 +110,7 @@
|
||||||
- Enhance: 自分へのメンション一覧を取得する際のパフォーマンスを向上
|
- Enhance: 自分へのメンション一覧を取得する際のパフォーマンスを向上
|
||||||
- Enhance: Docker環境でjemallocを使用することでメモリ使用量を削減
|
- Enhance: Docker環境でjemallocを使用することでメモリ使用量を削減
|
||||||
- Enhance: ID生成方式としてaidxを追加、かつデフォルトに
|
- Enhance: ID生成方式としてaidxを追加、かつデフォルトに
|
||||||
|
- Enhance: Add address bind config option (outgoingAddress)
|
||||||
- Fix: MK_ONLY_SERVERオプションを指定した際にクラッシュする問題を修正
|
- Fix: MK_ONLY_SERVERオプションを指定した際にクラッシュする問題を修正
|
||||||
- Fix: notes/reactionsのページネーションが機能しない問題を修正
|
- Fix: notes/reactionsのページネーションが機能しない問題を修正
|
||||||
- Fix: ノート検索 `notes/search` にてhostを指定した際に検索結果に反映されるように
|
- Fix: ノート検索 `notes/search` にてhostを指定した際に検索結果に反映されるように
|
||||||
|
@ -120,7 +133,6 @@
|
||||||
### Server
|
### Server
|
||||||
- Fix: APIのオフセットが壊れていたせいで「もっと見る」でもっと見れない問題を修正
|
- Fix: APIのオフセットが壊れていたせいで「もっと見る」でもっと見れない問題を修正
|
||||||
- Fix: 外部サーバーの投稿がタイムラインに表示されないことがある問題を修正
|
- Fix: 外部サーバーの投稿がタイムラインに表示されないことがある問題を修正
|
||||||
- Enhance: Add address bind config option (outgoingAddress)
|
|
||||||
|
|
||||||
## 13.14.1
|
## 13.14.1
|
||||||
|
|
||||||
|
|
|
@ -2101,9 +2101,9 @@ _webhookSettings:
|
||||||
reaction: "Wenn du eine Reaktion erhältst"
|
reaction: "Wenn du eine Reaktion erhältst"
|
||||||
mention: "Wenn du erwähnt wirst"
|
mention: "Wenn du erwähnt wirst"
|
||||||
_moderationLogTypes:
|
_moderationLogTypes:
|
||||||
|
updateRole: "Rolle aktualisiert"
|
||||||
assignRole: "Zu Rolle zugewiesen"
|
assignRole: "Zu Rolle zugewiesen"
|
||||||
unassignRole: "Aus Rolle entfernt"
|
unassignRole: "Aus Rolle entfernt"
|
||||||
updateRole: "Rolle aktualisiert"
|
|
||||||
suspend: "Gesperrt"
|
suspend: "Gesperrt"
|
||||||
unsuspend: "Entsperrt"
|
unsuspend: "Entsperrt"
|
||||||
addCustomEmoji: "Benutzerdefiniertes Emoji hinzugefügt"
|
addCustomEmoji: "Benutzerdefiniertes Emoji hinzugefügt"
|
||||||
|
|
|
@ -2101,9 +2101,9 @@ _webhookSettings:
|
||||||
reaction: "When receiving a reaction"
|
reaction: "When receiving a reaction"
|
||||||
mention: "When being mentioned"
|
mention: "When being mentioned"
|
||||||
_moderationLogTypes:
|
_moderationLogTypes:
|
||||||
|
updateRole: "Role updated"
|
||||||
assignRole: "Assigned to role"
|
assignRole: "Assigned to role"
|
||||||
unassignRole: "Removed from role"
|
unassignRole: "Removed from role"
|
||||||
updateRole: "Role updated"
|
|
||||||
suspend: "Suspended"
|
suspend: "Suspended"
|
||||||
unsuspend: "Unsuspended"
|
unsuspend: "Unsuspended"
|
||||||
addCustomEmoji: "Custom emoji added"
|
addCustomEmoji: "Custom emoji added"
|
||||||
|
|
6
locales/index.d.ts
vendored
6
locales/index.d.ts
vendored
|
@ -1123,6 +1123,7 @@ export interface Locale {
|
||||||
"unnotifyNotes": string;
|
"unnotifyNotes": string;
|
||||||
"authentication": string;
|
"authentication": string;
|
||||||
"authenticationRequiredToContinue": string;
|
"authenticationRequiredToContinue": string;
|
||||||
|
"dateAndTime": string;
|
||||||
"_announcement": {
|
"_announcement": {
|
||||||
"forExistingUsers": string;
|
"forExistingUsers": string;
|
||||||
"forExistingUsersDescription": string;
|
"forExistingUsersDescription": string;
|
||||||
|
@ -2250,9 +2251,11 @@ export interface Locale {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"_moderationLogTypes": {
|
"_moderationLogTypes": {
|
||||||
|
"createRole": string;
|
||||||
|
"deleteRole": string;
|
||||||
|
"updateRole": string;
|
||||||
"assignRole": string;
|
"assignRole": string;
|
||||||
"unassignRole": string;
|
"unassignRole": string;
|
||||||
"updateRole": string;
|
|
||||||
"suspend": string;
|
"suspend": string;
|
||||||
"unsuspend": string;
|
"unsuspend": string;
|
||||||
"addCustomEmoji": string;
|
"addCustomEmoji": string;
|
||||||
|
@ -2273,6 +2276,7 @@ export interface Locale {
|
||||||
"unsuspendRemoteInstance": string;
|
"unsuspendRemoteInstance": string;
|
||||||
"markSensitiveDriveFile": string;
|
"markSensitiveDriveFile": string;
|
||||||
"unmarkSensitiveDriveFile": string;
|
"unmarkSensitiveDriveFile": string;
|
||||||
|
"resolveAbuseReport": string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
declare const locales: {
|
declare const locales: {
|
||||||
|
|
|
@ -2031,7 +2031,7 @@ _notification:
|
||||||
_types:
|
_types:
|
||||||
all: "Tutto"
|
all: "Tutto"
|
||||||
note: "Nuove Note"
|
note: "Nuove Note"
|
||||||
follow: "Novità follower"
|
follow: "Nuovi profili follower"
|
||||||
mention: "Menzioni"
|
mention: "Menzioni"
|
||||||
reply: "Risposte"
|
reply: "Risposte"
|
||||||
renote: "Rinota"
|
renote: "Rinota"
|
||||||
|
@ -2101,18 +2101,26 @@ _webhookSettings:
|
||||||
reaction: "Quando ricevo una reazione"
|
reaction: "Quando ricevo una reazione"
|
||||||
mention: "Quando mi menzionano"
|
mention: "Quando mi menzionano"
|
||||||
_moderationLogTypes:
|
_moderationLogTypes:
|
||||||
assignRole: "Assegna un ruolo"
|
updateRole: "Ruolo aggiornato"
|
||||||
unassignRole: "Disassegna un ruolo"
|
assignRole: "Ruolo assegnato"
|
||||||
updateRole: "Aggiorna un ruolo"
|
unassignRole: "Ruolo disassegnato"
|
||||||
suspend: "Sospensione"
|
suspend: "Sospensione"
|
||||||
unsuspend: "Toglie la sospensione"
|
unsuspend: "Sospensione rimossa"
|
||||||
addCustomEmoji: "Aggiunge una emoji personalizzata"
|
addCustomEmoji: "Emoji personalizzata aggiunta"
|
||||||
updateServerSettings: "Aggiorna le impostazioni del server"
|
updateCustomEmoji: "Emoji personalizzata aggiornata"
|
||||||
updateUserNote: "Aggiorna il promemoria di moderazione"
|
deleteCustomEmoji: "Emoji personalizzata eliminata"
|
||||||
deleteDriveFile: "Elimina file da Drive"
|
updateServerSettings: "Impostazioni del server aggiornate"
|
||||||
deleteNote: "Elimina la Nota"
|
updateUserNote: "Promemoria di moderazione aggiornato"
|
||||||
createGlobalAnnouncement: "Crea un annuncio globale"
|
deleteDriveFile: "File da Drive eliminato"
|
||||||
createUserAnnouncement: "Crea un annuncio ai profili iscritti"
|
deleteNote: "Nota eliminata"
|
||||||
resetPassword: "Ripristina la password"
|
createGlobalAnnouncement: "Annuncio globale creato"
|
||||||
suspendRemoteInstance: "Sospendi istanza remota"
|
createUserAnnouncement: "Annuncio ai profili iscritti creato"
|
||||||
unsuspendRemoteInstance: "Riattiva istanza remota"
|
updateGlobalAnnouncement: "Annuncio globale aggiornato"
|
||||||
|
updateUserAnnouncement: "Annuncio ai profili iscritti aggiornato"
|
||||||
|
deleteGlobalAnnouncement: "Annuncio globale eliminato"
|
||||||
|
deleteUserAnnouncement: "Annuncio ai profili iscritti eliminato"
|
||||||
|
resetPassword: "Password azzerata"
|
||||||
|
suspendRemoteInstance: "Istanza remota sospesa"
|
||||||
|
unsuspendRemoteInstance: "Istanza remota riattivata"
|
||||||
|
markSensitiveDriveFile: "File nel Drive segnato come esplicito"
|
||||||
|
unmarkSensitiveDriveFile: "File nel Drive segnato come non esplicito"
|
||||||
|
|
|
@ -1120,6 +1120,7 @@ notifyNotes: "投稿を通知"
|
||||||
unnotifyNotes: "投稿の通知を解除"
|
unnotifyNotes: "投稿の通知を解除"
|
||||||
authentication: "認証"
|
authentication: "認証"
|
||||||
authenticationRequiredToContinue: "続けるには認証を行ってください"
|
authenticationRequiredToContinue: "続けるには認証を行ってください"
|
||||||
|
dateAndTime: "日時"
|
||||||
|
|
||||||
_announcement:
|
_announcement:
|
||||||
forExistingUsers: "既存ユーザーのみ"
|
forExistingUsers: "既存ユーザーのみ"
|
||||||
|
@ -2163,9 +2164,11 @@ _webhookSettings:
|
||||||
mention: "メンションされたとき"
|
mention: "メンションされたとき"
|
||||||
|
|
||||||
_moderationLogTypes:
|
_moderationLogTypes:
|
||||||
|
createRole: "ロールを作成"
|
||||||
|
deleteRole: "ロールを削除"
|
||||||
|
updateRole: "ロールを更新"
|
||||||
assignRole: "ロールへアサイン"
|
assignRole: "ロールへアサイン"
|
||||||
unassignRole: "ロールのアサイン解除"
|
unassignRole: "ロールのアサイン解除"
|
||||||
updateRole: "ロール設定更新"
|
|
||||||
suspend: "凍結"
|
suspend: "凍結"
|
||||||
unsuspend: "凍結解除"
|
unsuspend: "凍結解除"
|
||||||
addCustomEmoji: "カスタム絵文字追加"
|
addCustomEmoji: "カスタム絵文字追加"
|
||||||
|
@ -2186,3 +2189,4 @@ _moderationLogTypes:
|
||||||
unsuspendRemoteInstance: "リモートサーバーを再開"
|
unsuspendRemoteInstance: "リモートサーバーを再開"
|
||||||
markSensitiveDriveFile: "ファイルをセンシティブ付与"
|
markSensitiveDriveFile: "ファイルをセンシティブ付与"
|
||||||
unmarkSensitiveDriveFile: "ファイルをセンシティブ解除"
|
unmarkSensitiveDriveFile: "ファイルをセンシティブ解除"
|
||||||
|
resolveAbuseReport: "通報を解決"
|
||||||
|
|
|
@ -2101,9 +2101,9 @@ _webhookSettings:
|
||||||
reaction: "被回应时"
|
reaction: "被回应时"
|
||||||
mention: "被提及时"
|
mention: "被提及时"
|
||||||
_moderationLogTypes:
|
_moderationLogTypes:
|
||||||
|
updateRole: "更新角色"
|
||||||
assignRole: "分配角色"
|
assignRole: "分配角色"
|
||||||
unassignRole: "取消分配角色"
|
unassignRole: "取消分配角色"
|
||||||
updateRole: "更新角色"
|
|
||||||
suspend: "冻结"
|
suspend: "冻结"
|
||||||
unsuspend: "解除冻结"
|
unsuspend: "解除冻结"
|
||||||
addCustomEmoji: "添加自定义表情符号"
|
addCustomEmoji: "添加自定义表情符号"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
_lang_: "繁體中文"
|
_lang_: "繁體中文(台灣)"
|
||||||
headlineMisskey: "貼文連繫網絡"
|
headlineMisskey: "貼文連繫網路"
|
||||||
introMisskey: "歡迎!Misskey 是一個開放原始碼且去中心化的社群網路服務。\n發布「貼文」向身邊的人分享您的想法!📡\n利用「反應」表達您對貼文的感覺!👍\n讓我們一起探索新的世界吧!🚀"
|
introMisskey: "歡迎!Misskey 是一個開放原始碼且去中心化的社群網路服務。\n發布「貼文」向身邊的人分享您的想法!📡\n利用「反應」表達您對貼文的感覺!👍\n讓我們一起探索新的世界吧!🚀"
|
||||||
poweredByMisskeyDescription: "{name}是開放原始碼平臺 <b>Misskey</b> 的伺服器之一。"
|
poweredByMisskeyDescription: "{name}是開放原始碼平臺 <b>Misskey</b> 的伺服器之一。"
|
||||||
monthAndDay: "{month} 月 {day} 日"
|
monthAndDay: "{month} 月 {day} 日"
|
||||||
|
@ -45,7 +45,7 @@ pin: "置頂"
|
||||||
unpin: "取消置頂"
|
unpin: "取消置頂"
|
||||||
copyContent: "複製內容"
|
copyContent: "複製內容"
|
||||||
copyLink: "複製連結"
|
copyLink: "複製連結"
|
||||||
copyLinkRenote: "複製轉貼連結"
|
copyLinkRenote: "複製轉發的連結"
|
||||||
delete: "刪除"
|
delete: "刪除"
|
||||||
deleteAndEdit: "刪除並編輯"
|
deleteAndEdit: "刪除並編輯"
|
||||||
deleteAndEditConfirm: "要刪除並再次編輯嗎?此貼文的所有反應、轉發和回覆也將會消失。"
|
deleteAndEditConfirm: "要刪除並再次編輯嗎?此貼文的所有反應、轉發和回覆也將會消失。"
|
||||||
|
@ -107,7 +107,7 @@ followRequestPending: "追隨許可待批准"
|
||||||
enterEmoji: "輸入表情符號"
|
enterEmoji: "輸入表情符號"
|
||||||
renote: "轉發"
|
renote: "轉發"
|
||||||
unrenote: "取消轉發"
|
unrenote: "取消轉發"
|
||||||
renoted: "轉發成功"
|
renoted: "轉發成功。"
|
||||||
cantRenote: "無法轉發此貼文。"
|
cantRenote: "無法轉發此貼文。"
|
||||||
cantReRenote: "無法轉發之前已經轉發過的內容。"
|
cantReRenote: "無法轉發之前已經轉發過的內容。"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
|
@ -138,8 +138,8 @@ suspend: "凍結"
|
||||||
unsuspend: "解除凍結"
|
unsuspend: "解除凍結"
|
||||||
blockConfirm: "確定要封鎖此使用者嗎?"
|
blockConfirm: "確定要封鎖此使用者嗎?"
|
||||||
unblockConfirm: "確定要解除封鎖此使用者嗎?"
|
unblockConfirm: "確定要解除封鎖此使用者嗎?"
|
||||||
suspendConfirm: "確定凍結此帳戶?"
|
suspendConfirm: "確定凍結此使用者?"
|
||||||
unsuspendConfirm: "確定解凍此帳戶?"
|
unsuspendConfirm: "確定解凍此使用者?"
|
||||||
selectList: "選擇清單"
|
selectList: "選擇清單"
|
||||||
editList: "編輯清單"
|
editList: "編輯清單"
|
||||||
selectChannel: "選擇頻道"
|
selectChannel: "選擇頻道"
|
||||||
|
@ -152,12 +152,12 @@ customEmojis: "自訂表情符號"
|
||||||
emoji: "表情符號"
|
emoji: "表情符號"
|
||||||
emojis: "表情符號"
|
emojis: "表情符號"
|
||||||
emojiName: "表情符號名稱"
|
emojiName: "表情符號名稱"
|
||||||
emojiUrl: "表情符號URL"
|
emojiUrl: "表情符號 URL"
|
||||||
addEmoji: "新增表情符號"
|
addEmoji: "新增表情符號"
|
||||||
settingGuide: "推薦設定"
|
settingGuide: "推薦設定"
|
||||||
cacheRemoteFiles: "快取遠端檔案"
|
cacheRemoteFiles: "快取遠端檔案"
|
||||||
cacheRemoteFilesDescription: "禁用此設定會停止建立遠端檔案快取,從而節省伺服器儲存空間,但會因從遠端讀取資料而增加網路數據用量。"
|
cacheRemoteFilesDescription: "啟用此設定後,遠端檔案會被快取在本伺服器的儲存空間中。雖然顯示圖片會變快,但會消耗較多伺服器的儲存空間。至於要快取遠端使用者到什麼程度,是依照角色的雲端硬碟容量而定。當超過這個限制時,從較舊的檔案開始自快取中刪除並改為連結。關閉這個設定時,遠端檔案從一開始就維持連結的方式,但為了產生圖片的縮圖並保護使用者的隱私,建議將 default.yml 的 proxyRemoteFiles 設為 true。"
|
||||||
youCanCleanRemoteFilesCache: "按檔案管理的🗑️按鈕,將快取全部刪除。"
|
youCanCleanRemoteFilesCache: "按檔案管理的🗑️按鈕,可將快取全部刪除。"
|
||||||
cacheRemoteSensitiveFiles: "快取遠端的敏感檔案"
|
cacheRemoteSensitiveFiles: "快取遠端的敏感檔案"
|
||||||
cacheRemoteSensitiveFilesDescription: "若停用這個設定,則不會快取遠端的敏感檔案,而是直接連結。"
|
cacheRemoteSensitiveFilesDescription: "若停用這個設定,則不會快取遠端的敏感檔案,而是直接連結。"
|
||||||
flagAsBot: "此使用者是機器人"
|
flagAsBot: "此使用者是機器人"
|
||||||
|
@ -424,7 +424,7 @@ securityKeyAndPasskey: "安全金鑰、Passkey"
|
||||||
securityKey: "安全金鑰"
|
securityKey: "安全金鑰"
|
||||||
lastUsed: "上次使用"
|
lastUsed: "上次使用"
|
||||||
lastUsedAt: "上次使用:{t}"
|
lastUsedAt: "上次使用:{t}"
|
||||||
unregister: "註銷帳戶"
|
unregister: "註銷"
|
||||||
passwordLessLogin: "設置無密碼登入"
|
passwordLessLogin: "設置無密碼登入"
|
||||||
passwordLessLoginDescription: "不使用密碼,以安全金鑰或 Passkey 登入"
|
passwordLessLoginDescription: "不使用密碼,以安全金鑰或 Passkey 登入"
|
||||||
resetPassword: "重設密碼"
|
resetPassword: "重設密碼"
|
||||||
|
@ -509,8 +509,8 @@ promote: "推廣"
|
||||||
numberOfDays: "有效天數"
|
numberOfDays: "有效天數"
|
||||||
hideThisNote: "隱藏此貼文"
|
hideThisNote: "隱藏此貼文"
|
||||||
showFeaturedNotesInTimeline: "在時間軸上顯示熱門推薦"
|
showFeaturedNotesInTimeline: "在時間軸上顯示熱門推薦"
|
||||||
objectStorage: "對象存儲"
|
objectStorage: "物件儲存"
|
||||||
useObjectStorage: "使用對象存儲"
|
useObjectStorage: "使用物件儲存"
|
||||||
objectStorageBaseUrl: "Base URL"
|
objectStorageBaseUrl: "Base URL"
|
||||||
objectStorageBaseUrlDesc: "用於引用的 URL。如果您使用的是 CDN 或反向代理,請指定其 URL,例如 S3(https://<bucket>.s3.amazonaws.com)、GCS(https://storage.googleapis.com/<bucket>)。"
|
objectStorageBaseUrlDesc: "用於引用的 URL。如果您使用的是 CDN 或反向代理,請指定其 URL,例如 S3(https://<bucket>.s3.amazonaws.com)、GCS(https://storage.googleapis.com/<bucket>)。"
|
||||||
objectStorageBucket: "儲存空間(Bucket)"
|
objectStorageBucket: "儲存空間(Bucket)"
|
||||||
|
@ -1120,6 +1120,7 @@ notifyNotes: "開啟貼文通知"
|
||||||
unnotifyNotes: "關閉貼文通知"
|
unnotifyNotes: "關閉貼文通知"
|
||||||
authentication: "驗證"
|
authentication: "驗證"
|
||||||
authenticationRequiredToContinue: "請於繼續前完成驗證"
|
authenticationRequiredToContinue: "請於繼續前完成驗證"
|
||||||
|
dateAndTime: "日期與時間"
|
||||||
_announcement:
|
_announcement:
|
||||||
forExistingUsers: "僅限既有的使用者"
|
forExistingUsers: "僅限既有的使用者"
|
||||||
forExistingUsersDescription: "啟用代表僅向現存使用者顯示;停用代表張貼後註冊的新使用者也會看到。"
|
forExistingUsersDescription: "啟用代表僅向現存使用者顯示;停用代表張貼後註冊的新使用者也會看到。"
|
||||||
|
@ -2101,9 +2102,11 @@ _webhookSettings:
|
||||||
reaction: "當獲得反應時"
|
reaction: "當獲得反應時"
|
||||||
mention: "當被提到時"
|
mention: "當被提到時"
|
||||||
_moderationLogTypes:
|
_moderationLogTypes:
|
||||||
|
createRole: "新增角色"
|
||||||
|
deleteRole: "刪除角色 "
|
||||||
|
updateRole: "更新角色設定"
|
||||||
assignRole: "指派角色"
|
assignRole: "指派角色"
|
||||||
unassignRole: "撤銷角色"
|
unassignRole: "撤銷角色"
|
||||||
updateRole: "更新角色設定"
|
|
||||||
suspend: "凍結"
|
suspend: "凍結"
|
||||||
unsuspend: "解除凍結"
|
unsuspend: "解除凍結"
|
||||||
addCustomEmoji: "新增自訂表情符號"
|
addCustomEmoji: "新增自訂表情符號"
|
||||||
|
@ -2122,3 +2125,5 @@ _moderationLogTypes:
|
||||||
resetPassword: "重設密碼"
|
resetPassword: "重設密碼"
|
||||||
suspendRemoteInstance: "封鎖遠端伺服器"
|
suspendRemoteInstance: "封鎖遠端伺服器"
|
||||||
unsuspendRemoteInstance: "解除封鎖遠端伺服器"
|
unsuspendRemoteInstance: "解除封鎖遠端伺服器"
|
||||||
|
markSensitiveDriveFile: "標記為敏感檔案"
|
||||||
|
unmarkSensitiveDriveFile: "撤銷標記為敏感檔案"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2023.9.0",
|
"version": "2023.9.1",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
export class MutingNotificationTypes1695605508898 {
|
||||||
|
name = 'MutingNotificationTypes1695605508898'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TYPE "public"."user_profile_mutingnotificationtypes_enum" RENAME TO "user_profile_mutingnotificationtypes_enum_old"`);
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."user_profile_mutingnotificationtypes_enum" AS ENUM('note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'achievementEarned', 'app', 'test', 'pollVote', 'groupInvited')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" DROP DEFAULT`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" TYPE "public"."user_profile_mutingnotificationtypes_enum"[] USING "mutingNotificationTypes"::"text"::"public"."user_profile_mutingnotificationtypes_enum"[]`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" SET DEFAULT '{}'`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."user_profile_mutingnotificationtypes_enum_old"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."user_profile_mutingnotificationtypes_enum_old" AS ENUM('follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'achievementEarned', 'app')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" DROP DEFAULT`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" TYPE "public"."user_profile_mutingnotificationtypes_enum_old"[] USING "mutingNotificationTypes"::"text"::"public"."user_profile_mutingnotificationtypes_enum_old"[]`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" SET DEFAULT '{}'`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."user_profile_mutingnotificationtypes_enum"`);
|
||||||
|
await queryRunner.query(`ALTER TYPE "public"."user_profile_mutingnotificationtypes_enum_old" RENAME TO "user_profile_mutingnotificationtypes_enum"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Brackets } from 'typeorm';
|
import { Brackets } from 'typeorm';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import type { AnnouncementReadsRepository, AnnouncementsRepository, MiAnnouncement, MiAnnouncementRead } from '@/models/_.js';
|
import type { AnnouncementReadsRepository, AnnouncementsRepository, MiAnnouncement, MiAnnouncementRead, UsersRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { Packed } from '@/misc/json-schema.js';
|
import { Packed } from '@/misc/json-schema.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
@ -23,6 +23,9 @@ export class AnnouncementService {
|
||||||
@Inject(DI.announcementReadsRepository)
|
@Inject(DI.announcementReadsRepository)
|
||||||
private announcementReadsRepository: AnnouncementReadsRepository,
|
private announcementReadsRepository: AnnouncementReadsRepository,
|
||||||
|
|
||||||
|
@Inject(DI.usersRepository)
|
||||||
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
private moderationLogService: ModerationLogService,
|
private moderationLogService: ModerationLogService,
|
||||||
|
@ -83,10 +86,13 @@ export class AnnouncementService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (moderator) {
|
if (moderator) {
|
||||||
|
const user = await this.usersRepository.findOneByOrFail({ id: values.userId });
|
||||||
this.moderationLogService.log(moderator, 'createUserAnnouncement', {
|
this.moderationLogService.log(moderator, 'createUserAnnouncement', {
|
||||||
announcementId: announcement.id,
|
announcementId: announcement.id,
|
||||||
announcement: announcement,
|
announcement: announcement,
|
||||||
userId: values.userId,
|
userId: values.userId,
|
||||||
|
userUsername: user.username,
|
||||||
|
userHost: user.host,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -127,10 +133,14 @@ export class AnnouncementService {
|
||||||
|
|
||||||
if (moderator) {
|
if (moderator) {
|
||||||
if (announcement.userId) {
|
if (announcement.userId) {
|
||||||
|
const user = await this.usersRepository.findOneByOrFail({ id: announcement.userId });
|
||||||
this.moderationLogService.log(moderator, 'updateUserAnnouncement', {
|
this.moderationLogService.log(moderator, 'updateUserAnnouncement', {
|
||||||
announcementId: announcement.id,
|
announcementId: announcement.id,
|
||||||
before: announcement,
|
before: announcement,
|
||||||
after: after,
|
after: after,
|
||||||
|
userId: announcement.userId,
|
||||||
|
userUsername: user.username,
|
||||||
|
userHost: user.host,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.moderationLogService.log(moderator, 'updateGlobalAnnouncement', {
|
this.moderationLogService.log(moderator, 'updateGlobalAnnouncement', {
|
||||||
|
|
|
@ -134,11 +134,11 @@ export class CustomEmojiService implements OnApplicationShutdown {
|
||||||
|
|
||||||
this.localEmojisCache.refresh();
|
this.localEmojisCache.refresh();
|
||||||
|
|
||||||
const updated = await this.emojiEntityService.packDetailed(emoji.id);
|
const packed = await this.emojiEntityService.packDetailed(emoji.id);
|
||||||
|
|
||||||
if (emoji.name === data.name) {
|
if (emoji.name === data.name) {
|
||||||
this.globalEventService.publishBroadcastStream('emojiUpdated', {
|
this.globalEventService.publishBroadcastStream('emojiUpdated', {
|
||||||
emojis: [updated],
|
emojis: [packed],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.globalEventService.publishBroadcastStream('emojiDeleted', {
|
this.globalEventService.publishBroadcastStream('emojiDeleted', {
|
||||||
|
@ -146,11 +146,12 @@ export class CustomEmojiService implements OnApplicationShutdown {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.globalEventService.publishBroadcastStream('emojiAdded', {
|
this.globalEventService.publishBroadcastStream('emojiAdded', {
|
||||||
emoji: updated,
|
emoji: packed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moderator) {
|
if (moderator) {
|
||||||
|
const updated = await this.emojisRepository.findOneByOrFail({ id: id });
|
||||||
this.moderationLogService.log(moderator, 'updateCustomEmoji', {
|
this.moderationLogService.log(moderator, 'updateCustomEmoji', {
|
||||||
emojiId: emoji.id,
|
emojiId: emoji.id,
|
||||||
before: emoji,
|
before: emoji,
|
||||||
|
|
|
@ -686,15 +686,20 @@ export class DriveService {
|
||||||
|
|
||||||
if (await this.roleService.isModerator(updater) && (file.userId !== updater.id)) {
|
if (await this.roleService.isModerator(updater) && (file.userId !== updater.id)) {
|
||||||
if (values.isSensitive !== undefined && values.isSensitive !== file.isSensitive) {
|
if (values.isSensitive !== undefined && values.isSensitive !== file.isSensitive) {
|
||||||
|
const user = file.userId ? await this.usersRepository.findOneByOrFail({ id: file.userId }) : null;
|
||||||
if (values.isSensitive) {
|
if (values.isSensitive) {
|
||||||
this.moderationLogService.log(updater, 'markSensitiveDriveFile', {
|
this.moderationLogService.log(updater, 'markSensitiveDriveFile', {
|
||||||
fileId: file.id,
|
fileId: file.id,
|
||||||
fileUserId: file.userId,
|
fileUserId: file.userId,
|
||||||
|
fileUserUsername: user?.username ?? null,
|
||||||
|
fileUserHost: user?.host ?? null,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.moderationLogService.log(updater, 'unmarkSensitiveDriveFile', {
|
this.moderationLogService.log(updater, 'unmarkSensitiveDriveFile', {
|
||||||
fileId: file.id,
|
fileId: file.id,
|
||||||
fileUserId: file.userId,
|
fileUserId: file.userId,
|
||||||
|
fileUserUsername: user?.username ?? null,
|
||||||
|
fileUserHost: user?.host ?? null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -795,9 +800,12 @@ export class DriveService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleter && await this.roleService.isModerator(deleter) && (file.userId !== deleter.id)) {
|
if (deleter && await this.roleService.isModerator(deleter) && (file.userId !== deleter.id)) {
|
||||||
|
const user = file.userId ? await this.usersRepository.findOneByOrFail({ id: file.userId }) : null;
|
||||||
this.moderationLogService.log(deleter, 'deleteDriveFile', {
|
this.moderationLogService.log(deleter, 'deleteDriveFile', {
|
||||||
fileId: file.id,
|
fileId: file.id,
|
||||||
fileUserId: file.userId,
|
fileUserId: file.userId,
|
||||||
|
fileUserUsername: user?.username ?? null,
|
||||||
|
fileUserHost: user?.host ?? null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,9 +135,12 @@ export class NoteDeleteService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (deleter && (note.userId !== deleter.id)) {
|
if (deleter && (note.userId !== deleter.id)) {
|
||||||
|
const user = await this.usersRepository.findOneByOrFail({ id: note.userId });
|
||||||
this.moderationLogService.log(deleter, 'deleteNote', {
|
this.moderationLogService.log(deleter, 'deleteNote', {
|
||||||
noteId: note.id,
|
noteId: note.id,
|
||||||
noteUserId: note.userId,
|
noteUserId: note.userId,
|
||||||
|
noteUserUsername: user.username,
|
||||||
|
noteUserHost: user.host,
|
||||||
note: note,
|
note: note,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -412,10 +412,13 @@ export class RoleService implements OnApplicationShutdown {
|
||||||
this.globalEventService.publishInternalEvent('userRoleAssigned', created);
|
this.globalEventService.publishInternalEvent('userRoleAssigned', created);
|
||||||
|
|
||||||
if (moderator) {
|
if (moderator) {
|
||||||
|
const user = await this.usersRepository.findOneByOrFail({ id: userId });
|
||||||
this.moderationLogService.log(moderator, 'assignRole', {
|
this.moderationLogService.log(moderator, 'assignRole', {
|
||||||
roleId: roleId,
|
roleId: roleId,
|
||||||
roleName: role.name,
|
roleName: role.name,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
|
userUsername: user.username,
|
||||||
|
userHost: user.host,
|
||||||
expiresAt: expiresAt ? expiresAt.toISOString() : null,
|
expiresAt: expiresAt ? expiresAt.toISOString() : null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -445,11 +448,16 @@ export class RoleService implements OnApplicationShutdown {
|
||||||
this.globalEventService.publishInternalEvent('userRoleUnassigned', existing);
|
this.globalEventService.publishInternalEvent('userRoleUnassigned', existing);
|
||||||
|
|
||||||
if (moderator) {
|
if (moderator) {
|
||||||
const role = await this.rolesRepository.findOneByOrFail({ id: roleId });
|
const [user, role] = await Promise.all([
|
||||||
|
this.usersRepository.findOneByOrFail({ id: userId }),
|
||||||
|
this.rolesRepository.findOneByOrFail({ id: roleId }),
|
||||||
|
]);
|
||||||
this.moderationLogService.log(moderator, 'unassignRole', {
|
this.moderationLogService.log(moderator, 'unassignRole', {
|
||||||
roleId: roleId,
|
roleId: roleId,
|
||||||
roleName: role.name,
|
roleName: role.name,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
|
userUsername: user.username,
|
||||||
|
userHost: user.host,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -473,6 +481,42 @@ export class RoleService implements OnApplicationShutdown {
|
||||||
redisPipeline.exec();
|
redisPipeline.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async create(values: Partial<MiRole>, moderator?: MiUser): Promise<MiRole> {
|
||||||
|
const date = new Date();
|
||||||
|
const created = await this.rolesRepository.insert({
|
||||||
|
id: this.idService.genId(),
|
||||||
|
createdAt: date,
|
||||||
|
updatedAt: date,
|
||||||
|
lastUsedAt: date,
|
||||||
|
name: values.name,
|
||||||
|
description: values.description,
|
||||||
|
color: values.color,
|
||||||
|
iconUrl: values.iconUrl,
|
||||||
|
target: values.target,
|
||||||
|
condFormula: values.condFormula,
|
||||||
|
isPublic: values.isPublic,
|
||||||
|
isAdministrator: values.isAdministrator,
|
||||||
|
isModerator: values.isModerator,
|
||||||
|
isExplorable: values.isExplorable,
|
||||||
|
asBadge: values.asBadge,
|
||||||
|
canEditMembersByModerator: values.canEditMembersByModerator,
|
||||||
|
displayOrder: values.displayOrder,
|
||||||
|
policies: values.policies,
|
||||||
|
}).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
|
this.globalEventService.publishInternalEvent('roleCreated', created);
|
||||||
|
|
||||||
|
if (moderator) {
|
||||||
|
this.moderationLogService.log(moderator, 'createRole', {
|
||||||
|
roleId: created.id,
|
||||||
|
role: created,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async update(role: MiRole, params: Partial<MiRole>, moderator?: MiUser): Promise<void> {
|
public async update(role: MiRole, params: Partial<MiRole>, moderator?: MiUser): Promise<void> {
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
|
|
|
@ -73,7 +73,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
});
|
});
|
||||||
|
|
||||||
this.moderationLogService.log(me, 'resetPassword', {
|
this.moderationLogService.log(me, 'resetPassword', {
|
||||||
targetId: user.id,
|
userId: user.id,
|
||||||
|
userUsername: user.username,
|
||||||
|
userHost: user.host,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { InstanceActorService } from '@/core/InstanceActorService.js';
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
@ -41,6 +42,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
private instanceActorService: InstanceActorService,
|
private instanceActorService: InstanceActorService,
|
||||||
private apRendererService: ApRendererService,
|
private apRendererService: ApRendererService,
|
||||||
|
private moderationLogService: ModerationLogService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const report = await this.abuseUserReportsRepository.findOneBy({ id: ps.reportId });
|
const report = await this.abuseUserReportsRepository.findOneBy({ id: ps.reportId });
|
||||||
|
@ -61,6 +63,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
assigneeId: me.id,
|
assigneeId: me.id,
|
||||||
forwarded: ps.forward && report.targetUserHost != null,
|
forwarded: ps.forward && report.targetUserHost != null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.moderationLogService.log(me, 'resolveAbuseReport', {
|
||||||
|
reportId: report.id,
|
||||||
|
report: report,
|
||||||
|
forwarded: ps.forward && report.targetUserHost != null,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,8 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import type { RolesRepository } from '@/models/_.js';
|
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
import { RoleEntityService } from '@/core/entities/RoleEntityService.js';
|
import { RoleEntityService } from '@/core/entities/RoleEntityService.js';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['admin', 'role'],
|
tags: ['admin', 'role'],
|
||||||
|
@ -58,37 +55,11 @@ export const paramDef = {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.rolesRepository)
|
|
||||||
private rolesRepository: RolesRepository,
|
|
||||||
|
|
||||||
private globalEventService: GlobalEventService,
|
|
||||||
private idService: IdService,
|
|
||||||
private roleEntityService: RoleEntityService,
|
private roleEntityService: RoleEntityService,
|
||||||
|
private roleService: RoleService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const date = new Date();
|
const created = await this.roleService.create(ps, me);
|
||||||
const created = await this.rolesRepository.insert({
|
|
||||||
id: this.idService.genId(),
|
|
||||||
createdAt: date,
|
|
||||||
updatedAt: date,
|
|
||||||
lastUsedAt: date,
|
|
||||||
name: ps.name,
|
|
||||||
description: ps.description,
|
|
||||||
color: ps.color,
|
|
||||||
iconUrl: ps.iconUrl,
|
|
||||||
target: ps.target,
|
|
||||||
condFormula: ps.condFormula,
|
|
||||||
isPublic: ps.isPublic,
|
|
||||||
isAdministrator: ps.isAdministrator,
|
|
||||||
isModerator: ps.isModerator,
|
|
||||||
isExplorable: ps.isExplorable,
|
|
||||||
asBadge: ps.asBadge,
|
|
||||||
canEditMembersByModerator: ps.canEditMembersByModerator,
|
|
||||||
displayOrder: ps.displayOrder,
|
|
||||||
policies: ps.policies,
|
|
||||||
}).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0]));
|
|
||||||
|
|
||||||
this.globalEventService.publishInternalEvent('roleCreated', created);
|
|
||||||
|
|
||||||
return await this.roleEntityService.pack(created, me);
|
return await this.roleEntityService.pack(created, me);
|
||||||
});
|
});
|
||||||
|
|
|
@ -79,9 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchRole);
|
throw new ApiError(meta.errors.noSuchRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
const date = new Date();
|
|
||||||
await this.roleService.update(role, {
|
await this.roleService.update(role, {
|
||||||
updatedAt: date,
|
|
||||||
name: ps.name,
|
name: ps.name,
|
||||||
description: ps.description,
|
description: ps.description,
|
||||||
color: ps.color,
|
color: ps.color,
|
||||||
|
|
|
@ -61,7 +61,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
});
|
});
|
||||||
|
|
||||||
this.moderationLogService.log(me, 'suspend', {
|
this.moderationLogService.log(me, 'suspend', {
|
||||||
targetId: user.id,
|
userId: user.id,
|
||||||
|
userUsername: user.username,
|
||||||
|
userHost: user.host,
|
||||||
});
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
|
@ -46,7 +46,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
});
|
});
|
||||||
|
|
||||||
this.moderationLogService.log(me, 'unsuspend', {
|
this.moderationLogService.log(me, 'unsuspend', {
|
||||||
targetId: user.id,
|
userId: user.id,
|
||||||
|
userUsername: user.username,
|
||||||
|
userHost: user.host,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.userSuspendService.doPostUnsuspend(user);
|
this.userSuspendService.doPostUnsuspend(user);
|
||||||
|
|
|
@ -51,6 +51,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
this.moderationLogService.log(me, 'updateUserNote', {
|
this.moderationLogService.log(me, 'updateUserNote', {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
|
userUsername: user.username,
|
||||||
|
userHost: user.host,
|
||||||
before: currentProfile.moderationNote,
|
before: currentProfile.moderationNote,
|
||||||
after: ps.text,
|
after: ps.text,
|
||||||
});
|
});
|
||||||
|
|
|
@ -52,7 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId)
|
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId)
|
||||||
.where('announcement.isActive = :isActive', { isActive: ps.isActive })
|
.andWhere('announcement.isActive = :isActive', { isActive: ps.isActive })
|
||||||
.andWhere(new Brackets(qb => {
|
.andWhere(new Brackets(qb => {
|
||||||
if (me) qb.orWhere('announcement.userId = :meId', { meId: me.id });
|
if (me) qb.orWhere('announcement.userId = :meId', { meId: me.id });
|
||||||
qb.orWhere('announcement.userId IS NULL');
|
qb.orWhere('announcement.userId IS NULL');
|
||||||
|
|
|
@ -37,6 +37,7 @@ export const moderationLogTypes = [
|
||||||
'deleteCustomEmoji',
|
'deleteCustomEmoji',
|
||||||
'assignRole',
|
'assignRole',
|
||||||
'unassignRole',
|
'unassignRole',
|
||||||
|
'createRole',
|
||||||
'updateRole',
|
'updateRole',
|
||||||
'deleteRole',
|
'deleteRole',
|
||||||
'clearQueue',
|
'clearQueue',
|
||||||
|
@ -54,6 +55,7 @@ export const moderationLogTypes = [
|
||||||
'unsuspendRemoteInstance',
|
'unsuspendRemoteInstance',
|
||||||
'markSensitiveDriveFile',
|
'markSensitiveDriveFile',
|
||||||
'unmarkSensitiveDriveFile',
|
'unmarkSensitiveDriveFile',
|
||||||
|
'resolveAbuseReport',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type ModerationLogPayloads = {
|
export type ModerationLogPayloads = {
|
||||||
|
@ -62,13 +64,19 @@ export type ModerationLogPayloads = {
|
||||||
after: any | null;
|
after: any | null;
|
||||||
};
|
};
|
||||||
suspend: {
|
suspend: {
|
||||||
targetId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
};
|
};
|
||||||
unsuspend: {
|
unsuspend: {
|
||||||
targetId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
};
|
};
|
||||||
updateUserNote: {
|
updateUserNote: {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
before: string | null;
|
before: string | null;
|
||||||
after: string | null;
|
after: string | null;
|
||||||
};
|
};
|
||||||
|
@ -87,15 +95,23 @@ export type ModerationLogPayloads = {
|
||||||
};
|
};
|
||||||
assignRole: {
|
assignRole: {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
roleId: string;
|
roleId: string;
|
||||||
roleName: string;
|
roleName: string;
|
||||||
expiresAt: string | null;
|
expiresAt: string | null;
|
||||||
};
|
};
|
||||||
unassignRole: {
|
unassignRole: {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
roleId: string;
|
roleId: string;
|
||||||
roleName: string;
|
roleName: string;
|
||||||
};
|
};
|
||||||
|
createRole: {
|
||||||
|
roleId: string;
|
||||||
|
role: any;
|
||||||
|
};
|
||||||
updateRole: {
|
updateRole: {
|
||||||
roleId: string;
|
roleId: string;
|
||||||
before: any;
|
before: any;
|
||||||
|
@ -110,10 +126,14 @@ export type ModerationLogPayloads = {
|
||||||
deleteDriveFile: {
|
deleteDriveFile: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileUserId: string | null;
|
fileUserId: string | null;
|
||||||
|
fileUserUsername: string | null;
|
||||||
|
fileUserHost: string | null;
|
||||||
};
|
};
|
||||||
deleteNote: {
|
deleteNote: {
|
||||||
noteId: string;
|
noteId: string;
|
||||||
noteUserId: string;
|
noteUserId: string;
|
||||||
|
noteUserUsername: string;
|
||||||
|
noteUserHost: string | null;
|
||||||
note: any;
|
note: any;
|
||||||
};
|
};
|
||||||
createGlobalAnnouncement: {
|
createGlobalAnnouncement: {
|
||||||
|
@ -124,6 +144,8 @@ export type ModerationLogPayloads = {
|
||||||
announcementId: string;
|
announcementId: string;
|
||||||
announcement: any;
|
announcement: any;
|
||||||
userId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
};
|
};
|
||||||
updateGlobalAnnouncement: {
|
updateGlobalAnnouncement: {
|
||||||
announcementId: string;
|
announcementId: string;
|
||||||
|
@ -134,6 +156,9 @@ export type ModerationLogPayloads = {
|
||||||
announcementId: string;
|
announcementId: string;
|
||||||
before: any;
|
before: any;
|
||||||
after: any;
|
after: any;
|
||||||
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
};
|
};
|
||||||
deleteGlobalAnnouncement: {
|
deleteGlobalAnnouncement: {
|
||||||
announcementId: string;
|
announcementId: string;
|
||||||
|
@ -144,7 +169,9 @@ export type ModerationLogPayloads = {
|
||||||
announcement: any;
|
announcement: any;
|
||||||
};
|
};
|
||||||
resetPassword: {
|
resetPassword: {
|
||||||
targetId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
};
|
};
|
||||||
suspendRemoteInstance: {
|
suspendRemoteInstance: {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -157,9 +184,18 @@ export type ModerationLogPayloads = {
|
||||||
markSensitiveDriveFile: {
|
markSensitiveDriveFile: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileUserId: string | null;
|
fileUserId: string | null;
|
||||||
|
fileUserUsername: string | null;
|
||||||
|
fileUserHost: string | null;
|
||||||
};
|
};
|
||||||
unmarkSensitiveDriveFile: {
|
unmarkSensitiveDriveFile: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileUserId: string | null;
|
fileUserId: string | null;
|
||||||
|
fileUserUsername: string | null;
|
||||||
|
fileUserHost: string | null;
|
||||||
|
};
|
||||||
|
resolveAbuseReport: {
|
||||||
|
reportId: string;
|
||||||
|
report: any;
|
||||||
|
forwarded: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,33 +5,61 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._moderationLogTypes[log.type] }}</template>
|
<template #label>
|
||||||
|
<b>{{ i18n.ts._moderationLogTypes[log.type] }}</b>
|
||||||
|
<span v-if="log.type === 'updateUserNote'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'suspend'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'unsuspend'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'resetPassword'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'assignRole'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'unassignRole'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'createRole'">: {{ log.info.role.name }}</span>
|
||||||
|
<span v-else-if="log.type === 'updateRole'">: {{ log.info.before.name }}</span>
|
||||||
|
<span v-else-if="log.type === 'deleteRole'">: {{ log.info.role.name }}</span>
|
||||||
|
<span v-else-if="log.type === 'updateCustomEmoji'">: {{ log.info.before.name }}</span>
|
||||||
|
<span v-else-if="log.type === 'markSensitiveDriveFile'">: @{{ log.info.fileUserUsername }}{{ log.info.fileUserHost ? '@' + log.info.fileUserHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'unmarkSensitiveDriveFile'">: @{{ log.info.fileUserUsername }}{{ log.info.fileUserHost ? '@' + log.info.fileUserHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'suspendRemoteInstance'">: {{ log.info.host }}</span>
|
||||||
|
<span v-else-if="log.type === 'unsuspendRemoteInstance'">: {{ log.info.host }}</span>
|
||||||
|
<span v-else-if="log.type === 'createUserAnnouncement'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'updateUserAnnouncement'">: @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'deleteNote'">: @{{ log.info.noteUserUsername }}{{ log.info.noteUserHost ? '@' + log.info.noteUserHost : '' }}</span>
|
||||||
|
<span v-else-if="log.type === 'deleteDriveFile'">: @{{ log.info.fileUserUsername }}{{ log.info.fileUserHost ? '@' + log.info.fileUserHost : '' }}</span>
|
||||||
|
</template>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<MkAvatar :user="log.user" :class="$style.avatar"/>
|
<MkAvatar :user="log.user" :class="$style.avatar"/>
|
||||||
</template>
|
</template>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<MkTime :time="log.createdAt" mode="detail"/>
|
<MkTime :time="log.createdAt"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<div>{{ i18n.ts.moderator }}: {{ log.userId }}</div>
|
<div style="display: flex; gap: var(--margin); flex-wrap: wrap;">
|
||||||
|
<div style="flex: 1;">{{ i18n.ts.moderator }}: <MkA :to="`/admin/user/${log.userId}`" class="_link">@{{ log.user?.username }}</MkA></div>
|
||||||
|
<div style="flex: 1;">{{ i18n.ts.dateAndTime }}: <MkTime :time="log.createdAt" mode="detail"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template v-if="log.type === 'updateServerSettings'">
|
<template v-if="log.type === 'updateServerSettings'">
|
||||||
<div :class="$style.diff">
|
<div :class="$style.diff">
|
||||||
<CodeDiff :oldString="JSON5.stringify(log.info.before, null, '\t')" :newString="JSON5.stringify(log.info.after, null, '\t')" language="javascript" maxHeight="300px"/>
|
<CodeDiff :context="5" :hideHeader="true" :oldString="JSON5.stringify(log.info.before, null, '\t')" :newString="JSON5.stringify(log.info.after, null, '\t')" language="javascript" maxHeight="300px"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="log.type === 'updateUserNote'">
|
<template v-else-if="log.type === 'updateUserNote'">
|
||||||
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
|
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
|
||||||
<div :class="$style.diff">
|
<div :class="$style.diff">
|
||||||
<CodeDiff :oldString="log.info.before ?? ''" :newString="log.info.after ?? ''" maxHeight="300px"/>
|
<CodeDiff :context="5" :hideHeader="true" :oldString="log.info.before ?? ''" :newString="log.info.after ?? ''" maxHeight="300px"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="log.type === 'suspend'">
|
<template v-else-if="log.type === 'suspend'">
|
||||||
<div>{{ i18n.ts.user }}: {{ log.info.targetId }}</div>
|
<div>{{ i18n.ts.user }}: <MkA :to="`/admin/user/${log.info.userId}`" class="_link">@{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</MkA></div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="log.type === 'unsuspend'">
|
<template v-else-if="log.type === 'unsuspend'">
|
||||||
<div>{{ i18n.ts.user }}: {{ log.info.targetId }}</div>
|
<div>{{ i18n.ts.user }}: <MkA :to="`/admin/user/${log.info.userId}`" class="_link">@{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }}</MkA></div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="log.type === 'updateRole'">
|
||||||
|
<div :class="$style.diff">
|
||||||
|
<CodeDiff :context="5" :hideHeader="true" :oldString="JSON5.stringify(log.info.before, null, '\t')" :newString="JSON5.stringify(log.info.after, null, '\t')" language="javascript" maxHeight="300px"/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="log.type === 'assignRole'">
|
<template v-else-if="log.type === 'assignRole'">
|
||||||
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
|
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
|
||||||
|
@ -41,6 +69,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
|
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
|
||||||
<div>{{ i18n.ts.role }}: {{ log.info.roleName }} [{{ log.info.roleId }}]</div>
|
<div>{{ i18n.ts.role }}: {{ log.info.roleName }} [{{ log.info.roleId }}]</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="log.type === 'updateCustomEmoji'">
|
||||||
|
<div>{{ i18n.ts.emoji }}: {{ log.info.emojiId }}</div>
|
||||||
|
<div :class="$style.diff">
|
||||||
|
<CodeDiff :context="5" :hideHeader="true" :oldString="JSON5.stringify(log.info.before, null, '\t')" :newString="JSON5.stringify(log.info.after, null, '\t')" language="javascript" maxHeight="300px"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>raw</summary>
|
||||||
|
<pre>{{ JSON5.stringify(log, null, '\t') }}</pre>
|
||||||
|
</details>
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -368,8 +368,8 @@ export function getNoteMenu(props: {
|
||||||
.filter(x => x !== undefined);
|
.filter(x => x !== undefined);
|
||||||
} else {
|
} else {
|
||||||
menu = [{
|
menu = [{
|
||||||
icon: 'ti ti-external-link',
|
icon: 'ti ti-info-circle',
|
||||||
text: i18n.ts.detailed,
|
text: i18n.ts.details,
|
||||||
action: openDetail,
|
action: openDetail,
|
||||||
}, {
|
}, {
|
||||||
icon: 'ti ti-copy',
|
icon: 'ti ti-copy',
|
||||||
|
|
|
@ -2550,6 +2550,9 @@ type ModerationLog = {
|
||||||
} | {
|
} | {
|
||||||
type: 'unassignRole';
|
type: 'unassignRole';
|
||||||
info: ModerationLogPayloads['unassignRole'];
|
info: ModerationLogPayloads['unassignRole'];
|
||||||
|
} | {
|
||||||
|
type: 'createRole';
|
||||||
|
info: ModerationLogPayloads['createRole'];
|
||||||
} | {
|
} | {
|
||||||
type: 'updateRole';
|
type: 'updateRole';
|
||||||
info: ModerationLogPayloads['updateRole'];
|
info: ModerationLogPayloads['updateRole'];
|
||||||
|
@ -2604,7 +2607,7 @@ type ModerationLog = {
|
||||||
});
|
});
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "markSensitiveDriveFile", "unmarkSensitiveDriveFile"];
|
export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"];
|
export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"];
|
||||||
|
|
|
@ -55,6 +55,7 @@ export const moderationLogTypes = [
|
||||||
'deleteCustomEmoji',
|
'deleteCustomEmoji',
|
||||||
'assignRole',
|
'assignRole',
|
||||||
'unassignRole',
|
'unassignRole',
|
||||||
|
'createRole',
|
||||||
'updateRole',
|
'updateRole',
|
||||||
'deleteRole',
|
'deleteRole',
|
||||||
'clearQueue',
|
'clearQueue',
|
||||||
|
@ -72,6 +73,7 @@ export const moderationLogTypes = [
|
||||||
'unsuspendRemoteInstance',
|
'unsuspendRemoteInstance',
|
||||||
'markSensitiveDriveFile',
|
'markSensitiveDriveFile',
|
||||||
'unmarkSensitiveDriveFile',
|
'unmarkSensitiveDriveFile',
|
||||||
|
'resolveAbuseReport',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type ModerationLogPayloads = {
|
export type ModerationLogPayloads = {
|
||||||
|
@ -80,13 +82,19 @@ export type ModerationLogPayloads = {
|
||||||
after: any | null;
|
after: any | null;
|
||||||
};
|
};
|
||||||
suspend: {
|
suspend: {
|
||||||
targetId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
};
|
};
|
||||||
unsuspend: {
|
unsuspend: {
|
||||||
targetId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
};
|
};
|
||||||
updateUserNote: {
|
updateUserNote: {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
before: string | null;
|
before: string | null;
|
||||||
after: string | null;
|
after: string | null;
|
||||||
};
|
};
|
||||||
|
@ -105,15 +113,23 @@ export type ModerationLogPayloads = {
|
||||||
};
|
};
|
||||||
assignRole: {
|
assignRole: {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
roleId: string;
|
roleId: string;
|
||||||
roleName: string;
|
roleName: string;
|
||||||
expiresAt: string | null;
|
expiresAt: string | null;
|
||||||
};
|
};
|
||||||
unassignRole: {
|
unassignRole: {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
roleId: string;
|
roleId: string;
|
||||||
roleName: string;
|
roleName: string;
|
||||||
};
|
};
|
||||||
|
createRole: {
|
||||||
|
roleId: string;
|
||||||
|
role: any;
|
||||||
|
};
|
||||||
updateRole: {
|
updateRole: {
|
||||||
roleId: string;
|
roleId: string;
|
||||||
before: any;
|
before: any;
|
||||||
|
@ -128,10 +144,14 @@ export type ModerationLogPayloads = {
|
||||||
deleteDriveFile: {
|
deleteDriveFile: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileUserId: string | null;
|
fileUserId: string | null;
|
||||||
|
fileUserUsername: string | null;
|
||||||
|
fileUserHost: string | null;
|
||||||
};
|
};
|
||||||
deleteNote: {
|
deleteNote: {
|
||||||
noteId: string;
|
noteId: string;
|
||||||
noteUserId: string;
|
noteUserId: string;
|
||||||
|
noteUserUsername: string;
|
||||||
|
noteUserHost: string | null;
|
||||||
note: any;
|
note: any;
|
||||||
};
|
};
|
||||||
createGlobalAnnouncement: {
|
createGlobalAnnouncement: {
|
||||||
|
@ -142,6 +162,8 @@ export type ModerationLogPayloads = {
|
||||||
announcementId: string;
|
announcementId: string;
|
||||||
announcement: any;
|
announcement: any;
|
||||||
userId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
};
|
};
|
||||||
updateGlobalAnnouncement: {
|
updateGlobalAnnouncement: {
|
||||||
announcementId: string;
|
announcementId: string;
|
||||||
|
@ -152,6 +174,9 @@ export type ModerationLogPayloads = {
|
||||||
announcementId: string;
|
announcementId: string;
|
||||||
before: any;
|
before: any;
|
||||||
after: any;
|
after: any;
|
||||||
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
};
|
};
|
||||||
deleteGlobalAnnouncement: {
|
deleteGlobalAnnouncement: {
|
||||||
announcementId: string;
|
announcementId: string;
|
||||||
|
@ -162,7 +187,9 @@ export type ModerationLogPayloads = {
|
||||||
announcement: any;
|
announcement: any;
|
||||||
};
|
};
|
||||||
resetPassword: {
|
resetPassword: {
|
||||||
targetId: string;
|
userId: string;
|
||||||
|
userUsername: string;
|
||||||
|
userHost: string | null;
|
||||||
};
|
};
|
||||||
suspendRemoteInstance: {
|
suspendRemoteInstance: {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -175,9 +202,18 @@ export type ModerationLogPayloads = {
|
||||||
markSensitiveDriveFile: {
|
markSensitiveDriveFile: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileUserId: string | null;
|
fileUserId: string | null;
|
||||||
|
fileUserUsername: string | null;
|
||||||
|
fileUserHost: string | null;
|
||||||
};
|
};
|
||||||
unmarkSensitiveDriveFile: {
|
unmarkSensitiveDriveFile: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileUserId: string | null;
|
fileUserId: string | null;
|
||||||
|
fileUserUsername: string | null;
|
||||||
|
fileUserHost: string | null;
|
||||||
|
};
|
||||||
|
resolveAbuseReport: {
|
||||||
|
reportId: string;
|
||||||
|
report: any;
|
||||||
|
forwarded: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -601,6 +601,9 @@ export type ModerationLog = {
|
||||||
} | {
|
} | {
|
||||||
type: 'unassignRole';
|
type: 'unassignRole';
|
||||||
info: ModerationLogPayloads['unassignRole'];
|
info: ModerationLogPayloads['unassignRole'];
|
||||||
|
} | {
|
||||||
|
type: 'createRole';
|
||||||
|
info: ModerationLogPayloads['createRole'];
|
||||||
} | {
|
} | {
|
||||||
type: 'updateRole';
|
type: 'updateRole';
|
||||||
info: ModerationLogPayloads['updateRole'];
|
info: ModerationLogPayloads['updateRole'];
|
||||||
|
|
Loading…
Reference in a new issue