統計で無視するハッシュタグを設定できるように
This commit is contained in:
		
							parent
							
								
									106d4cc0d6
								
							
						
					
					
						commit
						7343e6e2e8
					
				
					 6 changed files with 74 additions and 6 deletions
				
			
		
							
								
								
									
										41
									
								
								src/client/app/desktop/views/pages/admin/admin.hashtags.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/client/app/desktop/views/pages/admin/admin.hashtags.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					<div class="jdnqwkzlnxcfftthoybjxrebyolvoucw mk-admin-card">
 | 
				
			||||||
 | 
						<header>%i18n:@hided-tags%</header>
 | 
				
			||||||
 | 
						<textarea v-model="hidedTags"></textarea>
 | 
				
			||||||
 | 
						<button class="ui" @click="save">%i18n:@save%</button>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import Vue from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Vue.extend({
 | 
				
			||||||
 | 
						data() {
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								hidedTags: '',
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						created() {
 | 
				
			||||||
 | 
							(this as any).os.getMeta().then(meta => {
 | 
				
			||||||
 | 
								this.hidedTags = meta.hidedTags.join('\n');
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						methods: {
 | 
				
			||||||
 | 
							save() {
 | 
				
			||||||
 | 
								(this as any).api('admin/update-meta', {
 | 
				
			||||||
 | 
									hidedTags: this.hidedTags.split('\n')
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="stylus" scoped>
 | 
				
			||||||
 | 
					@import '~const.styl'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.jdnqwkzlnxcfftthoybjxrebyolvoucw
 | 
				
			||||||
 | 
						textarea
 | 
				
			||||||
 | 
							width 100%
 | 
				
			||||||
 | 
							min-height 300px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,8 @@
 | 
				
			||||||
			<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:chalkboard .fw%%i18n:@dashboard%</li>
 | 
								<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:chalkboard .fw%%i18n:@dashboard%</li>
 | 
				
			||||||
			<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
 | 
								<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
 | 
				
			||||||
			<li @click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
 | 
								<li @click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
 | 
				
			||||||
 | 
								<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</li>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:@drive%</li> -->
 | 
								<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:@drive%</li> -->
 | 
				
			||||||
			<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
 | 
								<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
 | 
				
			||||||
		</ul>
 | 
							</ul>
 | 
				
			||||||
| 
						 | 
					@ -17,6 +19,9 @@
 | 
				
			||||||
		<div v-show="page == 'announcements'">
 | 
							<div v-show="page == 'announcements'">
 | 
				
			||||||
			<x-announcements/>
 | 
								<x-announcements/>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
 | 
							<div v-show="page == 'hashtags'">
 | 
				
			||||||
 | 
								<x-hashtags/>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
		<div v-if="page == 'users'">
 | 
							<div v-if="page == 'users'">
 | 
				
			||||||
			<x-suspend-user/>
 | 
								<x-suspend-user/>
 | 
				
			||||||
			<x-unsuspend-user/>
 | 
								<x-unsuspend-user/>
 | 
				
			||||||
| 
						 | 
					@ -33,6 +38,7 @@
 | 
				
			||||||
import Vue from "vue";
 | 
					import Vue from "vue";
 | 
				
			||||||
import XDashboard from "./admin.dashboard.vue";
 | 
					import XDashboard from "./admin.dashboard.vue";
 | 
				
			||||||
import XAnnouncements from "./admin.announcements.vue";
 | 
					import XAnnouncements from "./admin.announcements.vue";
 | 
				
			||||||
 | 
					import XHashtags from "./admin.hashtags.vue";
 | 
				
			||||||
import XSuspendUser from "./admin.suspend-user.vue";
 | 
					import XSuspendUser from "./admin.suspend-user.vue";
 | 
				
			||||||
import XUnsuspendUser from "./admin.unsuspend-user.vue";
 | 
					import XUnsuspendUser from "./admin.unsuspend-user.vue";
 | 
				
			||||||
import XVerifyUser from "./admin.verify-user.vue";
 | 
					import XVerifyUser from "./admin.verify-user.vue";
 | 
				
			||||||
| 
						 | 
					@ -43,6 +49,7 @@ export default Vue.extend({
 | 
				
			||||||
	components: {
 | 
						components: {
 | 
				
			||||||
		XDashboard,
 | 
							XDashboard,
 | 
				
			||||||
		XAnnouncements,
 | 
							XAnnouncements,
 | 
				
			||||||
 | 
							XHashtags,
 | 
				
			||||||
		XSuspendUser,
 | 
							XSuspendUser,
 | 
				
			||||||
		XUnsuspendUser,
 | 
							XUnsuspendUser,
 | 
				
			||||||
		XVerifyUser,
 | 
							XVerifyUser,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,12 +4,13 @@ const Meta = db.get<IMeta>('meta');
 | 
				
			||||||
export default Meta;
 | 
					export default Meta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type IMeta = {
 | 
					export type IMeta = {
 | 
				
			||||||
	broadcasts: any[];
 | 
						broadcasts?: any[];
 | 
				
			||||||
	stats: {
 | 
						stats?: {
 | 
				
			||||||
		notesCount: number;
 | 
							notesCount: number;
 | 
				
			||||||
		originalNotesCount: number;
 | 
							originalNotesCount: number;
 | 
				
			||||||
		usersCount: number;
 | 
							usersCount: number;
 | 
				
			||||||
		originalUsersCount: number;
 | 
							originalUsersCount: number;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	disableRegistration: boolean;
 | 
						disableRegistration?: boolean;
 | 
				
			||||||
 | 
						hidedTags?: string[];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,13 @@ export const meta = {
 | 
				
			||||||
			desc: {
 | 
								desc: {
 | 
				
			||||||
				'ja-JP': '招待制か否か'
 | 
									'ja-JP': '招待制か否か'
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		})
 | 
							}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hidedTags: $.arr($.str).optional.nullable.note({
 | 
				
			||||||
 | 
								desc: {
 | 
				
			||||||
 | 
									'ja-JP': '統計などで無視するハッシュタグ'
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +45,10 @@ export default (params: any) => new Promise(async (res, rej) => {
 | 
				
			||||||
		set.disableRegistration = ps.disableRegistration;
 | 
							set.disableRegistration = ps.disableRegistration;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (Array.isArray(ps.hidedTags)) {
 | 
				
			||||||
 | 
							set.hidedTags = ps.hidedTags;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	await Meta.update({}, {
 | 
						await Meta.update({}, {
 | 
				
			||||||
		$set: set
 | 
							$set: set
 | 
				
			||||||
	}, { upsert: true });
 | 
						}, { upsert: true });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
import Note from '../../../../models/note';
 | 
					import Note from '../../../../models/note';
 | 
				
			||||||
import { erase } from '../../../../prelude/array';
 | 
					import { erase } from '../../../../prelude/array';
 | 
				
			||||||
 | 
					import Meta from '../../../../models/meta';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
トレンドに載るためには「『直近a分間のユニーク投稿数が今からa分前~今からb分前の間のユニーク投稿数のn倍以上』のハッシュタグの上位5位以内に入る」ことが必要
 | 
					トレンドに載るためには「『直近a分間のユニーク投稿数が今からa分前~今からb分前の間のユニーク投稿数のn倍以上』のハッシュタグの上位5位以内に入る」ことが必要
 | 
				
			||||||
| 
						 | 
					@ -17,6 +18,9 @@ const max = 5;
 | 
				
			||||||
 * Get trends of hashtags
 | 
					 * Get trends of hashtags
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export default () => new Promise(async (res, rej) => {
 | 
					export default () => new Promise(async (res, rej) => {
 | 
				
			||||||
 | 
						const meta = await Meta.findOne({});
 | 
				
			||||||
 | 
						const hidedTags = (meta.hidedTags || []).map(t => t.toLowerCase());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//#region 1. 直近Aの内に投稿されたハッシュタグ(とユーザーのペア)を集計
 | 
						//#region 1. 直近Aの内に投稿されたハッシュタグ(とユーザーのペア)を集計
 | 
				
			||||||
	const data = await Note.aggregate([{
 | 
						const data = await Note.aggregate([{
 | 
				
			||||||
		$match: {
 | 
							$match: {
 | 
				
			||||||
| 
						 | 
					@ -53,6 +57,9 @@ export default () => new Promise(async (res, rej) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// カウント
 | 
						// カウント
 | 
				
			||||||
	data.map(x => x._id).forEach(x => {
 | 
						data.map(x => x._id).forEach(x => {
 | 
				
			||||||
 | 
							// ブラックリストに登録されているタグなら弾く
 | 
				
			||||||
 | 
							if (hidedTags.includes(x.tag)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const i = tags.findIndex(tag => tag.name == x.tag);
 | 
							const i = tags.findIndex(tag => tag.name == x.tag);
 | 
				
			||||||
		if (i != -1) {
 | 
							if (i != -1) {
 | 
				
			||||||
			tags[i].count++;
 | 
								tags[i].count++;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
import * as os from 'os';
 | 
					import * as os from 'os';
 | 
				
			||||||
import config from '../../../config';
 | 
					import config from '../../../config';
 | 
				
			||||||
import Meta from '../../../models/meta';
 | 
					import Meta from '../../../models/meta';
 | 
				
			||||||
 | 
					import { ILocalUser } from '../../../models/user';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const pkg = require('../../../../package.json');
 | 
					const pkg = require('../../../../package.json');
 | 
				
			||||||
const client = require('../../../../built/client/meta.json');
 | 
					const client = require('../../../../built/client/meta.json');
 | 
				
			||||||
| 
						 | 
					@ -11,7 +12,7 @@ const client = require('../../../../built/client/meta.json');
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Show core info
 | 
					 * Show core info
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export default () => new Promise(async (res, rej) => {
 | 
					export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
 | 
				
			||||||
	const meta: any = (await Meta.findOne()) || {};
 | 
						const meta: any = (await Meta.findOne()) || {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res({
 | 
						res({
 | 
				
			||||||
| 
						 | 
					@ -35,6 +36,7 @@ export default () => new Promise(async (res, rej) => {
 | 
				
			||||||
		disableRegistration: meta.disableRegistration,
 | 
							disableRegistration: meta.disableRegistration,
 | 
				
			||||||
		driveCapacityPerLocalUserMb: config.localDriveCapacityMb,
 | 
							driveCapacityPerLocalUserMb: config.localDriveCapacityMb,
 | 
				
			||||||
		recaptchaSitekey: config.recaptcha ? config.recaptcha.site_key : null,
 | 
							recaptchaSitekey: config.recaptcha ? config.recaptcha.site_key : null,
 | 
				
			||||||
		swPublickey: config.sw ? config.sw.public_key : null
 | 
							swPublickey: config.sw ? config.sw.public_key : null,
 | 
				
			||||||
 | 
							hidedTags: (me && me.isAdmin) ? meta.hidedTags : undefined
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue