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