2016-06-19 18:02:32 +08:00
|
|
|
const Joi = require('joi');
|
2016-06-30 03:02:31 +08:00
|
|
|
const _ = require('underscore');
|
2016-06-19 18:02:32 +08:00
|
|
|
const Serialization = require('../serialization');
|
2016-06-29 06:35:35 +08:00
|
|
|
const {createSyncbackRequest} = require('../route-helpers')
|
2016-06-19 18:02:32 +08:00
|
|
|
|
|
|
|
module.exports = (server) => {
|
|
|
|
server.route({
|
|
|
|
method: 'GET',
|
|
|
|
path: '/threads',
|
|
|
|
config: {
|
|
|
|
description: 'Returns threads',
|
|
|
|
notes: 'Notes go here',
|
|
|
|
tags: ['threads'],
|
|
|
|
validate: {
|
2016-06-25 07:14:04 +08:00
|
|
|
query: {
|
2016-06-29 06:01:41 +08:00
|
|
|
'id': Joi.number().integer().min(0),
|
2016-06-30 03:02:31 +08:00
|
|
|
'view': Joi.string().valid('expanded', 'count'),
|
2016-06-29 06:01:41 +08:00
|
|
|
'subject': Joi.string(),
|
|
|
|
'unread': Joi.boolean(),
|
|
|
|
'starred': Joi.boolean(),
|
|
|
|
'startedBefore': Joi.date().timestamp(),
|
|
|
|
'startedAfter': Joi.date().timestamp(),
|
|
|
|
'lastMessageBefore': Joi.date().timestamp(),
|
|
|
|
'lastMessageAfter': Joi.date().timestamp(),
|
|
|
|
'in': Joi.string().allow(Joi.number()),
|
2016-06-30 03:02:31 +08:00
|
|
|
'limit': Joi.number().integer().min(1).max(2000).default(100),
|
|
|
|
'offset': Joi.number().integer().min(0).default(0),
|
2016-06-19 18:02:32 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
response: {
|
2016-06-30 03:02:31 +08:00
|
|
|
schema: Joi.alternatives().try([
|
|
|
|
Joi.array().items(
|
|
|
|
Serialization.jsonSchema('Thread')
|
|
|
|
),
|
|
|
|
Joi.object().keys({
|
|
|
|
count: Joi.number().integer().min(0),
|
|
|
|
}),
|
|
|
|
]),
|
2016-06-19 18:02:32 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
handler: (request, reply) => {
|
|
|
|
request.getAccountDatabase().then((db) => {
|
2016-06-30 03:02:31 +08:00
|
|
|
const {Thread, Category, Message} = db;
|
2016-06-28 03:30:28 +08:00
|
|
|
const query = request.query;
|
2016-06-28 01:15:05 +08:00
|
|
|
const where = {};
|
2016-06-29 06:01:41 +08:00
|
|
|
const include = [];
|
2016-06-28 01:15:05 +08:00
|
|
|
|
2016-06-28 03:30:28 +08:00
|
|
|
if (query.id) {
|
|
|
|
where.id = query.id;
|
2016-06-28 01:35:34 +08:00
|
|
|
}
|
2016-06-28 04:45:11 +08:00
|
|
|
if (query.subject) {
|
|
|
|
// the 'like' operator is case-insenstive in sequelite and for
|
|
|
|
// non-binary strings in mysql
|
2016-06-29 09:11:55 +08:00
|
|
|
where.subject = {like: query.subject};
|
2016-06-28 04:45:11 +08:00
|
|
|
}
|
2016-06-28 03:30:28 +08:00
|
|
|
|
|
|
|
// Boolean queries
|
|
|
|
if (query.unread) {
|
2016-06-28 01:15:05 +08:00
|
|
|
where.unreadCount = {gt: 0};
|
2016-06-28 03:30:28 +08:00
|
|
|
} else if (query.unread !== undefined) {
|
2016-06-28 01:15:05 +08:00
|
|
|
where.unreadCount = 0;
|
|
|
|
}
|
2016-06-28 03:30:28 +08:00
|
|
|
if (query.starred) {
|
2016-06-28 01:15:05 +08:00
|
|
|
where.starredCount = {gt: 0};
|
2016-06-28 03:30:28 +08:00
|
|
|
} else if (query.starred !== undefined) {
|
2016-06-28 01:15:05 +08:00
|
|
|
where.starredCount = 0;
|
2016-06-25 07:14:04 +08:00
|
|
|
}
|
2016-06-28 01:15:05 +08:00
|
|
|
|
2016-06-28 03:30:28 +08:00
|
|
|
// Timestamp queries
|
|
|
|
if (query.lastMessageBefore) {
|
2016-06-29 09:01:43 +08:00
|
|
|
where.lastMessageReceivedDate = {lt: query.lastMessageBefore};
|
2016-06-28 03:30:28 +08:00
|
|
|
}
|
|
|
|
if (query.lastMessageAfter) {
|
2016-06-29 09:01:43 +08:00
|
|
|
if (where.lastMessageReceivedDate) {
|
|
|
|
where.lastMessageReceivedDate.gt = query.lastMessageAfter;
|
2016-06-28 03:30:28 +08:00
|
|
|
} else {
|
2016-06-29 09:01:43 +08:00
|
|
|
where.lastMessageReceivedDate = {gt: query.lastMessageAfter};
|
2016-06-28 03:30:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (query.startedBefore) {
|
2016-06-29 09:01:43 +08:00
|
|
|
where.firstMessageDate = {lt: query.startedBefore};
|
2016-06-28 03:30:28 +08:00
|
|
|
}
|
|
|
|
if (query.startedAfter) {
|
2016-06-29 09:01:43 +08:00
|
|
|
if (where.firstMessageDate) {
|
|
|
|
where.firstMessageDate.gt = query.startedAfter;
|
2016-06-28 03:30:28 +08:00
|
|
|
} else {
|
2016-06-29 09:01:43 +08:00
|
|
|
where.firstMessageDate = {gt: query.startedAfter};
|
2016-06-28 03:30:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-29 06:01:41 +08:00
|
|
|
// Association queries
|
|
|
|
if (query.in) {
|
|
|
|
include.push({
|
|
|
|
model: Category,
|
|
|
|
where: { $or: [
|
|
|
|
{ id: query.in },
|
|
|
|
{ name: query.in },
|
|
|
|
{ role: query.in },
|
|
|
|
]},
|
|
|
|
});
|
2016-06-30 02:22:38 +08:00
|
|
|
} else {
|
|
|
|
include.push({model: Category})
|
2016-06-29 06:01:41 +08:00
|
|
|
}
|
|
|
|
|
2016-06-30 03:02:31 +08:00
|
|
|
if (query.view === 'expanded') {
|
|
|
|
include.push({
|
|
|
|
model: Message,
|
|
|
|
as: 'messages',
|
|
|
|
attributes: _.without(Object.keys(Message.attributes), 'body'),
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
include.push({
|
|
|
|
model: Message,
|
|
|
|
as: 'messages',
|
|
|
|
attributes: ['id'],
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query.view === 'count') {
|
|
|
|
Thread.count({
|
|
|
|
where: where,
|
|
|
|
include: include,
|
|
|
|
}).then((count) => {
|
|
|
|
reply(Serialization.jsonStringify({count: count}));
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-28 01:15:05 +08:00
|
|
|
Thread.findAll({
|
2016-06-30 03:02:31 +08:00
|
|
|
limit: request.query.limit,
|
|
|
|
offset: request.query.offset,
|
2016-06-28 01:15:05 +08:00
|
|
|
where: where,
|
2016-06-29 06:01:41 +08:00
|
|
|
include: include,
|
2016-06-28 01:15:05 +08:00
|
|
|
}).then((threads) => {
|
2016-06-30 03:02:31 +08:00
|
|
|
// if the user requested the expanded viw, fill message.category using
|
|
|
|
// thread.category, since it must be a superset.
|
|
|
|
if (query.view === 'expanded') {
|
|
|
|
for (const thread of threads) {
|
|
|
|
for (const msg of thread.messages) {
|
|
|
|
msg.category = thread.categories.find(c => c.id === msg.categoryId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-06-28 01:15:05 +08:00
|
|
|
reply(Serialization.jsonStringify(threads));
|
|
|
|
})
|
2016-06-19 18:02:32 +08:00
|
|
|
})
|
|
|
|
},
|
|
|
|
});
|
2016-06-24 06:46:52 +08:00
|
|
|
|
|
|
|
server.route({
|
|
|
|
method: 'PUT',
|
2016-06-29 09:14:39 +08:00
|
|
|
path: '/threads/{id}',
|
2016-06-24 06:46:52 +08:00
|
|
|
config: {
|
|
|
|
description: 'Update a thread',
|
|
|
|
notes: 'Can move between folders',
|
|
|
|
tags: ['threads'],
|
|
|
|
validate: {
|
|
|
|
params: {
|
2016-06-29 09:14:39 +08:00
|
|
|
id: Joi.string(),
|
2016-06-24 06:46:52 +08:00
|
|
|
payload: {
|
|
|
|
folder_id: Joi.string(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
response: {
|
2016-06-29 09:14:39 +08:00
|
|
|
schema: Serialization.jsonSchema('SyncbackRequest'),
|
2016-06-24 06:46:52 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
handler: (request, reply) => {
|
2016-06-29 06:35:35 +08:00
|
|
|
createSyncbackRequest(request, reply, {
|
|
|
|
type: "MoveToFolder",
|
|
|
|
props: {
|
2016-06-29 09:14:39 +08:00
|
|
|
folderId: request.payload.folder_id,
|
2016-06-29 08:38:47 +08:00
|
|
|
threadId: request.params.id,
|
|
|
|
},
|
2016-06-24 06:46:52 +08:00
|
|
|
})
|
|
|
|
},
|
|
|
|
});
|
2016-06-29 08:38:47 +08:00
|
|
|
|
|
|
|
server.route({
|
|
|
|
method: 'POST',
|
|
|
|
path: '/threads/{id}/markread',
|
|
|
|
config: {
|
|
|
|
description: 'Mark a thread as read.',
|
|
|
|
tags: ['threads'],
|
|
|
|
handler: (request, reply) => {
|
|
|
|
createSyncbackRequest(request, reply, {
|
|
|
|
type: "MarkThreadAsRead",
|
|
|
|
props: {
|
|
|
|
threadId: request.params.id,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
2016-06-19 18:02:32 +08:00
|
|
|
};
|