Skip to content

Commit

Permalink
fix(api): Improved message-move API endpoint for Gmail API accounts. …
Browse files Browse the repository at this point in the history
…There is now a new payload option 'source' that specifies the folder the message is moved from
  • Loading branch information
andris9 committed Feb 1, 2025
1 parent d1bd122 commit 861bc23
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 15 deletions.
3 changes: 2 additions & 1 deletion lib/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -1161,13 +1161,14 @@ class Account {
return x;
}

async moveMessage(message, target) {
async moveMessage(message, target, options) {
await this.loadAccountData(this.account, true);
return await this.call({
cmd: 'moveMessage',
account: this.account,
message,
target,
options,
timeout: this.timeout
});
}
Expand Down
24 changes: 22 additions & 2 deletions lib/email-client/gmail-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -879,9 +879,11 @@ class GmailClient extends BaseClient {
});
}

async moveMessage(emailId, target) {
async moveMessage(emailId, target, options) {
await this.prepare();

options = options || {};

let path = [].concat(target?.path || []).join('/');

let label = await this.getLabel(path);
Expand All @@ -894,8 +896,26 @@ class GmailClient extends BaseClient {
error.statusCode = 404;
throw error;
}
let labelsUpdate = { add: [label.id] };

let sourcePath = options.source?.path;

let sourceLabel = sourcePath ? await this.getLabel(sourcePath) : null;
if (sourcePath && !sourceLabel) {
let error = new Error('Unknown path');
error.info = {
response: `Mailbox doesn't exist: ${sourcePath}`
};
error.code = 'NotFound';
error.statusCode = 404;
throw error;
}

if (sourceLabel) {
labelsUpdate.delete = sourceLabel.id;
}

await this.updateMessage(emailId, { labels: { add: [label.id] } });
await this.updateMessage(emailId, { labels: labelsUpdate });

return {
path,
Expand Down
4 changes: 2 additions & 2 deletions lib/email-client/imap-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -1381,7 +1381,7 @@ class IMAPClient extends BaseClient {
return await this.getCurrentListing(options, connectionOptions);
}

async moveMessage(id, target, connectionOptions) {
async moveMessage(id, target, options, connectionOptions) {
target = target || {};
connectionOptions = connectionOptions || { allowSecondary: true };

Expand All @@ -1399,7 +1399,7 @@ class IMAPClient extends BaseClient {
}

let mailbox = this.mailboxes.get(normalizePath(message.path));
return await mailbox.moveMessage(message, target, connectionOptions);
return await mailbox.moveMessage(message, target, options, connectionOptions);
}

async moveMessages(source, search, target, connectionOptions) {
Expand Down
2 changes: 1 addition & 1 deletion lib/email-client/imap/mailbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -2644,7 +2644,7 @@ class Mailbox {
}
}

async moveMessage(message, target, connectionOptions) {
async moveMessage(message, target, options, connectionOptions) {
target = target || {};

const connectionClient = await this.connection.getImapConnection(connectionOptions);
Expand Down
34 changes: 26 additions & 8 deletions workers/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4472,7 +4472,17 @@ const init = async () => {
});

try {
return await accountObject.moveMessage(request.params.message, request.payload);
return await accountObject.moveMessage(
request.params.message,
{ path: request.payload.path },
{
source: request.payload.source
? {
path: request.payload.source
}
: null
}
);
} catch (err) {
request.logger.error({ msg: 'API request failed', err });
if (Boom.isBoom(err)) {
Expand All @@ -4486,8 +4496,8 @@ const init = async () => {
}
},
options: {
description: 'Move message',
notes: 'Move message to another folder',
description: 'Move a message to a specified folder',
notes: 'Moves a message to a target folder',
tags: ['api', 'Message'],

plugins: {},
Expand All @@ -4512,15 +4522,23 @@ const init = async () => {
}),

payload: Joi.object({
path: Joi.string().required().example('INBOX').description('Target mailbox folder path')
}).label('MessageMove')
path: Joi.string().required().example('INBOX').description('Destination mailbox folder path'),
source: Joi.string()
.example('INBOX')
.description('Source mailbox folder path (Gmail API only). Needed to remove the label from the message.')
})
.example({ path: 'Target/Folder' })
.label('MessageMove')
},

response: {
schema: Joi.object({
path: Joi.string().required().example('INBOX').description('Target mailbox folder path'),
id: Joi.string().max(256).required().example('AAAAAQAACnA').description('Message ID'),
uid: Joi.number().integer().example(12345).description('UID of moved message')
path: Joi.string().required().example('INBOX').description('Destination mailbox folder path'),
id: Joi.string().max(256).example('AAAAAQAACnA').description('ID of the moved message. Only included if the server provides it.'),
uid: Joi.number()
.integer()
.example(12345)
.description('UID of the moved message, applies only to IMAP accounts. Only included if the server provides it.')
}).label('MessageMoveResponse'),
failAction: 'log'
}
Expand Down
2 changes: 1 addition & 1 deletion workers/imap.js
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ class ConnectionHandler {
return NO_ACTIVE_HANDLER_RESP;
}

return await accountData.connection.moveMessage(message.message, message.target);
return await accountData.connection.moveMessage(message.message, message.target, message.options);
}

async moveMessages(message) {
Expand Down

0 comments on commit 861bc23

Please sign in to comment.