summaryrefslogtreecommitdiff
path: root/src/server/api/endpoints/notes/search.ts
blob: d3fb33c420aac079cb79a1a58f1b140eeb6b4bf6 (plain)
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
import $ from 'cafy';
import es from '../../../../db/elasticsearch';
import define from '../../define';
import { ApiError } from '../../error';
import { Notes } from '../../../../models';
import { In } from 'typeorm';
import { ID } from '../../../../misc/cafy-id';

export const meta = {
	desc: {
		'ja-JP': '投稿を検索します。',
		'en-US': 'Search notes.'
	},

	tags: ['notes'],

	requireCredential: false,

	params: {
		query: {
			validator: $.str
		},

		limit: {
			validator: $.optional.num.range(1, 100),
			default: 10
		},

		offset: {
			validator: $.optional.num.min(0),
			default: 0
		},

		host: {
			validator: $.optional.nullable.str,
			default: undefined
		},

		userId: {
			validator: $.optional.nullable.type(ID),
			default: null
		},
	},

	res: {
		type: 'array' as const,
		optional: false as const, nullable: false as const,
		items: {
			type: 'object' as const,
			optional: false as const, nullable: false as const,
			ref: 'Note',
		}
	},

	errors: {
		searchingNotAvailable: {
			message: 'Searching not available.',
			code: 'SEARCHING_NOT_AVAILABLE',
			id: '7ee9c119-16a1-479f-a6fd-6fab00ed946f'
		}
	}
};

export default define(meta, async (ps, me) => {
	if (es == null) throw new ApiError(meta.errors.searchingNotAvailable);

	const userQuery = ps.userId != null ? [{
		term: {
			userId: ps.userId
		}
	}] : [];

	const hostQuery = ps.userId == null ?
		ps.host === null ? [{
			bool: {
				must_not: {
					exists: {
						field: 'userHost'
					}
				}
			}
		}] : ps.host !== undefined ? [{
			term: {
				userHost: ps.host
			}
		}] : []
	: [];

	const result = await es.search({
		index: 'misskey_note',
		body: {
			size: ps.limit!,
			from: ps.offset,
			query: {
				bool: {
					must: [{
						simple_query_string: {
							fields: ['text'],
							query: ps.query.toLowerCase(),
							default_operator: 'and'
						},
					}, ...hostQuery, ...userQuery]
				}
			},
			sort: [{
				_doc: 'desc'
			}]
		}
	});

	const hits = result.body.hits.hits.map((hit: any) => hit._id);

	if (hits.length === 0) return [];

	// Fetch found notes
	const notes = await Notes.find({
		where: {
			id: In(hits)
		},
		order: {
			id: -1
		}
	});

	return await Notes.packMany(notes, me);
});