mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-20 11:22:15 +00:00
feat(Microsoft SharePoint Node): New node (#13727)
This commit is contained in:
committed by
GitHub
parent
64b3fa3d17
commit
954b66218f
@@ -0,0 +1,2 @@
|
||||
export * as listSearch from './listSearch';
|
||||
export * as resourceMapping from './resourceMapping';
|
||||
@@ -0,0 +1,252 @@
|
||||
import type {
|
||||
IDataObject,
|
||||
ILoadOptionsFunctions,
|
||||
INodeListSearchItems,
|
||||
INodeListSearchResult,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import type { IDriveItem, IList, IListItem, ISite } from '../helpers/interfaces';
|
||||
import { microsoftSharePointApiRequest } from '../transport';
|
||||
|
||||
export async function getFiles(
|
||||
this: ILoadOptionsFunctions,
|
||||
filter?: string,
|
||||
paginationToken?: string,
|
||||
): Promise<INodeListSearchResult> {
|
||||
const site = this.getNodeParameter('site', undefined, { extractValue: true }) as string;
|
||||
const folder = this.getNodeParameter('folder', undefined, { extractValue: true }) as string;
|
||||
|
||||
let response: any;
|
||||
if (paginationToken) {
|
||||
response = await microsoftSharePointApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/sites/${site}/drive/items/${folder}/children`,
|
||||
{},
|
||||
undefined,
|
||||
undefined,
|
||||
paginationToken,
|
||||
);
|
||||
} else {
|
||||
// File filter not supported
|
||||
// https://learn.microsoft.com/en-us/onedrive/developer/rest-api/concepts/filtering-results?view=odsp-graph-online#filterable-properties
|
||||
const qs: IDataObject = {
|
||||
$select: 'id,name,file',
|
||||
};
|
||||
if (filter) {
|
||||
qs.$filter = `name eq '${filter}'`;
|
||||
}
|
||||
response = await microsoftSharePointApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/sites/${site}/drive/items/${folder}/children`,
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
}
|
||||
|
||||
const items: IDriveItem[] = response.value;
|
||||
|
||||
const results: INodeListSearchItems[] = items
|
||||
.filter((x) => x.file)
|
||||
.map((g) => ({
|
||||
name: g.name,
|
||||
value: g.id,
|
||||
}))
|
||||
.sort((a, b) =>
|
||||
a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' }),
|
||||
);
|
||||
|
||||
return { results, paginationToken: response['@odata.nextLink'] };
|
||||
}
|
||||
|
||||
export async function getFolders(
|
||||
this: ILoadOptionsFunctions,
|
||||
filter?: string,
|
||||
paginationToken?: string,
|
||||
): Promise<INodeListSearchResult> {
|
||||
const site = this.getNodeParameter('site', undefined, { extractValue: true }) as string;
|
||||
|
||||
let response: any;
|
||||
if (paginationToken) {
|
||||
response = await microsoftSharePointApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/sites/${site}/drive/items`,
|
||||
{},
|
||||
undefined,
|
||||
undefined,
|
||||
paginationToken,
|
||||
);
|
||||
} else {
|
||||
const qs: IDataObject = {
|
||||
$select: 'id,name,folder',
|
||||
// Folder filter not supported, but filter is still required
|
||||
// https://learn.microsoft.com/en-us/onedrive/developer/rest-api/concepts/filtering-results?view=odsp-graph-online#filterable-properties
|
||||
$filter: 'folder ne null',
|
||||
};
|
||||
if (filter) {
|
||||
qs.$filter = `name eq '${filter}'`;
|
||||
}
|
||||
response = await microsoftSharePointApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/sites/${site}/drive/items`,
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
}
|
||||
|
||||
const items: IDriveItem[] = response.value;
|
||||
|
||||
const results: INodeListSearchItems[] = items
|
||||
.filter((x) => x.folder)
|
||||
.map((g) => ({
|
||||
name: g.name,
|
||||
value: g.id,
|
||||
}))
|
||||
.sort((a, b) =>
|
||||
a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' }),
|
||||
);
|
||||
|
||||
return { results, paginationToken: response['@odata.nextLink'] };
|
||||
}
|
||||
|
||||
export async function getItems(
|
||||
this: ILoadOptionsFunctions,
|
||||
filter?: string,
|
||||
paginationToken?: string,
|
||||
): Promise<INodeListSearchResult> {
|
||||
const site = this.getNodeParameter('site', undefined, { extractValue: true }) as string;
|
||||
const list = this.getNodeParameter('list', undefined, { extractValue: true }) as string;
|
||||
|
||||
let response: any;
|
||||
if (paginationToken) {
|
||||
response = await microsoftSharePointApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/sites/${site}/lists/${list}/items`,
|
||||
{},
|
||||
undefined,
|
||||
undefined,
|
||||
paginationToken,
|
||||
);
|
||||
} else {
|
||||
const qs: IDataObject = {
|
||||
$expand: 'fields(select=Title)',
|
||||
$select: 'id,fields',
|
||||
};
|
||||
if (filter) {
|
||||
qs.$filter = `fields/Title eq '${filter}'`;
|
||||
}
|
||||
response = await microsoftSharePointApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/sites/${site}/lists/${list}/items`,
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
}
|
||||
|
||||
const items: IListItem[] = response.value;
|
||||
|
||||
const results: INodeListSearchItems[] = items
|
||||
.map((g) => ({
|
||||
name: g.fields.Title ?? g.id,
|
||||
value: g.id,
|
||||
}))
|
||||
.sort((a, b) =>
|
||||
a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' }),
|
||||
);
|
||||
|
||||
return { results, paginationToken: response['@odata.nextLink'] };
|
||||
}
|
||||
|
||||
export async function getLists(
|
||||
this: ILoadOptionsFunctions,
|
||||
filter?: string,
|
||||
paginationToken?: string,
|
||||
): Promise<INodeListSearchResult> {
|
||||
const site = this.getNodeParameter('site', undefined, { extractValue: true }) as string;
|
||||
|
||||
let response: any;
|
||||
if (paginationToken) {
|
||||
response = await microsoftSharePointApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/sites/${site}/lists`,
|
||||
{},
|
||||
undefined,
|
||||
undefined,
|
||||
paginationToken,
|
||||
);
|
||||
} else {
|
||||
const qs: IDataObject = {
|
||||
$select: 'id,displayName',
|
||||
};
|
||||
if (filter) {
|
||||
qs.$filter = `displayName eq '${filter}'`;
|
||||
}
|
||||
response = await microsoftSharePointApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/sites/${site}/lists`,
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
}
|
||||
|
||||
const lists: IList[] = response.value;
|
||||
|
||||
const results: INodeListSearchItems[] = lists
|
||||
.map((g) => ({
|
||||
name: g.displayName,
|
||||
value: g.id,
|
||||
}))
|
||||
.sort((a, b) =>
|
||||
a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' }),
|
||||
);
|
||||
|
||||
return { results, paginationToken: response['@odata.nextLink'] };
|
||||
}
|
||||
|
||||
export async function getSites(
|
||||
this: ILoadOptionsFunctions,
|
||||
filter?: string,
|
||||
paginationToken?: string,
|
||||
): Promise<INodeListSearchResult> {
|
||||
let response: any;
|
||||
if (paginationToken) {
|
||||
response = await microsoftSharePointApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/sites',
|
||||
{},
|
||||
undefined,
|
||||
undefined,
|
||||
paginationToken,
|
||||
);
|
||||
} else {
|
||||
const qs: IDataObject = {
|
||||
$select: 'id,title',
|
||||
$search: '*',
|
||||
};
|
||||
if (filter) {
|
||||
qs.$search = filter;
|
||||
}
|
||||
response = await microsoftSharePointApiRequest.call(this, 'GET', '/sites', {}, qs);
|
||||
}
|
||||
|
||||
const sites: ISite[] = response.value;
|
||||
|
||||
const results: INodeListSearchItems[] = sites
|
||||
.map((g) => ({
|
||||
name: g.title,
|
||||
value: g.id,
|
||||
}))
|
||||
.sort((a, b) =>
|
||||
a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' }),
|
||||
);
|
||||
|
||||
return { results, paginationToken: response['@odata.nextLink'] };
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import type {
|
||||
FieldType,
|
||||
ILoadOptionsFunctions,
|
||||
ResourceMapperField,
|
||||
ResourceMapperFields,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import type { IListColumnType } from '../helpers/interfaces';
|
||||
import { microsoftSharePointApiRequest } from '../transport';
|
||||
|
||||
const unsupportedFields = ['geoLocation', 'location', 'term', 'url'];
|
||||
const fieldTypeMapping: Partial<Record<FieldType, string[]>> = {
|
||||
string: ['text', 'user', 'lookup'],
|
||||
// unknownFutureValue: rating
|
||||
number: ['number', 'currency', 'unknownFutureValue'],
|
||||
boolean: ['boolean'],
|
||||
dateTime: ['dateTime'],
|
||||
object: ['thumbnail'],
|
||||
options: ['choice'],
|
||||
};
|
||||
|
||||
function mapType(column: IListColumnType): FieldType | undefined {
|
||||
if (unsupportedFields.includes(column.type)) {
|
||||
return undefined;
|
||||
}
|
||||
let mappedType: FieldType = 'string';
|
||||
for (const t of Object.keys(fieldTypeMapping)) {
|
||||
const postgresTypes = fieldTypeMapping[t as FieldType];
|
||||
if (postgresTypes?.includes(column.type)) {
|
||||
mappedType = t as FieldType;
|
||||
}
|
||||
}
|
||||
return mappedType;
|
||||
}
|
||||
|
||||
export async function getMappingColumns(
|
||||
this: ILoadOptionsFunctions,
|
||||
): Promise<ResourceMapperFields> {
|
||||
const site = this.getNodeParameter('site', undefined, { extractValue: true }) as string;
|
||||
const list = this.getNodeParameter('list', undefined, { extractValue: true }) as string;
|
||||
const operation = this.getNodeParameter('operation') as string;
|
||||
|
||||
const response = await microsoftSharePointApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/sites/${site}/lists/${list}/contentTypes`,
|
||||
{},
|
||||
{ expand: 'columns' },
|
||||
);
|
||||
|
||||
const columns: IListColumnType[] = response.value[0].columns;
|
||||
|
||||
const fields: ResourceMapperField[] = [];
|
||||
|
||||
for (const column of columns.filter((x) => !x.hidden && !x.readOnly)) {
|
||||
const fieldType = mapType(column);
|
||||
const field = {
|
||||
id: column.name,
|
||||
canBeUsedToMatch: column.enforceUniqueValues && column.required,
|
||||
defaultMatch: false,
|
||||
display: true,
|
||||
displayName: column.displayName,
|
||||
readOnly: column.readOnly || !fieldType,
|
||||
required: column.required,
|
||||
type: fieldType,
|
||||
} as ResourceMapperField;
|
||||
if (field.type === 'options') {
|
||||
field.options = [];
|
||||
if (Array.isArray(column.choice?.choices)) {
|
||||
for (const choice of column.choice.choices) {
|
||||
field.options.push({
|
||||
name: choice,
|
||||
value: choice,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
fields.push(field);
|
||||
}
|
||||
|
||||
if (operation === 'update') {
|
||||
fields.push({
|
||||
id: 'id',
|
||||
canBeUsedToMatch: true,
|
||||
defaultMatch: false,
|
||||
display: true,
|
||||
displayName: 'ID',
|
||||
readOnly: true,
|
||||
required: true,
|
||||
type: 'string',
|
||||
});
|
||||
}
|
||||
|
||||
return { fields };
|
||||
}
|
||||
Reference in New Issue
Block a user