Skip to content

Commit

Permalink
Merge pull request #16 from mailosaur/updated-get
Browse files Browse the repository at this point in the history
Update get and search methods
  • Loading branch information
jm-mailosaur authored Jul 15, 2019
2 parents 951d0a4 + 30230bf commit 29c2e6f
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 96 deletions.
224 changes: 149 additions & 75 deletions lib/operations/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,86 @@ class Messages {
}

/**
* @summary Retrieve a message
* @summary Retrieve a message using search criteria
*
* Returns as soon as a message matching the specified search criteria is
* found. This is the most efficient method of looking up a message.
*
* @param {string} server The identifier of the server hosting the message.
*
* @param {object} criteria The search criteria to use in order to find a
* match.
*
* @param {string} [criteria.sentTo] The full email address to which the target
* email was sent.
*
* @param {string} [criteria.subject] The value to seek within the target
* email's subject line.
*
* @param {string} [criteria.body] The value to seek within the target email's
* HTML or text body.
*
* @param {object} [options] Optional Parameters.
*
* @param {number} [options.timeout] Specify how long to wait for a matching
* result (in milliseconds).
*
* @param {date} [options.receivedAfter] Limits results to only messages
* received after this date/time (default 20 seconds ago).
*
* @param {function} [optionalCallback] - The optional callback.
*
* @returns {function|Promise} If a callback was passed as the last parameter
* then it returns the callback else returns a Promise.
*
* {Promise} A promise is returned
*
* @resolve {Message} - The deserialized result object.
*
* @reject {Error} - The error object.
*
* {function} optionalCallback(err, result, request, response)
*
* {Error} err - The Error object if an error occurred, null otherwise.
*
* {object} [result] - The deserialized result object if an error did not occur.
* See {@link Message} for more information.
*/
get(server, criteria, options, optionalCallback) {
let self = this;
let getByIdError = new Error('Use getById to retrieve a message using its identifier');

options = options || {};

// Default timeout to 10s
options.timeout = options.timeout || 10000;

// Default receivedAfter to 1h
options.receivedAfter = options.receivedAfter || new Date(Date.now() - 3600000);

if (server.length > 8) {
return optionalCallback ? optionalCallback(getByIdError) : new Promise((resolve, reject) => {
reject(getByIdError);
});
}

if (!optionalCallback) {
return new Promise((resolve) => {
self.search(server, criteria, options).then((result) => {
return self.getById(result.items[0].id);
}).then((message) => {
resolve(message);
});
});
} else {
self.search(server, criteria, options).then((result) => {
self.getById(result.items[0].id, optionalCallback);
});
}
}

