mirror of
https://github.com/nodemailer/wildduck.git
synced 2024-12-26 01:40:48 +08:00
Allow including specific header fields in message listing
This commit is contained in:
parent
6e0e882ee0
commit
39560ae9dc
2 changed files with 124 additions and 38 deletions
|
@ -1711,6 +1711,12 @@ paths:
|
|||
description: Ordering of the records by insert date
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
- name: includeHeaders
|
||||
in: query
|
||||
description: 'Comma separated list of header keys to include in the response'
|
||||
schema:
|
||||
type: string
|
||||
example: 'List-ID, MIME-version'
|
||||
- name: next
|
||||
in: query
|
||||
description: 'Cursor value for next page, retrieved from nextCursor response value'
|
||||
|
@ -2037,6 +2043,12 @@ paths:
|
|||
description: Ordering of the records by insert date. If no order is supplied, results are sorted by heir mongoDB ObjectId.
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
- name: includeHeaders
|
||||
in: query
|
||||
description: 'Comma separated list of header keys to include in the response'
|
||||
schema:
|
||||
type: string
|
||||
example: 'List-ID, MIME-version'
|
||||
- name: page
|
||||
in: query
|
||||
description: 'Current page number. Informational only, page numbers start from 1'
|
||||
|
@ -6918,6 +6930,9 @@ components:
|
|||
metaData:
|
||||
type: object
|
||||
description: Custom metadata value. Included if metaData query argument was true
|
||||
headers:
|
||||
type: object
|
||||
description: Header object keys requested with the includeHeaders argument
|
||||
GetFilesResult:
|
||||
required:
|
||||
- id
|
||||
|
|
|
@ -387,6 +387,8 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
let sortAscending = result.value.order === 'asc';
|
||||
let filterUnseen = result.value.unseen;
|
||||
|
||||
let includeHeaders = result.value.includeHeaders ? result.value.includeHeaders.split(',') : false;
|
||||
|
||||
let mailboxData;
|
||||
try {
|
||||
mailboxData = await db.database.collection('mailboxes').findOne(
|
||||
|
@ -443,13 +445,6 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
hdate: true,
|
||||
idate: true,
|
||||
subject: true,
|
||||
'mimeTree.parsedHeader.from': true,
|
||||
'mimeTree.parsedHeader.sender': true,
|
||||
'mimeTree.parsedHeader.to': true,
|
||||
'mimeTree.parsedHeader.cc': true,
|
||||
'mimeTree.parsedHeader.bcc': true,
|
||||
'mimeTree.parsedHeader.content-type': true,
|
||||
'mimeTree.parsedHeader.references': true,
|
||||
ha: true,
|
||||
size: true,
|
||||
intro: true,
|
||||
|
@ -466,6 +461,24 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
sortAscending
|
||||
};
|
||||
|
||||
if (includeHeaders) {
|
||||
// get all headers
|
||||
opts.fields.projection['mimeTree.parsedHeader'] = true;
|
||||
} else {
|
||||
// get only required headers
|
||||
for (let requiredHeader of [
|
||||
'mimeTree.parsedHeader.from',
|
||||
'mimeTree.parsedHeader.sender',
|
||||
'mimeTree.parsedHeader.to',
|
||||
'mimeTree.parsedHeader.cc',
|
||||
'mimeTree.parsedHeader.bcc',
|
||||
'mimeTree.parsedHeader.content-type',
|
||||
'mimeTree.parsedHeader.references'
|
||||
]) {
|
||||
opts.fields.projection[requiredHeader] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pageNext) {
|
||||
opts.next = pageNext;
|
||||
} else if ((!page || page > 1) && pagePrevious) {
|
||||
|
@ -500,7 +513,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
previousCursor: listing.hasPrevious ? listing.previous : false,
|
||||
nextCursor: listing.hasNext ? listing.next : false,
|
||||
specialUse: mailboxData.specialUse,
|
||||
results: (listing.results || []).map(formatMessageListing)
|
||||
results: (listing.results || []).map(entry => formatMessageListing(entry, includeHeaders))
|
||||
};
|
||||
|
||||
return res.json(response);
|
||||
|
@ -532,6 +545,12 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
attachments: booleanSchema,
|
||||
flagged: booleanSchema,
|
||||
unseen: booleanSchema,
|
||||
includeHeaders: Joi.string()
|
||||
.max(1024)
|
||||
.trim()
|
||||
.empty('')
|
||||
.example('List-ID, MIME-Version')
|
||||
.description('Comma separated list of header keys to include in the response'),
|
||||
searchable: booleanSchema,
|
||||
sess: sessSchema,
|
||||
ip: sessIPSchema
|
||||
|
@ -546,6 +565,12 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
threadCounters: booleanSchema.default(false),
|
||||
limit: Joi.number().default(20).min(1).max(250),
|
||||
order: Joi.any().empty('').allow('asc', 'desc').optional(),
|
||||
includeHeaders: Joi.string()
|
||||
.max(1024)
|
||||
.trim()
|
||||
.empty('')
|
||||
.example('List-ID, MIME-Version')
|
||||
.description('Comma separated list of header keys to include in the response'),
|
||||
next: nextPageCursorSchema,
|
||||
previous: previousPageCursorSchema,
|
||||
page: pageNrSchema
|
||||
|
@ -581,6 +606,8 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
let pagePrevious = result.value.previous;
|
||||
let order = result.value.order;
|
||||
|
||||
let includeHeaders = result.value.includeHeaders ? result.value.includeHeaders.split(',') : false;
|
||||
|
||||
let filter;
|
||||
let query;
|
||||
|
||||
|
@ -588,29 +615,24 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
let hasESFeatureFlag = await db.redis.sismember(`feature:indexing`, user.toString());
|
||||
if (hasESFeatureFlag) {
|
||||
// search from ElasticSearch
|
||||
/*
|
||||
// TODO: paging and cursors for ElasticSearch results
|
||||
|
||||
let searchQuery = await getElasticSearchQuery(db, user, result.value.q);
|
||||
|
||||
const esclient = getClient();
|
||||
console.log(
|
||||
util.inspect(
|
||||
{
|
||||
index: config.elasticsearch.index,
|
||||
body: { query: searchQuery, sort: { uid: 'desc' } }
|
||||
},
|
||||
false,
|
||||
22,
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
let searchResult = await esclient.search({
|
||||
const searchOpts = {
|
||||
index: config.elasticsearch.index,
|
||||
body: { query: searchQuery, sort: { uid: 'desc' } }
|
||||
});
|
||||
};
|
||||
|
||||
let searchResult = await esclient.search(searchOpts);
|
||||
const searchHits = searchResult && searchResult.body && searchResult.body.hits;
|
||||
|
||||
console.log('ES RESULTS');
|
||||
console.log(util.inspect(searchResult, false, 22, true));
|
||||
*/
|
||||
}
|
||||
|
||||
filter = await getMongoDBQuery(db, user, result.value.q);
|
||||
|
@ -640,13 +662,6 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
hdate: true,
|
||||
idate: true,
|
||||
subject: true,
|
||||
'mimeTree.parsedHeader.from': true,
|
||||
'mimeTree.parsedHeader.sender': true,
|
||||
'mimeTree.parsedHeader.to': true,
|
||||
'mimeTree.parsedHeader.cc': true,
|
||||
'mimeTree.parsedHeader.bcc': true,
|
||||
'mimeTree.parsedHeader.content-type': true,
|
||||
'mimeTree.parsedHeader.references': true,
|
||||
ha: true,
|
||||
intro: true,
|
||||
size: true,
|
||||
|
@ -663,6 +678,24 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
sortAscending: order === 'asc' ? true : undefined
|
||||
};
|
||||
|
||||
if (includeHeaders) {
|
||||
// get all headers
|
||||
opts.fields.projection['mimeTree.parsedHeader'] = true;
|
||||
} else {
|
||||
// get only required headers
|
||||
for (let requiredHeader of [
|
||||
'mimeTree.parsedHeader.from',
|
||||
'mimeTree.parsedHeader.sender',
|
||||
'mimeTree.parsedHeader.to',
|
||||
'mimeTree.parsedHeader.cc',
|
||||
'mimeTree.parsedHeader.bcc',
|
||||
'mimeTree.parsedHeader.content-type',
|
||||
'mimeTree.parsedHeader.references'
|
||||
]) {
|
||||
opts.fields.projection[requiredHeader] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pageNext) {
|
||||
opts.next = pageNext;
|
||||
} else if ((!page || page > 1) && pagePrevious) {
|
||||
|
@ -697,7 +730,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
page,
|
||||
previousCursor: listing.hasPrevious ? listing.previous : false,
|
||||
nextCursor: listing.hasNext ? listing.next : false,
|
||||
results: (listing.results || []).map(formatMessageListing)
|
||||
results: (listing.results || []).map(entry => formatMessageListing(entry, includeHeaders))
|
||||
};
|
||||
|
||||
return res.json(response);
|
||||
|
@ -2499,6 +2532,12 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
next: nextPageCursorSchema,
|
||||
previous: previousPageCursorSchema,
|
||||
order: Joi.any().empty('').allow('asc', 'desc').default('desc'),
|
||||
includeHeaders: Joi.string()
|
||||
.max(1024)
|
||||
.trim()
|
||||
.empty('')
|
||||
.example('List-ID, MIME-Version')
|
||||
.description('Comma separated list of header keys to include in the response'),
|
||||
page: pageNrSchema,
|
||||
sess: sessSchema,
|
||||
ip: sessIPSchema
|
||||
|
@ -2533,6 +2572,8 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
let pagePrevious = result.value.previous;
|
||||
let sortAscending = result.value.order === 'asc';
|
||||
|
||||
let includeHeaders = result.value.includeHeaders ? result.value.includeHeaders.split(',') : false;
|
||||
|
||||
let total = await db.database.collection('archived').countDocuments({ user });
|
||||
|
||||
let opts = {
|
||||
|
@ -2551,13 +2592,6 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
hdate: true,
|
||||
idate: true,
|
||||
subject: true,
|
||||
'mimeTree.parsedHeader.from': true,
|
||||
'mimeTree.parsedHeader.sender': true,
|
||||
'mimeTree.parsedHeader.to': true,
|
||||
'mimeTree.parsedHeader.cc': true,
|
||||
'mimeTree.parsedHeader.bcc': true,
|
||||
'mimeTree.parsedHeader.content-type': true,
|
||||
'mimeTree.parsedHeader.references': true,
|
||||
ha: true,
|
||||
intro: true,
|
||||
size: true,
|
||||
|
@ -2573,6 +2607,24 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
sortAscending
|
||||
};
|
||||
|
||||
if (includeHeaders) {
|
||||
// get all headers
|
||||
opts.fields.projection['mimeTree.parsedHeader'] = true;
|
||||
} else {
|
||||
// get only required headers
|
||||
for (let requiredHeader of [
|
||||
'mimeTree.parsedHeader.from',
|
||||
'mimeTree.parsedHeader.sender',
|
||||
'mimeTree.parsedHeader.to',
|
||||
'mimeTree.parsedHeader.cc',
|
||||
'mimeTree.parsedHeader.bcc',
|
||||
'mimeTree.parsedHeader.content-type',
|
||||
'mimeTree.parsedHeader.references'
|
||||
]) {
|
||||
opts.fields.projection[requiredHeader] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pageNext) {
|
||||
opts.next = pageNext;
|
||||
} else if ((!page || page > 1) && pagePrevious) {
|
||||
|
@ -2606,7 +2658,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
m.uid = m._id;
|
||||
return m;
|
||||
})
|
||||
.map(formatMessageListing)
|
||||
.map(entry => formatMessageListing(entry, includeHeaders))
|
||||
};
|
||||
|
||||
return res.json(response);
|
||||
|
@ -3127,7 +3179,17 @@ function leftPad(val, chr, len) {
|
|||
return chr.repeat(len - val.toString().length) + val;
|
||||
}
|
||||
|
||||
function formatMessageListing(messageData) {
|
||||
function formatMessageListing(messageData, includeHeaders) {
|
||||
includeHeaders = []
|
||||
.concat(includeHeaders || [])
|
||||
.map(entry => {
|
||||
if (typeof entry !== 'string') {
|
||||
return false;
|
||||
}
|
||||
return entry.toLowerCase().trim();
|
||||
})
|
||||
.filter(entry => entry);
|
||||
|
||||
let parsedHeader = (messageData.mimeTree && messageData.mimeTree.parsedHeader) || {};
|
||||
|
||||
let from = parsedHeader.from ||
|
||||
|
@ -3176,6 +3238,15 @@ function formatMessageListing(messageData) {
|
|||
bimi: messageData.bimi
|
||||
};
|
||||
|
||||
if (includeHeaders.length) {
|
||||
response.headers = {};
|
||||
for (let headerKey of includeHeaders) {
|
||||
if (parsedHeader[headerKey]) {
|
||||
response.headers[headerKey] = parsedHeader[headerKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (messageData.meta && 'custom' in messageData.meta) {
|
||||
response.metaData = tools.formatMetaData(messageData.meta.custom);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue