Skip to content

Commit

Permalink
enhance: 人気ユーザーの算出基準を選べるように
Browse files Browse the repository at this point in the history
  • Loading branch information
kakkokari-gtyih committed Jul 13, 2024
1 parent 285c4b5 commit d98df9e
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 21 deletions.
12 changes: 12 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4984,6 +4984,18 @@ export interface Locale extends ILocale {
* お問い合わせ
*/
"inquiry": string;
/**
* ページ閲覧数
*/
"pageViewCount": string;
/**
* 人気のユーザーの算出基準
*/
"preferPopularUserFactor": string;
/**
* ページ閲覧数はローカルユーザーにのみ適用されます(リモートユーザーはフォロワー数で表示されます)。「無効」に設定すると、ローカル・リモートどちらの「人気のユーザー」セクションも表示されなくなります。
*/
"preferPopularUserFactorDescription": string;
"_delivery": {
/**
* 配信状態
Expand Down
3 changes: 3 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,9 @@ keepOriginalFilenameDescription: "この設定をオフにすると、アップ
noDescription: "説明文はありません"
alwaysConfirmFollow: "フォローの際常に確認する"
inquiry: "お問い合わせ"
pageViewCount: "ページ閲覧数"
preferPopularUserFactor: "人気のユーザーの算出基準"
preferPopularUserFactorDescription: "ページ閲覧数はローカルユーザーにのみ適用されます(リモートユーザーはフォロワー数で表示されます)。「無効」に設定すると、ローカル・リモートどちらの「人気のユーザー」セクションも表示されなくなります。"

_delivery:
status: "配信状態"
Expand Down
Original file line number Diff line number Diff line change
@@ -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"`);
}
}
2 changes: 2 additions & 0 deletions packages/backend/src/core/entities/MetaEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ export class MetaEntityService {

mediaProxy: this.config.mediaProxy,
enableUrlPreview: instance.urlPreviewEnabled,

preferPopularUserFactor: instance.preferPopularUserFactor,
};

return packed;
Expand Down
6 changes: 6 additions & 0 deletions packages/backend/src/models/Meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}
5 changes: 5 additions & 0 deletions packages/backend/src/models/json-schema/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions packages/backend/src/server/api/endpoints/admin/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -614,6 +619,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,
urlPreviewUserAgent: instance.urlPreviewUserAgent,
urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl,
preferPopularUserFactor: instance.preferPopularUserFactor,
};
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -617,6 +621,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // 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);
Expand Down
27 changes: 23 additions & 4 deletions packages/frontend/src/pages/admin/settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,24 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #caption>{{ i18n.ts.impressumDescription }}</template>
</MkInput>

<MkTextarea v-model="pinnedUsers">
<template #label>{{ i18n.ts.pinnedUsers }}</template>
<template #caption>{{ i18n.ts.pinnedUsersDescription }}</template>
</MkTextarea>
<FormSection>
<template #label>{{ i18n.ts.explore }}</template>

<div class="_gaps_m">
<MkTextarea v-model="pinnedUsers">
<template #label>{{ i18n.ts.pinnedUsers }}</template>
<template #caption>{{ i18n.ts.pinnedUsersDescription }}</template>
</MkTextarea>

<MkRadios v-model="preferPopularUserFactor">
<template #label>{{ i18n.ts.preferPopularUserFactor }}</template>
<template #caption>{{ i18n.ts.preferPopularUserFactorDescription }}</template>
<option value="follower">{{ i18n.ts.followersCount }}</option>
<option value="pv">{{ i18n.ts.pageViewCount }}</option>
<option value="none">{{ i18n.ts.disabled }}</option>
</MkRadios>
</div>
</FormSection>

<FormSection>
<template #label>{{ i18n.ts.files }}</template>
Expand Down Expand Up @@ -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<string | null>(null);
const shortName = ref<string | null>(null);
Expand Down Expand Up @@ -249,6 +265,7 @@ const urlPreviewMaximumContentLength = ref<number>(1024 * 1024 * 10);
const urlPreviewRequireContentLength = ref<boolean>(true);
const urlPreviewUserAgent = ref<string | null>(null);
const urlPreviewSummaryProxyUrl = ref<string | null>(null);
const preferPopularUserFactor = ref<MisskeyEntities.MetaLite['preferPopularUserFactor']>('follower');

async function init(): Promise<void> {
const meta = await misskeyApi('admin/meta');
Expand Down Expand Up @@ -278,6 +295,7 @@ async function init(): Promise<void> {
urlPreviewRequireContentLength.value = meta.urlPreviewRequireContentLength;
urlPreviewUserAgent.value = meta.urlPreviewUserAgent;
urlPreviewSummaryProxyUrl.value = meta.urlPreviewSummaryProxyUrl;
preferPopularUserFactor.value = meta.preferPopularUserFactor;
}

async function save() {
Expand Down Expand Up @@ -308,6 +326,7 @@ async function save() {
urlPreviewRequireContentLength: urlPreviewRequireContentLength.value,
urlPreviewUserAgent: urlPreviewUserAgent.value,
urlPreviewSummaryProxyUrl: urlPreviewSummaryProxyUrl.value,
preferPopularUserFactor: preferPopularUserFactor.value,
});

fetchInstance(true);
Expand Down
49 changes: 32 additions & 17 deletions packages/frontend/src/pages/explore.users.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header><i class="ti ti-bookmark ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.pinnedUsers }}</template>
<MkUserList :pagination="pinnedUsers"/>
</MkFoldableSection>
<MkFoldableSection class="_margin" persistKey="explore-popular-users">
<MkFoldableSection v-if="instance.preferPopularUserFactor !== 'none'" class="_margin" persistKey="explore-popular-users">
<template #header><i class="ti ti-chart-line ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularUsers }}</template>
<MkUserList :pagination="popularUsers"/>
</MkFoldableSection>
Expand Down Expand Up @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkFoldableSection>

<template v-if="tag == null">
<MkFoldableSection class="_margin">
<MkFoldableSection v-if="instance.preferPopularUserFactor !== 'none'" class="_margin">
<template #header><i class="ti ti-chart-line ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularUsers }}</template>
<MkUserList :pagination="popularUsersF"/>
</MkFoldableSection>
Expand All @@ -69,7 +69,9 @@ import MkUserList from '@/components/MkUserList.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkTab from '@/components/MkTab.vue';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { instance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import type { Paging } from '@/components/MkPagination.vue';

const props = defineProps<{
tag?: string;
Expand All @@ -94,34 +96,47 @@ const tagUsers = computed(() => ({
},
}));

const pinnedUsers = { endpoint: 'pinned-users', noPaging: true };
const popularUsers = { endpoint: 'users', limit: 10, noPaging: true, params: {
function createUserQueryPaging(params: Misskey.Endpoints['users']['req']): Paging {
return {
endpoint: 'users',
limit: 10,
noPaging: true,
params,
};
}

const pinnedUsers = {
endpoint: 'pinned-users',
noPaging: true,
limit: 10,
} satisfies Paging;
const popularUsers = createUserQueryPaging({
state: 'alive',
origin: 'local',
sort: '+pv',
} };
const recentlyUpdatedUsers = { endpoint: 'users', limit: 10, noPaging: true, params: {
sort: instance.preferPopularUserFactor === 'pv' ? '+pv' : '+follower',
});
const recentlyUpdatedUsers = createUserQueryPaging({
origin: 'local',
sort: '+updatedAt',
} };
const recentlyRegisteredUsers = { endpoint: 'users', limit: 10, noPaging: true, params: {
});
const recentlyRegisteredUsers = createUserQueryPaging({
origin: 'local',
state: 'alive',
sort: '+createdAt',
} };
const popularUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: {
});
const popularUsersF = createUserQueryPaging({
state: 'alive',
origin: 'remote',
sort: '+follower',
} };
const recentlyUpdatedUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: {
sort: '+follower', // リモートのpvは信用ならない
});
const recentlyUpdatedUsersF = createUserQueryPaging({
origin: 'combined',
sort: '+updatedAt',
} };
const recentlyRegisteredUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: {
});
const recentlyRegisteredUsersF = createUserQueryPaging({
origin: 'combined',
sort: '+createdAt',
} };
});

misskeyApi('hashtags/list', {
sort: '+attachedLocalUsers',
Expand Down
6 changes: 6 additions & 0 deletions packages/misskey-js/src/autogen/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4929,6 +4929,8 @@ export type components = {
translatorAvailable: boolean;
mediaProxy: string;
enableUrlPreview: boolean;
/** @enum {string} */
preferPopularUserFactor: 'follower' | 'pv' | 'none';
backgroundImageUrl: string | null;
impressumUrl: string | null;
logoImageUrl: string | null;
Expand Down Expand Up @@ -5124,6 +5126,8 @@ export type operations = {
urlPreviewRequireContentLength: boolean;
urlPreviewUserAgent: string | null;
urlPreviewSummaryProxyUrl: string | null;
/** @enum {string} */
preferPopularUserFactor: 'follower' | 'pv' | 'none';
};
};
};
Expand Down Expand Up @@ -9367,6 +9371,8 @@ export type operations = {
urlPreviewRequireContentLength?: boolean;
urlPreviewUserAgent?: string | null;
urlPreviewSummaryProxyUrl?: string | null;
/** @enum {string} */
preferPopularUserFactor?: 'follower' | 'pv' | 'none';
};
};
};
Expand Down

0 comments on commit d98df9e

Please sign in to comment.