Feature / user recommendation config in admin ui (#3357)

* add config for external user recommendation into admin ui

* debug

* correct admin ui

* switch external user recommendation to admin ui config

* debug

* debug

* debug

* Revert "debug"

This reverts commit f4a0460e5bde21cd1f39a735f496a2d74233ef3f.

* explicit parseInt radix

* add Japanese message

* change default engine to https

* remove unused settings

* debug

* nullable externalUserRecommendationTimeout
This commit is contained in:
Hakaba Hitoyo 2018-11-21 23:44:59 +09:00 committed by syuilo
parent 562a5f66fc
commit ac14adfd3e
8 changed files with 94 additions and 14 deletions

View file

@ -121,9 +121,3 @@ autoAdmin: true
# Summaly proxy # Summaly proxy
#summalyProxy: "http://example.com" #summalyProxy: "http://example.com"
# User recommendation
#user_recommendation:
# external: true
# engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}
# timeout: 300000

View file

@ -1117,6 +1117,12 @@ admin/views/instance.vue:
invite: "招待" invite: "招待"
save: "保存" save: "保存"
saved: "保存しました" saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする"
external-user-recommendation-engine: "エンジン"
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
external-user-recommendation-timeout: "タイムアウト"
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
admin/views/charts.vue: admin/views/charts.vue:
title: "チャート" title: "チャート"

View file

@ -42,6 +42,12 @@
<section> <section>
<ui-switch v-model="disableLocalTimeline">{{ $t('disable-local-timeline') }}</ui-switch> <ui-switch v-model="disableLocalTimeline">{{ $t('disable-local-timeline') }}</ui-switch>
</section> </section>
<section>
<header><fa :icon="faUserPlus"/> {{ $t('user-recommendation-config') }}</header>
<ui-switch v-model="enableExternalUserRecommendation">{{ $t('enable-external-user-recommendation') }}</ui-switch>
<ui-input v-model="externalUserRecommendationEngine" :disabled="!enableExternalUserRecommendation">{{ $t('external-user-recommendation-engine') }}<span slot="desc">{{ $t('external-user-recommendation-engine-desc') }}</span></ui-input>
<ui-input v-model="externalUserRecommendationTimeout" type="number" :disabled="!enableExternalUserRecommendation">{{ $t('external-user-recommendation-timeout') }}<span slot="suffix">ms</span><span slot="desc">{{ $t('external-user-recommendation-timeout-desc') }}</span></ui-input>
</section>
<section> <section>
<ui-button @click="updateMeta">{{ $t('save') }}</ui-button> <ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
</section> </section>
@ -95,7 +101,7 @@ import Vue from 'vue';
import i18n from '../../i18n'; import i18n from '../../i18n';
import { host } from '../../config'; import { host } from '../../config';
import { toUnicode } from 'punycode'; import { toUnicode } from 'punycode';
import { faHeadset, faShieldAlt, faGhost } from '@fortawesome/free-solid-svg-icons'; import { faHeadset, faShieldAlt, faGhost, faUserPlus } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('admin/views/instance.vue'), i18n: i18n('admin/views/instance.vue'),
@ -129,7 +135,10 @@ export default Vue.extend({
discordClientSecret: null, discordClientSecret: null,
proxyAccount: null, proxyAccount: null,
inviteCode: null, inviteCode: null,
faHeadset, faShieldAlt, faGhost enableExternalUserRecommendation: false,
externalUserRecommendationEngine: null,
externalUserRecommendationTimeout: null,
faHeadset, faShieldAlt, faGhost, faUserPlus
}; };
}, },
@ -158,6 +167,9 @@ export default Vue.extend({
this.enableDiscordIntegration = meta.enableDiscordIntegration; this.enableDiscordIntegration = meta.enableDiscordIntegration;
this.discordClientId = meta.discordClientId; this.discordClientId = meta.discordClientId;
this.discordClientSecret = meta.discordClientSecret; this.discordClientSecret = meta.discordClientSecret;
this.enableExternalUserRecommendation = meta.enableExternalUserRecommendation;
this.externalUserRecommendationEngine = meta.externalUserRecommendationEngine;
this.externalUserRecommendationTimeout = meta.externalUserRecommendationTimeout;
}); });
}, },
@ -199,7 +211,10 @@ export default Vue.extend({
githubClientSecret: this.githubClientSecret, githubClientSecret: this.githubClientSecret,
enableDiscordIntegration: this.enableDiscordIntegration, enableDiscordIntegration: this.enableDiscordIntegration,
discordClientId: this.discordClientId, discordClientId: this.discordClientId,
discordClientSecret: this.discordClientSecret discordClientSecret: this.discordClientSecret,
enableExternalUserRecommendation: this.enableExternalUserRecommendation,
externalUserRecommendationEngine: this.externalUserRecommendationEngine,
externalUserRecommendationTimeout: parseInt(this.externalUserRecommendationTimeout, 10)
}).then(() => { }).then(() => {
this.$root.alert({ this.$root.alert({
type: 'success', type: 'success',

View file

@ -15,7 +15,10 @@ const defaultMeta: any = {
maxNoteTextLength: 1000, maxNoteTextLength: 1000,
enableTwitterIntegration: false, enableTwitterIntegration: false,
enableGithubIntegration: false, enableGithubIntegration: false,
enableDiscordIntegration: false enableDiscordIntegration: false,
enableExternalUserRecommendation: false,
externalUserRecommendationEngine: "https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}",
externalUserRecommendationTimeout: 300000
}; };
export default async function(): Promise<IMeta> { export default async function(): Promise<IMeta> {

View file

@ -125,6 +125,19 @@ if ((config as any).github) {
} }
}); });
} }
if ((config as any).user_recommendation) {
Meta.findOne({}).then(m => {
if (m != null && m.enableExternalUserRecommendation == null) {
Meta.update({}, {
$set: {
enableExternalUserRecommendation: true,
externalUserRecommendationEngine: (config as any).user_recommendation.engine,
externalUserRecommendationTimeout: (config as any).user_recommendation.timeout
}
});
}
});
}
export type IMeta = { export type IMeta = {
name?: string; name?: string;
@ -195,4 +208,8 @@ export type IMeta = {
enableDiscordIntegration?: boolean; enableDiscordIntegration?: boolean;
discordClientId?: string; discordClientId?: string;
discordClientSecret?: string; discordClientSecret?: string;
enableExternalUserRecommendation?: boolean;
externalUserRecommendationEngine?: string;
externalUserRecommendationTimeout?: number;
}; };

View file

@ -200,6 +200,27 @@ export const meta = {
desc: { desc: {
'ja-JP': 'DiscordアプリのClient Secret' 'ja-JP': 'DiscordアプリのClient Secret'
} }
},
enableExternalUserRecommendation: {
validator: $.bool.optional,
desc: {
'ja-JP': '外部ユーザーレコメンデーションを有効にする'
}
},
externalUserRecommendationEngine: {
validator: $.str.optional.nullable,
desc: {
'ja-JP': '外部ユーザーレコメンデーションのサードパーティエンジン'
}
},
externalUserRecommendationTimeout: {
validator: $.num.optional.nullable.min(0),
desc: {
'ja-JP': '外部ユーザーレコメンデーションのタイムアウト (ミリ秒)'
}
} }
} }
}; };
@ -315,6 +336,18 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
set.discordClientSecret = ps.discordClientSecret; set.discordClientSecret = ps.discordClientSecret;
} }
if (ps.enableExternalUserRecommendation !== undefined) {
set.enableExternalUserRecommendation = ps.enableExternalUserRecommendation;
}
if (ps.externalUserRecommendationEngine !== undefined) {
set.externalUserRecommendationEngine = ps.externalUserRecommendationEngine;
}
if (ps.externalUserRecommendationTimeout !== undefined) {
set.externalUserRecommendationTimeout = ps.externalUserRecommendationTimeout;
}
await Meta.update({}, { await Meta.update({}, {
$set: set $set: set
}, { upsert: true }); }, { upsert: true });

