Files
n8n-enterprise-unlocked/packages/nodes-base/nodes/Microsoft/Outlook/v2/transport/index.ts
2023-09-15 12:52:18 +03:00

225 lines
5.4 KiB
TypeScript

import type { OptionsWithUri } from 'request';
import {
type IDataObject,
type IExecuteFunctions,
type IExecuteSingleFunctions,
type ILoadOptionsFunctions,
type INodeExecutionData,
} from 'n8n-workflow';
import { prepareApiError } from '../helpers/utils';
export async function microsoftApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
body: IDataObject = {},
qs: IDataObject = {},
uri?: string,
headers: IDataObject = {},
option: IDataObject = { json: true },
) {
const credentials = await this.getCredentials('microsoftOutlookOAuth2Api');
let apiUrl = `https://graph.microsoft.com/v1.0/me${resource}`;
// If accessing shared mailbox
if (credentials.useShared && credentials.userPrincipalName) {
apiUrl = `https://graph.microsoft.com/v1.0/users/${credentials.userPrincipalName}${resource}`;
}
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
},
method,
body,
qs,
uri: uri || apiUrl,
};
try {
Object.assign(options, option);
if (Object.keys(headers).length !== 0) {
options.headers = Object.assign({}, options.headers, headers);
}
if (Object.keys(body).length === 0) {
delete options.body;
}
return await this.helpers.requestWithAuthentication.call(
this,
'microsoftOutlookOAuth2Api',
options,
);
} catch (error) {
if (
((error.message || '').toLowerCase().includes('bad request') ||
(error.message || '').toLowerCase().includes('unknown error')) &&
error.description
) {
let updatedError;
// Try to return the error prettier, otherwise return the original one repalcing the message with the description
try {
updatedError = prepareApiError.call(this, error);
} catch (e) {}
if (updatedError) throw updatedError;
error.message = error.description;
error.description = '';
}
throw error;
}
}
export async function microsoftApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
body: IDataObject = {},
query: IDataObject = {},
headers: IDataObject = {},
) {
const returnData: IDataObject[] = [];
let responseData;
let nextLink: string | undefined;
query.$top = 100;
do {
responseData = await microsoftApiRequest.call(
this,
method,
endpoint,
body,
nextLink ? undefined : query, // Do not add query parameters as nextLink already contains them
nextLink,
headers,
);
nextLink = responseData['@odata.nextLink'];
returnData.push.apply(returnData, responseData[propertyName] as IDataObject[]);
} while (responseData['@odata.nextLink'] !== undefined);
return returnData;
}
export async function downloadAttachments(
this: IExecuteFunctions,
messages: IDataObject[] | IDataObject,
prefix: string,
) {
const elements: INodeExecutionData[] = [];
if (!Array.isArray(messages)) {
messages = [messages];
}
for (const message of messages) {
const element: INodeExecutionData = {
json: message,
binary: {},
};
if (message.hasAttachments === true) {
const attachments = await microsoftApiRequestAllItems.call(
this,
'value',
'GET',
`/messages/${message.id}/attachments`,
{},
);
for (const [index, attachment] of attachments.entries()) {
const response = await microsoftApiRequest.call(
this,
'GET',
`/messages/${message.id}/attachments/${attachment.id}/$value`,
undefined,
{},
undefined,
{},
{ encoding: null, resolveWithFullResponse: true },
);
const data = Buffer.from(response.body as string, 'utf8');
element.binary![`${prefix}${index}`] = await this.helpers.prepareBinaryData(
data as unknown as Buffer,
attachment.name as string,
attachment.contentType as string,
);
}
}
if (Object.keys(element.binary!).length === 0) {
delete element.binary;
}
elements.push(element);
}
return elements;
}
export async function getMimeContent(
this: IExecuteFunctions,
messageId: string,
binaryPropertyName: string,
outputFileName?: string,
) {
const response = await microsoftApiRequest.call(
this,
'GET',
`/messages/${messageId}/$value`,
undefined,
{},
undefined,
{},
{ encoding: null, resolveWithFullResponse: true },
);
let mimeType: string | undefined;
if (response.headers['content-type']) {
mimeType = response.headers['content-type'];
}
const fileName = `${outputFileName || messageId}.eml`;
const data = Buffer.from(response.body as string, 'utf8');
const binary: IDataObject = {};
binary[binaryPropertyName] = await this.helpers.prepareBinaryData(
data as unknown as Buffer,
fileName,
mimeType,
);
return binary;
}
export async function getSubfolders(
this: IExecuteFunctions | ILoadOptionsFunctions,
folders: IDataObject[],
addPathToDisplayName = false,
) {
const returnData: IDataObject[] = [...folders];
for (const folder of folders) {
if ((folder.childFolderCount as number) > 0) {
let subfolders = await microsoftApiRequest.call(
this,
'GET',
`/mailFolders/${folder.id}/childFolders`,
);
if (addPathToDisplayName) {
subfolders = subfolders.value.map((subfolder: IDataObject) => {
return {
...subfolder,
displayName: `${folder.displayName}/${subfolder.displayName}`,
};
});
} else {
subfolders = subfolders.value;
}
returnData.push(
...(await getSubfolders.call(this, subfolders as IDataObject[], addPathToDisplayName)),
);
}
}
return returnData;
}