From 01cbe12931f8b4feea07f2b30ca30feca041c893 Mon Sep 17 00:00:00 2001 From: nenohi Date: Sat, 13 Jul 2024 01:50:57 +0900 Subject: [PATCH 01/12] =?UTF-8?q?enhance(backend):=20api/users=E3=81=AB+pv?= =?UTF-8?q?=20-pv=E3=82=92=E8=BF=BD=E5=8A=A0=20(MisskeyIO#653)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 26cdf6fc09f8b696ff31f5649f01f2e91bcccbec) --- .../src/core/chart/charts/per-user-pv.ts | 8 +++ packages/backend/src/core/chart/core.ts | 68 ++++++++++++++++--- .../backend/src/server/api/endpoints/users.ts | 34 +++++++++- packages/misskey-js/src/autogen/types.ts | 2 +- 4 files changed, 101 insertions(+), 11 deletions(-) diff --git a/packages/backend/src/core/chart/charts/per-user-pv.ts b/packages/backend/src/core/chart/charts/per-user-pv.ts index 31708fefa8..40ff9061f6 100644 --- a/packages/backend/src/core/chart/charts/per-user-pv.ts +++ b/packages/backend/src/core/chart/charts/per-user-pv.ts @@ -52,4 +52,12 @@ export default class PerUserPvChart extends Chart { // eslint-dis 'pv.visitor': 1, }, user.id); } + + @bindThis + public async getChartUsers(span: 'hour' | 'day', amount: number, cursor: Date | null, limit = 0, offset = 0): Promise<{ + userId: string; + count: number; +}[]> { + return await this.getChartPv(span, amount, cursor, limit, offset); + } } diff --git a/packages/backend/src/core/chart/core.ts b/packages/backend/src/core/chart/core.ts index af5485a46e..f0d4fb25c2 100644 --- a/packages/backend/src/core/chart/core.ts +++ b/packages/backend/src/core/chart/core.ts @@ -15,7 +15,7 @@ import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/misc import type Logger from '@/logger.js'; import { bindThis } from '@/decorators.js'; import { MiRepository, miRepository } from '@/models/_.js'; -import type { DataSource, Repository } from 'typeorm'; +import type { DataSource, ObjectLiteral, Repository } from 'typeorm'; const COLUMN_PREFIX = '___' as const; const UNIQUE_TEMP_COLUMN_PREFIX = 'unique_temp___' as const; @@ -94,6 +94,8 @@ type ToJsonSchema = { required: (keyof S)[]; }; +type MiAndOrmRepository = Repository & MiRepository; + export function getJsonSchema(schema: S): ToJsonSchema>> { const unflatten = (str: string, parent: Record) => { const keys = str.split('.'); @@ -146,11 +148,12 @@ export default abstract class Chart { group: string | null; }[] = []; // ↓にしたいけどfindOneとかで型エラーになる - //private repositoryForHour: Repository> & MiRepository>; - //private repositoryForDay: Repository> & MiRepository>; - private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }> & MiRepository<{ id: number; group?: string | null; date: number; }>; - private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }> & MiRepository<{ id: number; group?: string | null; date: number; }>; - + //private repositoryForHour: MiAndOrmRepository>; + //private repositoryForDay: MiAndOrmRepository>; + private repositoryForHour: MiAndOrmRepository<{ id: number; group?: string | null; date: number;}>; + private repositoryForDay: MiAndOrmRepository<{ id: number; group?: string | null; date: number;}>; + private repositoryUserPvForHour: MiAndOrmRepository<{ id: number; group?: string | null; date: number; ___pv_user:number; ___upv_user:number; ___pv_visitor:number; ___upv_visitor:number;}>; + private repositoryUserPvForDay: MiAndOrmRepository<{ id: number; group?: string | null; date: number; ___pv_user:number; ___upv_user:number; ___pv_visitor:number; ___upv_visitor:number;}>; /** * 1日に一回程度実行されれば良いような計算処理を入れる(主にCASCADE削除などアプリケーション側で感知できない変動によるズレの修正用) */ @@ -276,8 +279,10 @@ export default abstract class Chart { this.logger = logger; const { hour, day } = Chart.schemaToEntity(name, schema, grouped); - this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour).extend(miRepository as MiRepository<{ id: number; group?: string | null; date: number; }>); - this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day).extend(miRepository as MiRepository<{ id: number; group?: string | null; date: number; }>); + this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour).extend(miRepository); + this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day).extend(miRepository); + this.repositoryUserPvForHour = db.getRepository<{ id: number; group?: string | null; date: number; ___pv_user:number; ___upv_user:number; ___pv_visitor:number; ___upv_visitor:number;}>(hour).extend(miRepository); + this.repositoryUserPvForDay = db.getRepository<{ id: number; group?: string | null; date: number; ___pv_user:number; ___upv_user:number; ___pv_visitor:number; ___upv_visitor:number;}>(day).extend(miRepository); } @bindThis @@ -727,4 +732,51 @@ export default abstract class Chart { } return object as Unflatten>; } + + @bindThis + public async getChartPv(span: 'hour' | 'day', amount: number, cursor: Date | null, limit: number, offset: number): Promise< + { + userId: string, + count: number, + }[] + > { + const [y, m, d, h, _m, _s, _ms] = cursor ? Chart.parseDate(subtractTime(addTime(cursor, 1, span), 1)) : Chart.getCurrentDate(); + const [y2, m2, d2, h2] = cursor ? Chart.parseDate(addTime(cursor, 1, span)) : [] as never; + + const lt = dateUTC([y, m, d, h, _m, _s, _ms]); + + const gt = + span === 'day' ? subtractTime(cursor ? dateUTC([y2, m2, d2, 0]) : dateUTC([y, m, d, 0]), amount - 1, 'day') : + span === 'hour' ? subtractTime(cursor ? dateUTC([y2, m2, d2, h2]) : dateUTC([y, m, d, h]), amount - 1, 'hour') : + new Error('not happen') as never; + + const repository = + span === 'hour' ? this.repositoryUserPvForHour : + span === 'day' ? this.repositoryUserPvForDay : + new Error('not happen') as never; + + // ログ取得 + const logs = await repository.createQueryBuilder() + .where('date BETWEEN :gt AND :lt', { gt: Chart.dateToTimestamp(gt), lt: Chart.dateToTimestamp(lt) }) + .orderBy('___pv_visitor + ___upv_visitor + ___pv_user + ___upv_user', 'DESC') + .skip(offset) + .take(limit) + .getMany() as { + ___pv_visitor: number, + ___upv_visitor: number, + ___pv_user: number, + ___upv_user: number, + group: string, + }[]; + const result = [] as { + userId: string, + count: number, + }[]; + for (const row of logs) { + const userId = row.group; + const count = row.___pv_user + row.___upv_user + row.___pv_visitor + row.___upv_visitor; + result.push({ userId, count }); + } + return result; + } } diff --git a/packages/backend/src/server/api/endpoints/users.ts b/packages/backend/src/server/api/endpoints/users.ts index e845853017..a424d7a4c7 100644 --- a/packages/backend/src/server/api/endpoints/users.ts +++ b/packages/backend/src/server/api/endpoints/users.ts @@ -6,6 +6,7 @@ import { Inject, Injectable } from '@nestjs/common'; import type { UsersRepository } from '@/models/_.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; +import PerUserPvChart from '@/core/chart/charts/per-user-pv.js'; import { QueryService } from '@/core/QueryService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DI } from '@/di-symbols.js'; @@ -31,7 +32,7 @@ export const paramDef = { properties: { limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, offset: { type: 'integer', default: 0 }, - sort: { type: 'string', enum: ['+follower', '-follower', '+createdAt', '-createdAt', '+updatedAt', '-updatedAt'] }, + sort: { type: 'string', enum: ['+follower', '-follower', '+createdAt', '-createdAt', '+updatedAt', '-updatedAt', '+pv', '-pv'] }, state: { type: 'string', enum: ['all', 'alive'], default: 'all' }, origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'local' }, hostname: { @@ -49,6 +50,7 @@ export default class extends Endpoint { // eslint- constructor( @Inject(DI.usersRepository) private usersRepository: UsersRepository, + private perUserPvChart: PerUserPvChart, private userEntityService: UserEntityService, private queryService: QueryService, @@ -70,7 +72,12 @@ export default class extends Endpoint { // eslint- if (ps.hostname) { query.andWhere('user.host = :hostname', { hostname: ps.hostname.toLowerCase() }); } - + const chartUsers: { userId: string; count: number; }[] = []; + if (ps.sort?.endsWith('pv')) { + await this.perUserPvChart.getChartUsers('hour', 0, null, ps.limit, ps.offset).then(users => { + chartUsers.push(...users); + }); + } switch (ps.sort) { case '+follower': query.orderBy('user.followersCount', 'DESC'); break; case '-follower': query.orderBy('user.followersCount', 'ASC'); break; @@ -78,6 +85,16 @@ export default class extends Endpoint { // eslint- case '-createdAt': query.orderBy('user.id', 'ASC'); break; case '+updatedAt': query.andWhere('user.updatedAt IS NOT NULL').orderBy('user.updatedAt', 'DESC'); break; case '-updatedAt': query.andWhere('user.updatedAt IS NOT NULL').orderBy('user.updatedAt', 'ASC'); break; + case '+pv': + if (chartUsers.length > 0) { + query.andWhere('user.id IN (:...userIds)', { userIds: chartUsers.map(user => user.userId) }); + } + break; + case '-pv': + if (chartUsers.length > 0) { + query.andWhere('user.id IN (:...userIds)', { userIds: chartUsers.map(user => user.userId) }); + } + break; default: query.orderBy('user.id', 'ASC'); break; } @@ -88,6 +105,19 @@ export default class extends Endpoint { // eslint- query.offset(ps.offset); const users = await query.getMany(); + if (ps.sort === '+pv') { + users.sort((a, b) => { + const aPv = chartUsers.find(user => user.userId === a.id)?.count ?? 0; + const bPv = chartUsers.find(user => user.userId === b.id)?.count ?? 0; + return bPv - aPv; + }); + } else if (ps.sort === '-pv') { + users.sort((a, b) => { + const aPv = chartUsers.find(user => user.userId === a.id)?.count ?? 0; + const bPv = chartUsers.find(user => user.userId === b.id)?.count ?? 0; + return aPv - bPv; + }); + } return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' }); }); diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index ff731a2fa6..25874d63c5 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -24986,7 +24986,7 @@ export type operations = { /** @default 0 */ offset?: number; /** @enum {string} */ - sort?: '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+updatedAt' | '-updatedAt'; + sort?: '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+updatedAt' | '-updatedAt' | '+pv' | '-pv'; /** * @default all * @enum {string} From 3f79f3585fdc785901c7c39f2cd09a03372ee8b9 Mon Sep 17 00:00:00 2001 From: nenohi Date: Sat, 13 Jul 2024 20:26:52 +0900 Subject: [PATCH 02/12] =?UTF-8?q?PV=E3=82=92=E8=A6=8B=E3=81=A6=E4=BA=BA?= =?UTF-8?q?=E6=B0=97=E3=81=AE=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC=E3=82=92?= =?UTF-8?q?=E5=8F=96=E5=BE=97=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=EF=BC=88=E3=83=AD=E3=83=BC=E3=82=AB=E3=83=AB=E3=81=AE=E3=81=BF?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit a93903c602748a2851dcd8d18657653d82ee4aee) --- packages/frontend/src/pages/explore.users.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/explore.users.vue b/packages/frontend/src/pages/explore.users.vue index e9608ae94e..398cb2c3f4 100644 --- a/packages/frontend/src/pages/explore.users.vue +++ b/packages/frontend/src/pages/explore.users.vue @@ -98,7 +98,7 @@ const pinnedUsers = { endpoint: 'pinned-users', noPaging: true }; const popularUsers = { endpoint: 'users', limit: 10, noPaging: true, params: { state: 'alive', origin: 'local', - sort: '+follower', + sort: '+pv', } }; const recentlyUpdatedUsers = { endpoint: 'users', limit: 10, noPaging: true, params: { origin: 'local', From ed45a38431943765a0d0550cb94b7bd78e87e9f7 Mon Sep 17 00:00:00 2001 From: nenohi Date: Sat, 13 Jul 2024 20:30:52 +0900 Subject: [PATCH 03/12] =?UTF-8?q?=E3=81=93=E3=82=8C=E3=82=82=E5=BF=85?= =?UTF-8?q?=E8=A6=81=E3=81=8B=E3=82=82=EF=BC=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit d3cc55bb0c828ea16bff579e8a11e7136e34637e) --- packages/frontend/src/components/MkUserSetupDialog.Follow.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkUserSetupDialog.Follow.vue b/packages/frontend/src/components/MkUserSetupDialog.Follow.vue index 1524ea0ec9..3e451519ee 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Follow.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Follow.vue @@ -53,7 +53,7 @@ const popularUsers: Paging = { params: { state: 'alive', origin: 'local', - sort: '+follower', + sort: '+pv', }, }; From a0cc91adc1f9c38d2c3d5f3b1c400bce15f7bb4f Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 13 Jul 2024 22:50:46 +0900 Subject: [PATCH 04/12] Update Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5533e3b518..63455581e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### General - Feat: 通報を受けた際、または解決した際に、予め登録した宛先に通知を飛ばせるように(mail or webhook) #13705 +- Enhance: 人気ユーザーの算出基準を変更 - Fix: 配信停止したインスタンス一覧が見れなくなる問題を修正 - Fix: Dockerコンテナの立ち上げ時に`pnpm`のインストールで固まることがある問題 - Fix: デフォルトテーマに無効なテーマコードを入力するとUIが使用できなくなる問題を修正 From 285c4b5d3775b249a6a3fcf4edf55b9b4843133d Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 13 Jul 2024 22:56:51 +0900 Subject: [PATCH 05/12] update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63455581e5..50d0b5d497 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ ### General - Feat: 通報を受けた際、または解決した際に、予め登録した宛先に通知を飛ばせるように(mail or webhook) #13705 -- Enhance: 人気ユーザーの算出基準を変更 +- Enhance: 人気ユーザーの算出基準を変更できるように + (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/653 , https://github.com/MisskeyIO/misskey/pull/664) - Fix: 配信停止したインスタンス一覧が見れなくなる問題を修正 - Fix: Dockerコンテナの立ち上げ時に`pnpm`のインストールで固まることがある問題 - Fix: デフォルトテーマに無効なテーマコードを入力するとUIが使用できなくなる問題を修正 From d98df9edf13e1de0c56ee8455e69fe29a39c3237 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sun, 14 Jul 2024 00:03:24 +0900 Subject: [PATCH 06/12] =?UTF-8?q?enhance:=20=E4=BA=BA=E6=B0=97=E3=83=A6?= =?UTF-8?q?=E3=83=BC=E3=82=B6=E3=83=BC=E3=81=AE=E7=AE=97=E5=87=BA=E5=9F=BA?= =?UTF-8?q?=E6=BA=96=E3=82=92=E9=81=B8=E3=81=B9=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 12 +++++ locales/ja-JP.yml | 3 ++ .../1720879227657-preferPopularUserFactor.js | 18 +++++++ .../src/core/entities/MetaEntityService.ts | 2 + packages/backend/src/models/Meta.ts | 6 +++ .../backend/src/models/json-schema/meta.ts | 5 ++ .../src/server/api/endpoints/admin/meta.ts | 6 +++ .../server/api/endpoints/admin/update-meta.ts | 8 +++ .../frontend/src/pages/admin/settings.vue | 27 ++++++++-- packages/frontend/src/pages/explore.users.vue | 49 ++++++++++++------- packages/misskey-js/src/autogen/types.ts | 6 +++ 11 files changed, 121 insertions(+), 21 deletions(-) create mode 100644 packages/backend/migration/1720879227657-preferPopularUserFactor.js diff --git a/locales/index.d.ts b/locales/index.d.ts index 5089f7802e..c9b6c6c816 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -4984,6 +4984,18 @@ export interface Locale extends ILocale { * お問い合わせ */ "inquiry": string; + /** + * ページ閲覧数 + */ + "pageViewCount": string; + /** + * 人気のユーザーの算出基準 + */ + "preferPopularUserFactor": string; + /** + * ページ閲覧数はローカルユーザーにのみ適用されます(リモートユーザーはフォロワー数で表示されます)。「無効」に設定すると、ローカル・リモートどちらの「人気のユーザー」セクションも表示されなくなります。 + */ + "preferPopularUserFactorDescription": string; "_delivery": { /** * 配信状態 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index a03d792140..96fb3bae68 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1242,6 +1242,9 @@ keepOriginalFilenameDescription: "この設定をオフにすると、アップ noDescription: "説明文はありません" alwaysConfirmFollow: "フォローの際常に確認する" inquiry: "お問い合わせ" +pageViewCount: "ページ閲覧数" +preferPopularUserFactor: "人気のユーザーの算出基準" +preferPopularUserFactorDescription: "ページ閲覧数はローカルユーザーにのみ適用されます(リモートユーザーはフォロワー数で表示されます)。「無効」に設定すると、ローカル・リモートどちらの「人気のユーザー」セクションも表示されなくなります。" _delivery: status: "配信状態" diff --git a/packages/backend/migration/1720879227657-preferPopularUserFactor.js b/packages/backend/migration/1720879227657-preferPopularUserFactor.js new file mode 100644 index 0000000000..b70e5b5aa4 --- /dev/null +++ b/packages/backend/migration/1720879227657-preferPopularUserFactor.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class PreferPopularUserFactor1720879227657 { + name = 'PreferPopularUserFactor1720879227657' + + async up(queryRunner) { + await queryRunner.query(`CREATE TYPE "meta_preferPopularUserFactor_enum" AS ENUM('follower', 'pv', 'none')`) + await queryRunner.query(`ALTER TABLE "meta" ADD "preferPopularUserFactor" "meta_preferPopularUserFactor_enum" NOT NULL DEFAULT 'follower'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "preferPopularUserFactor"`); + await queryRunner.query(`DROP TYPE "meta_preferPopularUserFactor_enum"`); + } +} diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts index 09641ce485..b5b5ab5c03 100644 --- a/packages/backend/src/core/entities/MetaEntityService.ts +++ b/packages/backend/src/core/entities/MetaEntityService.ts @@ -128,6 +128,8 @@ export class MetaEntityService { mediaProxy: this.config.mediaProxy, enableUrlPreview: instance.urlPreviewEnabled, + + preferPopularUserFactor: instance.preferPopularUserFactor, }; return packed; diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index ad306fcad6..3ae7c0e1b4 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -620,4 +620,10 @@ export class MiMeta { nullable: true, }) public urlPreviewUserAgent: string | null; + + @Column('enum', { + enum: ['follower', 'pv', 'none'], + default: 'follower', + }) + public preferPopularUserFactor: 'follower' | 'pv' | 'none'; } diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts index e7bc6356e5..42dfc65632 100644 --- a/packages/backend/src/models/json-schema/meta.ts +++ b/packages/backend/src/models/json-schema/meta.ts @@ -211,6 +211,11 @@ export const packedMetaLiteSchema = { type: 'boolean', optional: false, nullable: false, }, + preferPopularUserFactor: { + type: 'string', + optional: false, nullable: false, + enum: ['follower', 'pv', 'none'], + }, backgroundImageUrl: { type: 'string', optional: false, nullable: true, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index eee02a7123..146ac48384 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -481,6 +481,11 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + preferPopularUserFactor: { + type: 'string', + optional: false, nullable: false, + enum: ['follower', 'pv', 'none'], + }, }, }, } as const; @@ -614,6 +619,7 @@ export default class extends Endpoint { // eslint- urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength, urlPreviewUserAgent: instance.urlPreviewUserAgent, urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl, + preferPopularUserFactor: instance.preferPopularUserFactor, }; }); } diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 4e28ee6877..13e291a046 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -160,6 +160,10 @@ export const paramDef = { urlPreviewRequireContentLength: { type: 'boolean' }, urlPreviewUserAgent: { type: 'string', nullable: true }, urlPreviewSummaryProxyUrl: { type: 'string', nullable: true }, + preferPopularUserFactor: { + type: 'string', + enum: ['follower', 'pv', 'none'], + }, }, required: [], } as const; @@ -617,6 +621,10 @@ export default class extends Endpoint { // eslint- set.urlPreviewSummaryProxyUrl = value === '' ? null : value; } + if (ps.preferPopularUserFactor !== undefined) { + set.preferPopularUserFactor = ps.preferPopularUserFactor; + } + const before = await this.metaService.fetch(true); await this.metaService.update(set); diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue index 6f45c212ec..0acc956984 100644 --- a/packages/frontend/src/pages/admin/settings.vue +++ b/packages/frontend/src/pages/admin/settings.vue @@ -50,10 +50,24 @@ SPDX-License-Identifier: AGPL-3.0-only - - - - + + + +
+ + + + + + + + + + + + +
+
@@ -222,6 +236,8 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkButton from '@/components/MkButton.vue'; import MkFolder from '@/components/MkFolder.vue'; import MkSelect from '@/components/MkSelect.vue'; +import MkRadios from '@/components/MkRadios.vue'; +import { entities as MisskeyEntities } from 'misskey-js'; const name = ref(null); const shortName = ref(null); @@ -249,6 +265,7 @@ const urlPreviewMaximumContentLength = ref(1024 * 1024 * 10); const urlPreviewRequireContentLength = ref(true); const urlPreviewUserAgent = ref(null); const urlPreviewSummaryProxyUrl = ref(null); +const preferPopularUserFactor = ref('follower'); async function init(): Promise { const meta = await misskeyApi('admin/meta'); @@ -278,6 +295,7 @@ async function init(): Promise { urlPreviewRequireContentLength.value = meta.urlPreviewRequireContentLength; urlPreviewUserAgent.value = meta.urlPreviewUserAgent; urlPreviewSummaryProxyUrl.value = meta.urlPreviewSummaryProxyUrl; + preferPopularUserFactor.value = meta.preferPopularUserFactor; } async function save() { @@ -308,6 +326,7 @@ async function save() { urlPreviewRequireContentLength: urlPreviewRequireContentLength.value, urlPreviewUserAgent: urlPreviewUserAgent.value, urlPreviewSummaryProxyUrl: urlPreviewSummaryProxyUrl.value, + preferPopularUserFactor: preferPopularUserFactor.value, }); fetchInstance(true); diff --git a/packages/frontend/src/pages/explore.users.vue b/packages/frontend/src/pages/explore.users.vue index 398cb2c3f4..6c8ecd7ff8 100644 --- a/packages/frontend/src/pages/explore.users.vue +++ b/packages/frontend/src/pages/explore.users.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only - + @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only