Mailspring/packages/nylas-api/routes/threads.js

225 lines
6.4 KiB
JavaScript
Raw Normal View History

2016-06-19 18:02:32 +08:00
const Joi = require('joi');
const _ = require('underscore');
2016-06-19 18:02:32 +08:00
const Serialization = require('../serialization');
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: {
'id': Joi.number().integer().min(0),
'view': Joi.string().valid('expanded', 'count'),
'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()),
'filename': Joi.string(),
'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: {
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) => {
const {Thread, Folder, Label, Message, File} = db;
2016-06-28 03:30:28 +08:00
const query = request.query;
2016-06-28 01:15:05 +08:00
const where = {};
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
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) {
where.lastMessageReceivedDate = {lt: query.lastMessageBefore};
2016-06-28 03:30:28 +08:00
}
if (query.lastMessageAfter) {
if (where.lastMessageReceivedDate) {
where.lastMessageReceivedDate.gt = query.lastMessageAfter;
2016-06-28 03:30:28 +08:00
} else {
where.lastMessageReceivedDate = {gt: query.lastMessageAfter};
2016-06-28 03:30:28 +08:00
}
}
if (query.startedBefore) {
where.firstMessageDate = {lt: query.startedBefore};
2016-06-28 03:30:28 +08:00
}
if (query.startedAfter) {
if (where.firstMessageDate) {
where.firstMessageDate.gt = query.startedAfter;
2016-06-28 03:30:28 +08:00
} else {
where.firstMessageDate = {gt: query.startedAfter};
2016-06-28 03:30:28 +08:00
}
}
// Association queries
if (query.in) {
// BEN TODO FIX BEFORE COMMITTING
// include.push({
// model: Folder,
// where: { $or: [
// { id: query.in },
// { name: query.in },
// { role: query.in },
// ]},
// });
} else {
include.push({model: Folder})
include.push({model: Label})
}
const messagesInclude = [];
if (query.filename) {
messagesInclude.push({
model: File,
where: {filename: query.filename},
})
}
if (query.view === 'expanded') {
include.push({
model: Message,
as: 'messages',
attributes: _.without(Object.keys(Message.attributes), 'body'),
include: messagesInclude,
})
} else {
include.push({
model: Message,
as: 'messages',
attributes: ['id'],
include: messagesInclude,
})
}
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({
limit: request.query.limit,
offset: request.query.offset,
2016-06-28 01:15:05 +08:00
where: where,
include: include,
2016-06-28 01:15:05 +08:00
}).then((threads) => {
// if the user requested the expanded viw, fill message.folder using
// thread.folders, since it must be a superset.
if (query.view === 'expanded') {
for (const thread of threads) {
for (const msg of thread.messages) {
msg.folder = thread.folders.find(c => c.id === msg.folderId);
}
}
}
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',
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: {
id: Joi.string(),
2016-06-24 06:46:52 +08:00
payload: {
folder_id: Joi.string(),
},
},
},
response: {
schema: Serialization.jsonSchema('SyncbackRequest'),
2016-06-24 06:46:52 +08:00
},
},
handler: (request, reply) => {
2016-06-30 08:01:30 +08:00
const payload = request.payload
if (payload.folder_id) {
createSyncbackRequest(request, reply, {
type: "MoveToFolder",
props: {
folderId: request.payload.folder_id,
threadId: request.params.id,
},
})
}
if (payload.unread === false) {
createSyncbackRequest(request, reply, {
type: "MarkThreadAsRead",
props: {
threadId: request.params.id,
},
})
2016-06-30 08:23:18 +08:00
} else if (payload.unread === true) {
createSyncbackRequest(request, reply, {
type: "MarkThreadAsUnread",
props: {
threadId: request.params.id,
},
})
2016-06-30 08:01:30 +08:00
}
if (payload.starred === false) {
createSyncbackRequest(request, reply, {
type: "UnstarThread",
props: {
threadId: request.params.id,
},
})
} else if (payload.starred === true) {
createSyncbackRequest(request, reply, {
type: "StarThread",
props: {
threadId: request.params.id,
},
})
}
},
2016-06-30 08:01:30 +08:00
});
2016-06-19 18:02:32 +08:00
};