diff --git a/locales/index.d.ts b/locales/index.d.ts index 694ee53a1f..86be3b356f 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -6626,6 +6626,10 @@ export interface Locale extends ILocale { * ノートのピン留めの最大数 */ "pinMax": string; + /** + * 一つのノートに対する最大リアクション数 + */ + "reactionsPerNoteLimit": string; /** * アンテナの作成可能数 */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index bb3999f0e3..df578b8f9b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1713,6 +1713,7 @@ _role: alwaysMarkNsfw: "ファイルにNSFWを常に付与" canUpdateBioMedia: "アイコンとバナーの更新を許可" pinMax: "ノートのピン留めの最大数" + reactionsPerNoteLimit: "一つのノートに対する最大リアクション数" antennaMax: "アンテナの作成可能数" wordMuteMax: "ワードミュートの最大文字数" webhookMax: "Webhookの作成可能数" diff --git a/packages/backend/migration/1721117896543-multiple-reactions.js b/packages/backend/migration/1721117896543-multiple-reactions.js new file mode 100644 index 0000000000..d71128962e --- /dev/null +++ b/packages/backend/migration/1721117896543-multiple-reactions.js @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class MultipleReactions1721117896543 { + name = 'MultipleReactions1721117896543'; + + async up(queryRunner) { + await queryRunner.query('DROP INDEX "public"."IDX_ad0c221b25672daf2df320a817"'); + await queryRunner.query('CREATE UNIQUE INDEX "IDX_a7751b74317122d11575bff31c" ON "note_reaction" ("userId", "noteId", "reaction") '); + await queryRunner.query('CREATE INDEX "IDX_ad0c221b25672daf2df320a817" ON "note_reaction" ("userId", "noteId") '); + } + + async down(queryRunner) { + await queryRunner.query('DROP INDEX "public"."IDX_ad0c221b25672daf2df320a817"'); + await queryRunner.query('DROP INDEX "public"."IDX_a7751b74317122d11575bff31c"'); + await queryRunner.query('CREATE UNIQUE INDEX "IDX_ad0c221b25672daf2df320a817" ON "note_reaction" ("userId", "noteId") '); + } +} diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 94026fd503..ffde9bf930 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -49,6 +49,7 @@ export type RolePolicies = { alwaysMarkNsfw: boolean; canUpdateBioMedia: boolean; pinLimit: number; + reactionsPerNoteLimit: number; antennaLimit: number; wordMuteLimit: number; webhookLimit: number; @@ -78,6 +79,7 @@ export const DEFAULT_POLICIES: RolePolicies = { alwaysMarkNsfw: false, canUpdateBioMedia: true, pinLimit: 5, + reactionsPerNoteLimit: 1, antennaLimit: 5, wordMuteLimit: 200, webhookLimit: 3, @@ -380,6 +382,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { alwaysMarkNsfw: calc('alwaysMarkNsfw', vs => vs.some(v => v === true)), canUpdateBioMedia: calc('canUpdateBioMedia', vs => vs.some(v => v === true)), pinLimit: calc('pinLimit', vs => Math.max(...vs)), + reactionsPerNoteLimit: calc('reactionsPerNoteLimit', vs => Math.max(...vs)), antennaLimit: calc('antennaLimit', vs => Math.max(...vs)), wordMuteLimit: calc('wordMuteLimit', vs => Math.max(...vs)), webhookLimit: calc('webhookLimit', vs => Math.max(...vs)), diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 2cd092231c..d1949d1432 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -170,10 +170,10 @@ export class NoteEntityService implements OnModuleInit { @bindThis public async populateMyReaction(note: { id: MiNote['id']; reactions: MiNote['reactions']; reactionAndUserPairCache?: MiNote['reactionAndUserPairCache']; }, meId: MiUser['id'], _hint_?: { - myReactions: Map; + myReactionsMap: Map; }) { - if (_hint_?.myReactions) { - const reaction = _hint_.myReactions.get(note.id); + if (_hint_?.myReactionsMap) { + const reaction = _hint_.myReactionsMap.get(note.id); if (reaction) { return this.reactionService.convertLegacyReaction(reaction); } else { diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts index 7366f05356..5820aa32e3 100644 --- a/packages/backend/src/models/json-schema/role.ts +++ b/packages/backend/src/models/json-schema/role.ts @@ -236,6 +236,10 @@ export const packedRolePoliciesSchema = { type: 'integer', optional: false, nullable: false, }, + reactionsPerNoteLimit: { + type: 'integer', + optional: false, nullable: false, + }, antennaLimit: { type: 'integer', optional: false, nullable: false, diff --git a/packages/frontend/src/const.ts b/packages/frontend/src/const.ts index e135bc69a0..2bb534ccf2 100644 --- a/packages/frontend/src/const.ts +++ b/packages/frontend/src/const.ts @@ -89,6 +89,7 @@ export const ROLE_POLICIES = [ 'alwaysMarkNsfw', 'canUpdateBioMedia', 'pinLimit', + 'reactionsPerNoteLimit', 'antennaLimit', 'wordMuteLimit', 'webhookLimit', diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index 3e948abdf1..c298476a64 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -417,6 +417,25 @@ SPDX-License-Identifier: AGPL-3.0-only + + + +
+ + + + + + + + +
+
+