1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
/**
* Module dependencies
*/
import $ from 'cafy';
import rap from '@prezzemolo/rap';
import Post from '../../models/post';
import Mute from '../../models/mute';
import ChannelWatching from '../../models/channel-watching';
import getFriends from '../../common/get-friends';
import { pack } from '../../models/post';
/**
* Get timeline of myself
*
* @param {any} params
* @param {any} user
* @param {any} app
* @return {Promise<any>}
*/
module.exports = async (params, user, app) => {
// Get 'limit' parameter
const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
if (limitErr) throw 'invalid limit param';
// Get 'since_id' parameter
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
if (sinceIdErr) throw 'invalid since_id param';
// Get 'until_id' parameter
const [untilId, untilIdErr] = $(params.until_id).optional.id().$;
if (untilIdErr) throw 'invalid until_id param';
// Get 'since_date' parameter
const [sinceDate, sinceDateErr] = $(params.since_date).optional.number().$;
if (sinceDateErr) throw 'invalid since_date param';
// Get 'until_date' parameter
const [untilDate, untilDateErr] = $(params.until_date).optional.number().$;
if (untilDateErr) throw 'invalid until_date param';
// Check if only one of since_id, until_id, since_date, until_date specified
if ([sinceId, untilId, sinceDate, untilDate].filter(x => x != null).length > 1) {
throw 'only one of since_id, until_id, since_date, until_date can be specified';
}
const { followingIds, watchingChannelIds, mutedUserIds } = await rap({
// ID list of the user itself and other users who the user follows
followingIds: getFriends(user._id),
// Watchしているチャンネルを取得
watchingChannelIds: ChannelWatching.find({
user_id: user._id,
// 削除されたドキュメントは除く
deleted_at: { $exists: false }
}).then(watches => watches.map(w => w.channel_id)),
// ミュートしているユーザーを取得
mutedUserIds: Mute.find({
muter_id: user._id,
// 削除されたドキュメントは除く
deleted_at: { $exists: false }
}).then(ms => ms.map(m => m.mutee_id))
});
//#region Construct query
const sort = {
_id: -1
};
const query = {
$or: [{
// フォローしている人のタイムラインへの投稿
user_id: {
$in: followingIds
},
// 「タイムラインへの」投稿に限定するためにチャンネルが指定されていないもののみに限る
$or: [{
channel_id: {
$exists: false
}
}, {
channel_id: null
}]
}, {
// Watchしているチャンネルへの投稿
channel_id: {
$in: watchingChannelIds
}
}],
// mute
user_id: {
$nin: mutedUserIds
},
'_reply.user_id': {
$nin: mutedUserIds
},
'_repost.user_id': {
$nin: mutedUserIds
},
} as any;
if (sinceId) {
sort._id = 1;
query._id = {
$gt: sinceId
};
} else if (untilId) {
query._id = {
$lt: untilId
};
} else if (sinceDate) {
sort._id = 1;
query.created_at = {
$gt: new Date(sinceDate)
};
} else if (untilDate) {
query.created_at = {
$lt: new Date(untilDate)
};
}
//#endregion
// Issue query
const timeline = await Post
.find(query, {
limit: limit,
sort: sort
});
// Serialize
return await Promise.all(timeline.map(post => pack(post, user)));
};
|