Exclude channel notes from featured polls (#13838)

* feat(backend): add `channelId` to `MiPoll` as a Denormalized field

* feat(backend): option to exclude polls in channels

* chore: exclude channel notes from featured polls

* docs(changelog): みつけるのアンケート欄にてチャンネルのアンケートが含まれてしまう問題を修正

* fix: missing license header
This commit is contained in:
anatawa12 2024-05-20 18:08:20 +09:00 committed by GitHub
parent 4d0db37d2e
commit f6df94070b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 44 additions and 0 deletions

View File

@ -17,6 +17,7 @@
- 「アカウントを見つけやすくする」が有効なユーザーか - 「アカウントを見つけやすくする」が有効なユーザーか
- Fix: Play作成時に設定した公開範囲が機能していない問題を修正 - Fix: Play作成時に設定した公開範囲が機能していない問題を修正
- Fix: 正規化されていない状態のhashtagが連合されてきたhtmlに含まれているとhashtagが正しくhashtagに復元されない問題を修正 - Fix: 正規化されていない状態のhashtagが連合されてきたhtmlに含まれているとhashtagが正しくhashtagに復元されない問題を修正
- Fix: みつけるのアンケート欄にてチャンネルのアンケートが含まれてしまう問題を修正
### Client ### Client
- Feat: アップロードするファイルの名前をランダム文字列にできるように - Feat: アップロードするファイルの名前をランダム文字列にできるように

View File

@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class ChannelIdDenormalizedForMiPoll1716129964060 {
name = 'ChannelIdDenormalizedForMiPoll1716129964060'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "poll" ADD "channelId" character varying(32)`);
await queryRunner.query(`COMMENT ON COLUMN "poll"."channelId" IS '[Denormalized]'`);
await queryRunner.query(`CREATE INDEX "IDX_c1240fcc9675946ea5d6c2860e" ON "poll" ("channelId") `);
await queryRunner.query(`UPDATE "poll" SET "channelId" = "note"."channelId" FROM "note" WHERE "poll"."noteId" = "note"."id"`);
}
async down(queryRunner) {
await queryRunner.query(`DROP INDEX "public"."IDX_c1240fcc9675946ea5d6c2860e"`);
await queryRunner.query(`COMMENT ON COLUMN "poll"."channelId" IS '[Denormalized]'`);
await queryRunner.query(`ALTER TABLE "poll" DROP COLUMN "channelId"`);
}
}

View File

@ -473,6 +473,7 @@ export class NoteCreateService implements OnApplicationShutdown {
noteVisibility: insert.visibility, noteVisibility: insert.visibility,
userId: user.id, userId: user.id,
userHost: user.host, userHost: user.host,
channelId: insert.channelId,
}); });
await transactionalEntityManager.insert(MiPoll, poll); await transactionalEntityManager.insert(MiPoll, poll);

View File

@ -8,6 +8,7 @@ import { noteVisibilities } from '@/types.js';
import { id } from './util/id.js'; import { id } from './util/id.js';
import { MiNote } from './Note.js'; import { MiNote } from './Note.js';
import type { MiUser } from './User.js'; import type { MiUser } from './User.js';
import type { MiChannel } from "@/models/Channel.js";
@Entity('poll') @Entity('poll')
export class MiPoll { export class MiPoll {
@ -58,6 +59,14 @@ export class MiPoll {
comment: '[Denormalized]', comment: '[Denormalized]',
}) })
public userHost: string | null; public userHost: string | null;
@Index()
@Column({
...id(),
nullable: true,
comment: '[Denormalized]',
})
public channelId: MiChannel['id'] | null;
//#endregion //#endregion
constructor(data: Partial<MiPoll>) { constructor(data: Partial<MiPoll>) {

View File

@ -32,6 +32,7 @@ export const paramDef = {
properties: { properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
offset: { type: 'integer', default: 0 }, offset: { type: 'integer', default: 0 },
excludeChannels: { type: 'boolean', default: false },
}, },
required: [], required: [],
} as const; } as const;
@ -86,6 +87,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
query.setParameters(mutingQuery.getParameters()); query.setParameters(mutingQuery.getParameters());
//#endregion //#endregion
//#region exclude channels
if (ps.excludeChannels) {
query.andWhere('poll.channelId IS NULL');
}
//#endregion
const polls = await query const polls = await query
.orderBy('poll.noteId', 'DESC') .orderBy('poll.noteId', 'DESC')
.limit(ps.limit) .limit(ps.limit)

View File

@ -29,6 +29,9 @@ const paginationForPolls = {
endpoint: 'notes/polls/recommendation' as const, endpoint: 'notes/polls/recommendation' as const,
limit: 10, limit: 10,
offsetMode: true, offsetMode: true,
params: {
excludeChannels: true,
},
}; };
const tab = ref('notes'); const tab = ref('notes');

View File

@ -21019,6 +21019,8 @@ export type operations = {
limit?: number; limit?: number;
/** @default 0 */ /** @default 0 */
offset?: number; offset?: number;
/** @default false */
excludeChannels?: boolean;
}; };
}; };
}; };