/**
* @summary Retrieve a message using message id
*
* Retrieves the detail for a single email message. Simply supply the unique
* identifier for the required message.
Expand All @@ -40,11 +119,11 @@ class Messages {
* {object} [result] - The deserialized result object if an error did not occur.
* See {@link Message} for more information.
*/
get(id, optionalCallback) {
getById(id, optionalCallback) {
let client = this.client;
let self = this;
let url = `api/messages/${id}`;

if (!optionalCallback) {
return new Promise((resolve, reject) => {
self.client.request.get(url, (err, response, body) => {
Expand Down Expand Up @@ -262,6 +341,12 @@ class Messages {
* @param {number} [options.itemsPerPage] A limit on the number of results to
* be returned per page. Can be set between 1 and 1000 items, the default is
* 50.
*
* @param {number} [options.timeout] Specify how long to wait for a matching
* result (in milliseconds).
*
* @param {date} [options.receivedAfter] Limits results to only messages
* received after this date/time.
*
* @param {function} [optionalCallback] - The optional callback.
*
Expand All @@ -285,96 +370,85 @@ class Messages {
let client = this.client;
let self = this;
let url = `api/messages/search`;
let pollCount = 0;
let startTime = Date.now();

options = options || {};
let qs = {
server: server,
page: options.page,
itemPerPage: options.itemsPerPage
itemPerPage: options.itemsPerPage,
receivedAfter: options.receivedAfter
};

if (!Number.isInteger(options.timeout)) {
options.timeout = 0;
}

if (!optionalCallback) {
return new Promise((resolve, reject) => {
let fn = (resolve, reject) => function() {
self.client.request.post(url, { qs: qs, body: criteria }, (err, response, body) => {
if (err || response.statusCode !== 200) {
return reject(new MailosaurError(response));
}
return reject(new MailosaurError(response));
}

if (options.timeout && !body.items.length) {
let delayPattern = (response.headers['x-ms-delay'] || '1000')
.split(',')
.map(x => parseInt(x, 10));

let delay = (pollCount >= delayPattern.length) ?
delayPattern[delayPattern.length - 1] :
delayPattern[pollCount];

pollCount++;

// Stop if timeout will be exceeded
if (((Date.now() - startTime) + delay) > options.timeout) {
return reject(new MailosaurError(response));
}

return setTimeout(fn(resolve, reject), delay);
}

resolve(new MessageListResult(body));
});
};

return new Promise((resolve, reject) => {
fn(resolve, reject)();
});
} else {
self.client.request.get(url, { qs: qs, body: criteria }, (err, response, body) => {
if (err || response.statusCode !== 200) {
return optionalCallback(new MailosaurError(response));
}
optionalCallback(null, new MessageListResult(body));
});
}
}
let fn = () => {
self.client.request.post(url, { qs: qs, body: criteria }, (err, response, body) => {
if (err || response.statusCode !== 200) {
return optionalCallback(new MailosaurError(response));
}

/**
* @summary Wait for a specific message
*
* Returns as soon as a message matching the specified search criteria is
* found. This is the most efficient method of looking up a message.
*
* @param {string} server The identifier of the server hosting the message.
*
* @param {object} criteria The search criteria to use in order to find a
* match.
*
* @param {string} [criteria.sentTo] The full email address to which the target
* email was sent.
*
* @param {string} [criteria.subject] The value to seek within the target
* email's subject line.
*
* @param {string} [criteria.body] The value to seek within the target email's
* HTML or text body.
*
* @param {function} [optionalCallback] - The optional callback.
*
* @returns {function|Promise} If a callback was passed as the last parameter
* then it returns the callback else returns a Promise.
*
* {Promise} A promise is returned
*
* @resolve {Message} - The deserialized result object.
*
* @reject {Error} - The error object.
*
* {function} optionalCallback(err, result, request, response)
*
* {Error} err - The Error object if an error occurred, null otherwise.
*
* {object} [result] - The deserialized result object if an error did not occur.
* See {@link Message} for more information.
*/
waitFor(server, criteria, optionalCallback) {
let client = this.client;
let self = this;
let url = `api/messages/await`;
if (options.timeout && !body.items.length) {
let delayPattern = (response.headers['x-ms-delay'] || '1000')
.split(',')
.map(x => parseInt(x, 10));

let qs = {
server: server
};
let delay = (pollCount >= delayPattern.length) ?
delayPattern[delayPattern.length - 1] :
delayPattern[pollCount];

pollCount++;

if (!optionalCallback) {
return new Promise((resolve, reject) => {
self.client.request.post(url, { qs: qs, body: criteria }, (err, response, body) => {
if (err || response.statusCode !== 200) {
return reject(new MailosaurError(response));
}
resolve(new Message(body));
// Stop if timeout will be exceeded
if (((Date.now() - startTime) + delay) > options.timeout) {
return optionalCallback(new MailosaurError(response));
}

return setTimeout(fn(resolve, reject), delay);
}

optionalCallback(null, new MessageListResult(body));
});
});
} else {
self.client.request.get(url, { qs: qs, body: criteria }, (err, response, body) => {
if (err || response.statusCode !== 200) {
return optionalCallback(new MailosaurError(response));
}
optionalCallback(null, new Message(body));
});
};

fn();
}
}
}
Expand Down
40 changes: 20 additions & 20 deletions test/emails.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,26 @@ describe('emails', () => {
});

describe('get', () => {
it('should return a match once found', (done) => {
var host = process.env.MAILOSAUR_SMTP_HOST || 'mailosaur.io';
var testEmailAddress = `wait_for_test.${server}@${host}`;
mailer.sendEmail(client, server, testEmailAddress)
.then(() => {
return client.messages.get(server, {
sentTo: testEmailAddress
});
})
.then((email) => {
validateEmail(email);
done();
})
.catch(done);
});
});

describe('getById', () => {
it('should return a single email', (done) => {
client.messages.get(emails[0].id)
client.messages.getById(emails[0].id)
.then((email) => {
validateEmail(email);
validateHeaders(email);
Expand All @@ -128,32 +146,14 @@ describe('emails', () => {
});

it('should throw an error if email not found', (done) => {
client.messages.get('efe907e9-74ed-4113-a3e0-a3d41d914765')
client.messages.getById('efe907e9-74ed-4113-a3e0-a3d41d914765')
.catch((err) => {
assert.instanceOf(err, MailosaurError);
done();
});
});
});

describe('waitFor', () => {
it('should return a match once found', (done) => {
var host = process.env.MAILOSAUR_SMTP_HOST || 'mailosaur.io';
var testEmailAddress = `wait_for_test.${server}@${host}`;
mailer.sendEmail(client, server, testEmailAddress)
.then(() => {
return client.messages.waitFor(server, {
sentTo: testEmailAddress
});
})
.then((email) => {
validateEmail(email);
done();
})
.catch(done);
});
});

describe('search', () => {
it('should throw an error if no criteria', (done) => {
client.messages
Expand Down
2 changes: 1 addition & 1 deletion test/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('files', () => {
return mailer.sendEmail(client, server, testEmailAddress);
})
.then(() => {
return client.messages.waitFor(server, {
return client.messages.get(server, {
sentTo: testEmailAddress
});
})
Expand Down

0 comments on commit 29c2e6f

Please sign in to comment.