Merge pull request #2828 from hakaba-hitoyo/feature/external-user-recommendation
External user recommendation
This commit is contained in:
		
						commit
						1329721440
					
				
					 5 changed files with 81 additions and 38 deletions
				
			
		| 
						 | 
				
			
			@ -159,3 +159,10 @@ drive:
 | 
			
		|||
 | 
			
		||||
# Summaly proxy
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,6 @@
 | 
			
		|||
				<router-link class="name" :to="user | userPage" v-user-preview="user.id">{{ user | userName }}</router-link>
 | 
			
		||||
				<p class="username">@{{ user | acct }}</p>
 | 
			
		||||
			</div>
 | 
			
		||||
			<mk-follow-button :user="user"/>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@empty%</p>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,6 @@
 | 
			
		|||
						<router-link class="name" :to="_user | userPage" v-user-preview="_user.id">{{ _user | userName }}</router-link>
 | 
			
		||||
						<p class="username">@{{ _user | acct }}</p>
 | 
			
		||||
					</div>
 | 
			
		||||
					<mk-follow-button :user="_user"/>
 | 
			
		||||
				</div>
 | 
			
		||||
			</template>
 | 
			
		||||
			<p class="empty" v-else>%i18n:@no-one%</p>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,6 +96,12 @@ export type Source = {
 | 
			
		|||
	google_maps_api_key: string;
 | 
			
		||||
 | 
			
		||||
	clusterLimit?: number;
 | 
			
		||||
 | 
			
		||||
	user_recommendation: {
 | 
			
		||||
		external: boolean;
 | 
			
		||||
		engine: string;
 | 
			
		||||
		timeout: number;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,8 @@ import $ from 'cafy';
 | 
			
		|||
import User, { pack, ILocalUser } from '../../../../models/user';
 | 
			
		||||
import { getFriendIds } from '../../common/get-friends';
 | 
			
		||||
import Mute from '../../../../models/mute';
 | 
			
		||||
import * as request from 'request'
 | 
			
		||||
import config from '../../../../config'
 | 
			
		||||
 | 
			
		||||
export const meta = {
 | 
			
		||||
	desc: {
 | 
			
		||||
| 
						 | 
				
			
			@ -15,44 +17,74 @@ export const meta = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
 | 
			
		||||
	// Get 'limit' parameter
 | 
			
		||||
	const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit);
 | 
			
		||||
	if (limitErr) return rej('invalid limit param');
 | 
			
		||||
 | 
			
		||||
	// Get 'offset' parameter
 | 
			
		||||
	const [offset = 0, offsetErr] = $.num.optional.min(0).get(params.offset);
 | 
			
		||||
	if (offsetErr) return rej('invalid offset param');
 | 
			
		||||
 | 
			
		||||
	// ID list of the user itself and other users who the user follows
 | 
			
		||||
	const followingIds = await getFriendIds(me._id);
 | 
			
		||||
 | 
			
		||||
	// ミュートしているユーザーを取得
 | 
			
		||||
	const mutedUserIds = (await Mute.find({
 | 
			
		||||
		muterId: me._id
 | 
			
		||||
	})).map(m => m.muteeId);
 | 
			
		||||
 | 
			
		||||
	const users = await User
 | 
			
		||||
		.find({
 | 
			
		||||
			_id: {
 | 
			
		||||
				$nin: followingIds.concat(mutedUserIds)
 | 
			
		||||
	if (config.user_recommendation && config.user_recommendation.external) {
 | 
			
		||||
		const userName = me.username
 | 
			
		||||
		const hostName = config.hostname
 | 
			
		||||
		const limit = params.limit
 | 
			
		||||
		const offset = params.offset
 | 
			
		||||
		const timeout = config.user_recommendation.timeout
 | 
			
		||||
		const engine = config.user_recommendation.engine
 | 
			
		||||
		const url = engine
 | 
			
		||||
			.replace('{{host}}', hostName)
 | 
			
		||||
			.replace('{{user}}', userName)
 | 
			
		||||
			.replace('{{limit}}', limit)
 | 
			
		||||
			.replace('{{offset}}', offset)
 | 
			
		||||
		request(
 | 
			
		||||
			{
 | 
			
		||||
				url: url,
 | 
			
		||||
				timeout: timeout,
 | 
			
		||||
				json: true,
 | 
			
		||||
				followRedirect: true,
 | 
			
		||||
				followAllRedirects: true
 | 
			
		||||
			},
 | 
			
		||||
			isLocked: false,
 | 
			
		||||
			$or: [{
 | 
			
		||||
				lastUsedAt: {
 | 
			
		||||
					$gte: new Date(Date.now() - ms('7days'))
 | 
			
		||||
			(error: any, response: any, body: any) => {
 | 
			
		||||
				if (!error && response.statusCode == 200) {
 | 
			
		||||
					res(body)
 | 
			
		||||
				} else {
 | 
			
		||||
					res([])
 | 
			
		||||
				}
 | 
			
		||||
			}, {
 | 
			
		||||
				host: null
 | 
			
		||||
			}]
 | 
			
		||||
		}, {
 | 
			
		||||
			limit: limit,
 | 
			
		||||
			skip: offset,
 | 
			
		||||
			sort: {
 | 
			
		||||
				followersCount: -1
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
		)
 | 
			
		||||
	} else {
 | 
			
		||||
		// Get 'limit' parameter
 | 
			
		||||
		const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit);
 | 
			
		||||
		if (limitErr) return rej('invalid limit param');
 | 
			
		||||
 | 
			
		||||
	// Serialize
 | 
			
		||||
	res(await Promise.all(users.map(async user =>
 | 
			
		||||
		await pack(user, me, { detail: true }))));
 | 
			
		||||
		// Get 'offset' parameter
 | 
			
		||||
		const [offset = 0, offsetErr] = $.num.optional.min(0).get(params.offset);
 | 
			
		||||
		if (offsetErr) return rej('invalid offset param');
 | 
			
		||||
 | 
			
		||||
		// ID list of the user itself and other users who the user follows
 | 
			
		||||
		const followingIds = await getFriendIds(me._id);
 | 
			
		||||
 | 
			
		||||
		// ミュートしているユーザーを取得
 | 
			
		||||
		const mutedUserIds = (await Mute.find({
 | 
			
		||||
			muterId: me._id
 | 
			
		||||
		})).map(m => m.muteeId);
 | 
			
		||||
 | 
			
		||||
		const users = await User
 | 
			
		||||
			.find({
 | 
			
		||||
				_id: {
 | 
			
		||||
					$nin: followingIds.concat(mutedUserIds)
 | 
			
		||||
				},
 | 
			
		||||
				isLocked: false,
 | 
			
		||||
				$or: [{
 | 
			
		||||
					lastUsedAt: {
 | 
			
		||||
						$gte: new Date(Date.now() - ms('7days'))
 | 
			
		||||
					}
 | 
			
		||||
				}, {
 | 
			
		||||
					host: null
 | 
			
		||||
				}]
 | 
			
		||||
			}, {
 | 
			
		||||
				limit: limit,
 | 
			
		||||
				skip: offset,
 | 
			
		||||
				sort: {
 | 
			
		||||
					followersCount: -1
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
		// Serialize
 | 
			
		||||
		res(await Promise.all(users.map(async user =>
 | 
			
		||||
			await pack(user, me, { detail: true }))));
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue