ハッシュタグタイムラインを実装

This commit is contained in:
syuilo
2018-09-17 09:00:20 +09:00
parent 433dbe179d
commit 109738ccb9
19 changed files with 555 additions and 92 deletions

View File

@ -13,12 +13,18 @@ export const meta = {
},
params: {
tag: $.str.note({
tag: $.str.optional.note({
desc: {
'ja-JP': 'タグ'
}
}),
query: $.arr($.arr($.str)).optional.note({
desc: {
'ja-JP': 'クエリ'
}
}),
includeUserIds: $.arr($.type(ID)).optional.note({
default: []
}),
@ -59,11 +65,9 @@ export const meta = {
}
}),
withFiles: $.bool.optional.nullable.note({
default: null,
withFiles: $.bool.optional.note({
desc: {
'ja-JP': 'ファイルが添付された投稿に限定するか否か'
'ja-JP': 'true にすると、ファイルが添付された投稿だけ取得します'
}
}),
@ -126,8 +130,14 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) =>
}
const q: any = {
$and: [{
$and: [ps.tag ? {
tagsLower: ps.tag.toLowerCase()
} : {
$or: ps.query.map(tags => ({
$and: tags.map(t => ({
tagsLower: t.toLowerCase()
}))
}))
}],
deletedAt: { $exists: false }
};
@ -281,25 +291,10 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) =>
const withFiles = ps.withFiles != null ? ps.withFiles : ps.media;
if (withFiles != null) {
if (withFiles) {
push({
fileIds: {
$exists: true,
$ne: null
}
});
} else {
push({
$or: [{
fileIds: {
$exists: false
}
}, {
fileIds: null
}]
});
}
if (withFiles) {
push({
fileIds: { $exists: true, $ne: [] }
});
}
if (ps.poll != null) {

View File

@ -0,0 +1,48 @@
import * as websocket from 'websocket';
import Xev from 'xev';
import { IUser } from '../../../models/user';
import Mute from '../../../models/mute';
import { pack } from '../../../models/note';
export default async function(
request: websocket.request,
connection: websocket.connection,
subscriber: Xev,
user?: IUser
) {
const mute = user ? await Mute.find({ muterId: user._id }) : null;
const mutedUserIds = mute ? mute.map(m => m.muteeId.toString()) : [];
const q: Array<string[]> = JSON.parse((request.resourceURL.query as any).q);
// Subscribe stream
subscriber.on('hashtag', async note => {
const matched = q.some(tags => tags.every(tag => note.tags.map((t: string) => t.toLowerCase()).includes(tag.toLowerCase())));
if (!matched) return;
// Renoteなら再pack
if (note.renoteId != null) {
note.renote = await pack(note.renoteId, user, {
detail: true
});
}
//#region 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (mutedUserIds.indexOf(note.userId) != -1) {
return;
}
if (note.reply != null && mutedUserIds.indexOf(note.reply.userId) != -1) {
return;
}
if (note.renote != null && mutedUserIds.indexOf(note.renote.userId) != -1) {
return;
}
//#endregion
connection.send(JSON.stringify({
type: 'note',
body: note
}));
});
}

View File

@ -14,6 +14,7 @@ import reversiGameStream from './stream/games/reversi-game';
import reversiStream from './stream/games/reversi';
import serverStatsStream from './stream/server-stats';
import notesStatsStream from './stream/notes-stats';
import hashtagStream from './stream/hashtag';
import { ParsedUrlQuery } from 'querystring';
import authenticate from './authenticate';
@ -57,6 +58,11 @@ module.exports = (server: http.Server) => {
return;
}
if (request.resourceURL.pathname === '/hashtag') {
hashtagStream(request, connection, ev, user);
return;
}
if (user == null) {
connection.send('authentication-failed');
connection.close();