View file

@ -72,6 +72,10 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
enableTwitterIntegration: instance.enableTwitterIntegration, enableTwitterIntegration: instance.enableTwitterIntegration,
enableGithubIntegration: instance.enableGithubIntegration, enableGithubIntegration: instance.enableGithubIntegration,
enableDiscordIntegration: instance.enableDiscordIntegration, enableDiscordIntegration: instance.enableDiscordIntegration,
enableExternalUserRecommendation: instance.enableExternalUserRecommendation,
externalUserRecommendationEngine: instance.externalUserRecommendationEngine,
externalUserRecommendationTimeout: instance.externalUserRecommendationTimeout
}; };
if (ps.detail) { if (ps.detail) {
@ -85,7 +89,11 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
github: instance.enableGithubIntegration, github: instance.enableGithubIntegration,
discord: instance.enableDiscordIntegration, discord: instance.enableDiscordIntegration,
serviceWorker: config.sw ? true : false, serviceWorker: config.sw ? true : false,
userRecommendation: config.user_recommendation ? config.user_recommendation : {} userRecommendation: {
external: instance.enableExternalUserRecommendation,
engine: instance.externalUserRecommendationEngine,
timeout: instance.externalUserRecommendationTimeout
}
}; };
} }

View file

@ -6,6 +6,8 @@ import Mute from '../../../../models/mute';
import * as request from 'request'; import * as request from 'request';
import config from '../../../../config'; import config from '../../../../config';
import define from '../../define'; import define from '../../define';
import fetchMeta from '../../../../misc/fetch-meta';
export const meta = { export const meta = {
desc: { desc: {
@ -30,13 +32,15 @@ export const meta = {
}; };
export default define(meta, (ps, me) => new Promise(async (res, rej) => { export default define(meta, (ps, me) => new Promise(async (res, rej) => {
if (config.user_recommendation && config.user_recommendation.external) { const instance = await fetchMeta();
if (instance.enableExternalUserRecommendation) {
const userName = me.username; const userName = me.username;
const hostName = config.hostname; const hostName = config.hostname;
const limit = ps.limit; const limit = ps.limit;
const offset = ps.offset; const offset = ps.offset;
const timeout = config.user_recommendation.timeout; const timeout = instance.externalUserRecommendationTimeout;
const engine = config.user_recommendation.engine; const engine = instance.externalUserRecommendationEngine;
const url = engine const url = engine
.replace('{{host}}', hostName) .replace('{{host}}', hostName)
.replace('{{user}}', userName) .replace('{{user}}', userName)