@pipedream/sharepoint 0.7.2 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions/create-folder/create-folder.mjs +1 -1
- package/actions/create-item/create-item.mjs +1 -1
- package/actions/create-link/create-link.mjs +1 -1
- package/actions/create-list/create-list.mjs +1 -1
- package/actions/download-file/download-file.mjs +1 -1
- package/actions/download-files/download-files.mjs +88 -0
- package/actions/find-file-by-name/find-file-by-name.mjs +1 -1
- package/actions/find-files-with-metadata/find-files-with-metadata.mjs +1 -1
- package/actions/get-excel-table/get-excel-table.mjs +1 -1
- package/actions/get-file-by-id/get-file-by-id.mjs +1 -1
- package/actions/get-site/get-site.mjs +1 -1
- package/actions/list-files-in-folder/list-files-in-folder.mjs +1 -1
- package/actions/list-sites/list-sites.mjs +1 -1
- package/actions/retrieve-file-metadata/retrieve-file-metadata.mjs +55 -0
- package/actions/search-and-filter-files/search-and-filter-files.mjs +1 -1
- package/actions/search-files/search-files.mjs +1 -1
- package/actions/search-sites/search-sites.mjs +1 -1
- package/actions/update-item/update-item.mjs +1 -1
- package/actions/upload-file/upload-file.mjs +1 -1
- package/common/constants.mjs +23 -0
- package/common/file-picker-base.mjs +308 -0
- package/common/utils.mjs +78 -0
- package/package.json +5 -2
- package/sharepoint.app.mjs +400 -3
- package/sources/new-file-created/new-file-created.mjs +1 -1
- package/sources/new-folder-created/new-folder-created.mjs +1 -1
- package/sources/new-list-item/new-list-item.mjs +1 -1
- package/sources/updated-file-instant/updated-file-instant.mjs +407 -0
- package/sources/updated-list-item/updated-list-item.mjs +1 -1
- package/actions/select-files/select-files.mjs +0 -198
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "sharepoint-create-folder",
|
|
5
5
|
name: "Create Folder",
|
|
6
6
|
description: "Create a new folder in SharePoint. [See the documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_post_children?view=odsp-graph-online)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.5",
|
|
8
8
|
type: "action",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "sharepoint-create-item",
|
|
5
5
|
name: "Create Item",
|
|
6
6
|
description: "Create a new item in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/listitem-create?view=graph-rest-1.0&tabs=http)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.11",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
key: "sharepoint-create-link",
|
|
6
6
|
name: "Create Link",
|
|
7
7
|
description: "Create a sharing link for a DriveItem. [See the documentation](https://docs.microsoft.com/en-us/graph/api/driveitem-createlink?view=graph-rest-1.0&tabs=http)",
|
|
8
|
-
version: "0.0.
|
|
8
|
+
version: "0.0.7",
|
|
9
9
|
type: "action",
|
|
10
10
|
annotations: {
|
|
11
11
|
destructiveHint: false,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "sharepoint-create-list",
|
|
5
5
|
name: "Create List",
|
|
6
6
|
description: "Create a new list in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/list-create?view=graph-rest-1.0&tabs=http)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.11",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -8,7 +8,7 @@ export default {
|
|
|
8
8
|
key: "sharepoint-download-file",
|
|
9
9
|
name: "Download File",
|
|
10
10
|
description: "Download a Microsoft Sharepoint file to the /tmp directory. [See the documentation](https://learn.microsoft.com/en-us/graph/api/driveitem-get-content?view=graph-rest-1.0&tabs=http)",
|
|
11
|
-
version: "0.0.
|
|
11
|
+
version: "0.0.12",
|
|
12
12
|
annotations: {
|
|
13
13
|
destructiveHint: false,
|
|
14
14
|
openWorldHint: true,
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import sharepoint from "../../sharepoint.app.mjs";
|
|
2
|
+
import utils from "../../common/utils.mjs";
|
|
3
|
+
import { filePickerMethods } from "../../common/file-picker-base.mjs";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
key: "sharepoint-download-files",
|
|
7
|
+
name: "Download Files",
|
|
8
|
+
description: "Browse and select files from SharePoint and get their metadata along with pre-authenticated download URLs (valid ~1 hour). [See the documentation](https://learn.microsoft.com/en-us/graph/api/driveitem-get)",
|
|
9
|
+
version: "0.0.1",
|
|
10
|
+
type: "action",
|
|
11
|
+
annotations: {
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
readOnlyHint: true,
|
|
15
|
+
},
|
|
16
|
+
props: {
|
|
17
|
+
sharepoint,
|
|
18
|
+
siteId: {
|
|
19
|
+
propDefinition: [
|
|
20
|
+
sharepoint,
|
|
21
|
+
"siteId",
|
|
22
|
+
],
|
|
23
|
+
withLabel: true,
|
|
24
|
+
},
|
|
25
|
+
driveId: {
|
|
26
|
+
propDefinition: [
|
|
27
|
+
sharepoint,
|
|
28
|
+
"driveId",
|
|
29
|
+
(c) => ({
|
|
30
|
+
siteId: c.siteId,
|
|
31
|
+
}),
|
|
32
|
+
],
|
|
33
|
+
withLabel: true,
|
|
34
|
+
},
|
|
35
|
+
folderId: {
|
|
36
|
+
propDefinition: [
|
|
37
|
+
sharepoint,
|
|
38
|
+
"folderId",
|
|
39
|
+
(c) => ({
|
|
40
|
+
siteId: c.siteId,
|
|
41
|
+
driveId: c.driveId,
|
|
42
|
+
}),
|
|
43
|
+
],
|
|
44
|
+
description: "The folder to browse. Leave empty to browse the root of the drive.",
|
|
45
|
+
optional: true,
|
|
46
|
+
withLabel: true,
|
|
47
|
+
},
|
|
48
|
+
fileIds: {
|
|
49
|
+
propDefinition: [
|
|
50
|
+
sharepoint,
|
|
51
|
+
"fileIds",
|
|
52
|
+
(c) => ({
|
|
53
|
+
siteId: c.siteId,
|
|
54
|
+
driveId: c.driveId,
|
|
55
|
+
folderId: c.folderId,
|
|
56
|
+
}),
|
|
57
|
+
],
|
|
58
|
+
label: "Files",
|
|
59
|
+
description: "Select one or more files to download. **Note:** Only files can be downloaded; folders are not supported.",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
methods: filePickerMethods,
|
|
63
|
+
async run({ $ }) {
|
|
64
|
+
// Parse the fileIds (which are JSON strings from the file picker)
|
|
65
|
+
const selections = utils.parseFileOrFolderList(this.fileIds);
|
|
66
|
+
|
|
67
|
+
if (selections.length === 0) {
|
|
68
|
+
throw new Error("Please select at least one file");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const siteId = this.sharepoint.resolveWrappedValue(this.siteId);
|
|
72
|
+
const driveId = this.sharepoint.resolveWrappedValue(this.driveId);
|
|
73
|
+
|
|
74
|
+
// Fetch metadata for all selected files with download URLs
|
|
75
|
+
const {
|
|
76
|
+
fileResults,
|
|
77
|
+
errors,
|
|
78
|
+
} = await this.fetchFileMetadata($, selections, siteId, driveId, {
|
|
79
|
+
includeDownloadUrl: true,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Process and return results (no folders to handle)
|
|
83
|
+
return this.processResults($, fileResults, errors, [], {
|
|
84
|
+
successVerb: "Retrieved",
|
|
85
|
+
successNoun: "download URL(s)",
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
};
|
|
@@ -6,7 +6,7 @@ export default {
|
|
|
6
6
|
key: "sharepoint-find-file-by-name",
|
|
7
7
|
name: "Find File by Name",
|
|
8
8
|
description: "Search for a file or folder by name. [See the documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_search)",
|
|
9
|
-
version: "0.1.
|
|
9
|
+
version: "0.1.4",
|
|
10
10
|
type: "action",
|
|
11
11
|
annotations: {
|
|
12
12
|
destructiveHint: false,
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
name: "Find Files in List with Metadata",
|
|
6
6
|
description:
|
|
7
7
|
"Search and filter items in a SharePoint list based on metadata and custom columns. [See docs here](https://learn.microsoft.com/en-us/graph/api/listitem-list)",
|
|
8
|
-
version: "0.0.
|
|
8
|
+
version: "0.0.2",
|
|
9
9
|
type: "action",
|
|
10
10
|
annotations: {
|
|
11
11
|
destructiveHint: false,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "sharepoint-get-excel-table",
|
|
5
5
|
name: "Get Excel Table",
|
|
6
6
|
description: "Retrieve a table from an Excel spreadsheet stored in Sharepoint [See the documentation](https://learn.microsoft.com/en-us/graph/api/table-range?view=graph-rest-1.0&tabs=http)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.6",
|
|
8
8
|
type: "action",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "sharepoint-get-file-by-id",
|
|
5
5
|
name: "Get File by ID",
|
|
6
6
|
description: "Retrieves a file by ID. [See the documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_get)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.5",
|
|
8
8
|
type: "action",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "sharepoint-get-site",
|
|
5
5
|
name: "Get Site",
|
|
6
6
|
description: "Get a site in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/site-get?view=graph-rest-1.0&tabs=http)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.3",
|
|
8
8
|
type: "action",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "sharepoint-list-files-in-folder",
|
|
5
5
|
name: "List Files in Folder",
|
|
6
6
|
description: "Retrieves a list of the files and/or folders directly within a folder. [See the documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_list_children)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.5",
|
|
8
8
|
type: "action",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "sharepoint-list-sites",
|
|
5
5
|
name: "List Sites",
|
|
6
6
|
description: "List all sites in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/site-list?view=graph-rest-1.0&tabs=http)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.3",
|
|
8
8
|
type: "action",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import utils from "../../common/utils.mjs";
|
|
2
|
+
import {
|
|
3
|
+
filePickerProps,
|
|
4
|
+
filePickerMethods,
|
|
5
|
+
} from "../../common/file-picker-base.mjs";
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
key: "sharepoint-retrieve-file-metadata",
|
|
9
|
+
name: "Retrieve File Metadata",
|
|
10
|
+
description: "Browse and select files from SharePoint to retrieve their metadata (name, size, dates, etc.) without download URLs. [See the documentation](https://learn.microsoft.com/en-us/graph/api/driveitem-get)",
|
|
11
|
+
version: "0.0.1",
|
|
12
|
+
type: "action",
|
|
13
|
+
annotations: {
|
|
14
|
+
destructiveHint: false,
|
|
15
|
+
openWorldHint: true,
|
|
16
|
+
readOnlyHint: true,
|
|
17
|
+
},
|
|
18
|
+
props: filePickerProps,
|
|
19
|
+
methods: filePickerMethods,
|
|
20
|
+
async run({ $ }) {
|
|
21
|
+
const selections = utils.parseFileOrFolderList(this.fileOrFolderIds);
|
|
22
|
+
|
|
23
|
+
if (selections.length === 0) {
|
|
24
|
+
throw new Error("Please select at least one file or folder");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const siteId = this.sharepoint.resolveWrappedValue(this.siteId);
|
|
28
|
+
const driveId = this.sharepoint.resolveWrappedValue(this.driveId);
|
|
29
|
+
|
|
30
|
+
// Separate files and folders
|
|
31
|
+
const {
|
|
32
|
+
files,
|
|
33
|
+
folders,
|
|
34
|
+
} = this.categorizeSelections(selections);
|
|
35
|
+
|
|
36
|
+
// If only folders selected, return folder info
|
|
37
|
+
if (files.length === 0 && folders.length > 0) {
|
|
38
|
+
return this.handleFolderOnlySelection($, folders);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Fetch metadata for all selected files WITHOUT download URLs
|
|
42
|
+
const {
|
|
43
|
+
fileResults,
|
|
44
|
+
errors,
|
|
45
|
+
} = await this.fetchFileMetadata($, files, siteId, driveId, {
|
|
46
|
+
includeDownloadUrl: false,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Process and return results
|
|
50
|
+
return this.processResults($, fileResults, errors, folders, {
|
|
51
|
+
successVerb: "Retrieved",
|
|
52
|
+
successNoun: "metadata",
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -6,7 +6,7 @@ export default {
|
|
|
6
6
|
name: "Search and Filter Files",
|
|
7
7
|
description:
|
|
8
8
|
"Search and filter SharePoint files based on metadata and custom columns. This action allows you to query files using SharePoint's custom properties, managed metadata, and other column values. [See the documentation](https://learn.microsoft.com/en-us/graph/api/listitem-list)",
|
|
9
|
-
version: "0.0.
|
|
9
|
+
version: "0.0.2",
|
|
10
10
|
type: "action",
|
|
11
11
|
annotations: {
|
|
12
12
|
destructiveHint: false,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "sharepoint-search-files",
|
|
5
5
|
name: "Search Files",
|
|
6
6
|
description: "Search for files in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/search-query?view=graph-rest-1.0&tabs=http)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.3",
|
|
8
8
|
type: "action",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "sharepoint-search-sites",
|
|
5
5
|
name: "Search Sites",
|
|
6
6
|
description: "Search for sites in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/site-search?view=graph-rest-1.0&tabs=http)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.3",
|
|
8
8
|
type: "action",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
key: "sharepoint-update-item",
|
|
6
6
|
name: "Update Item",
|
|
7
7
|
description: "Updates an existing item in Microsoft Sharepoint. [See the documentation](https://learn.microsoft.com/en-us/graph/api/listitem-update?view=graph-rest-1.0&tabs=http)",
|
|
8
|
-
version: "0.0.
|
|
8
|
+
version: "0.0.11",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: true,
|
|
11
11
|
openWorldHint: true,
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
key: "sharepoint-upload-file",
|
|
6
6
|
name: "Upload File",
|
|
7
7
|
description: "Upload a file to OneDrive. [See the documentation](https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_put_content?view=odsp-graph-online)",
|
|
8
|
-
version: "0.0.
|
|
8
|
+
version: "0.0.5",
|
|
9
9
|
type: "action",
|
|
10
10
|
annotations: {
|
|
11
11
|
destructiveHint: false,
|
package/common/constants.mjs
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Microsoft Graph subscription constants for SharePoint webhooks.
|
|
3
|
+
* https://learn.microsoft.com/en-us/graph/api/subscription-post-subscriptions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Maximum subscription lifetime for driveItem resources is 42,300 minutes (~29.4 days).
|
|
8
|
+
* We use 29 days in milliseconds to stay safely within the limit.
|
|
9
|
+
*/
|
|
10
|
+
const WEBHOOK_SUBSCRIPTION_EXPIRATION_TIME_MILLISECONDS = 29 * 24 * 60 * 60 * 1000;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Renewal interval at 95% of max lifetime to ensure renewal before expiration.
|
|
14
|
+
* 29 days * 0.95 = 27.55 days = 2,380,320 seconds
|
|
15
|
+
*/
|
|
16
|
+
const WEBHOOK_SUBSCRIPTION_RENEWAL_SECONDS =
|
|
17
|
+
(WEBHOOK_SUBSCRIPTION_EXPIRATION_TIME_MILLISECONDS * 0.95) / 1000;
|
|
18
|
+
|
|
1
19
|
const SHARING_LINK_TYPE_OPTIONS = [
|
|
2
20
|
{
|
|
3
21
|
label: "Create a read-only link to the DriveItem",
|
|
@@ -84,6 +102,11 @@ const RETURN_CONTENT_TYPE_OPTIONS = [
|
|
|
84
102
|
},
|
|
85
103
|
];
|
|
86
104
|
|
|
105
|
+
export {
|
|
106
|
+
WEBHOOK_SUBSCRIPTION_EXPIRATION_TIME_MILLISECONDS,
|
|
107
|
+
WEBHOOK_SUBSCRIPTION_RENEWAL_SECONDS,
|
|
108
|
+
};
|
|
109
|
+
|
|
87
110
|
export default {
|
|
88
111
|
SHARING_LINK_TYPE_OPTIONS,
|
|
89
112
|
SHARING_LINK_SCOPE_OPTIONS,
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import sharepoint from "../sharepoint.app.mjs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared prop definitions for file picker actions.
|
|
5
|
+
* These props provide a consistent file/folder browsing experience across actions.
|
|
6
|
+
*/
|
|
7
|
+
export const filePickerProps = {
|
|
8
|
+
sharepoint,
|
|
9
|
+
siteId: {
|
|
10
|
+
propDefinition: [
|
|
11
|
+
sharepoint,
|
|
12
|
+
"siteId",
|
|
13
|
+
],
|
|
14
|
+
withLabel: true,
|
|
15
|
+
},
|
|
16
|
+
driveId: {
|
|
17
|
+
propDefinition: [
|
|
18
|
+
sharepoint,
|
|
19
|
+
"driveId",
|
|
20
|
+
(c) => ({
|
|
21
|
+
siteId: c.siteId,
|
|
22
|
+
}),
|
|
23
|
+
],
|
|
24
|
+
withLabel: true,
|
|
25
|
+
},
|
|
26
|
+
folderId: {
|
|
27
|
+
propDefinition: [
|
|
28
|
+
sharepoint,
|
|
29
|
+
"folderId",
|
|
30
|
+
(c) => ({
|
|
31
|
+
siteId: c.siteId,
|
|
32
|
+
driveId: c.driveId,
|
|
33
|
+
}),
|
|
34
|
+
],
|
|
35
|
+
label: "Folder",
|
|
36
|
+
description: "The folder to browse. Leave empty to browse the root of the drive.",
|
|
37
|
+
optional: true,
|
|
38
|
+
withLabel: true,
|
|
39
|
+
},
|
|
40
|
+
fileOrFolderIds: {
|
|
41
|
+
propDefinition: [
|
|
42
|
+
sharepoint,
|
|
43
|
+
"fileOrFolderId",
|
|
44
|
+
(c) => ({
|
|
45
|
+
siteId: c.siteId,
|
|
46
|
+
driveId: c.driveId,
|
|
47
|
+
folderId: c.folderId,
|
|
48
|
+
}),
|
|
49
|
+
],
|
|
50
|
+
type: "string[]",
|
|
51
|
+
label: "Files or Folders",
|
|
52
|
+
description: "Select one or more files, or select a folder and click 'Refresh Fields' to browse into it",
|
|
53
|
+
withLabel: true,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Shared methods for file picker actions.
|
|
59
|
+
* Provides common functionality for parsing selections, fetching metadata,
|
|
60
|
+
* and handling folder-only selections.
|
|
61
|
+
*/
|
|
62
|
+
export const filePickerMethods = {
|
|
63
|
+
/**
|
|
64
|
+
* Categorizes selections into files and folders based on isFolder property.
|
|
65
|
+
*
|
|
66
|
+
* @param {Array<{id: string, name: string, isFolder: boolean}>} selections
|
|
67
|
+
* Array of parsed file/folder objects
|
|
68
|
+
* @returns {{files: Array, folders: Array}}
|
|
69
|
+
* Object with separate files and folders arrays
|
|
70
|
+
* @example
|
|
71
|
+
* const { files, folders } = this.categorizeSelections([
|
|
72
|
+
* { id: "1", name: "report.pdf", isFolder: false },
|
|
73
|
+
* { id: "2", name: "Documents", isFolder: true }
|
|
74
|
+
* ]);
|
|
75
|
+
* // files: [{ id: "1", name: "report.pdf", isFolder: false }]
|
|
76
|
+
* // folders: [{ id: "2", name: "Documents", isFolder: true }]
|
|
77
|
+
*/
|
|
78
|
+
categorizeSelections(selections) {
|
|
79
|
+
return {
|
|
80
|
+
folders: selections.filter((s) => s.isFolder),
|
|
81
|
+
files: selections.filter((s) => !s.isFolder),
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Handles the case where only folders are selected
|
|
87
|
+
* @param {Object} $ - Pipedream step context
|
|
88
|
+
* @param {Array} folders - Array of folder objects
|
|
89
|
+
* @returns {Object} Response object with folder information
|
|
90
|
+
*/
|
|
91
|
+
handleFolderOnlySelection($, folders) {
|
|
92
|
+
const folderNames = folders.map((f) => f.name).join(", ");
|
|
93
|
+
$.export("$summary", `Selected ${folders.length} folder(s): ${folderNames}. Set one as the Folder ID and refresh to browse its contents.`);
|
|
94
|
+
return {
|
|
95
|
+
type: "folders",
|
|
96
|
+
folders: folders.map((f) => ({
|
|
97
|
+
id: f.id,
|
|
98
|
+
name: f.name,
|
|
99
|
+
})),
|
|
100
|
+
message: "To browse a folder, set it as the folderId and reload props",
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Constructs a SharePoint library view URL that opens the file in the
|
|
106
|
+
* document library context. This is useful for providing users with a
|
|
107
|
+
* link to view the file in SharePoint's web interface.
|
|
108
|
+
*
|
|
109
|
+
* @param {string} fileWebUrl - The file's webUrl from Microsoft Graph API
|
|
110
|
+
* @returns {string|null} SharePoint AllItems.aspx URL with file location,
|
|
111
|
+
* or null if construction fails
|
|
112
|
+
* @example
|
|
113
|
+
* // Input: "https://contoso.sharepoint.com/sites/Marketing/..."
|
|
114
|
+
* // Output: "https://contoso.sharepoint.com/sites/Marketing/...aspx?..."
|
|
115
|
+
*/
|
|
116
|
+
constructSharePointViewUrl(fileWebUrl) {
|
|
117
|
+
if (!fileWebUrl) return null;
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
// Parse webUrl to extract components
|
|
121
|
+
// Example: https://tenant.sharepoint.com/sites/sitename/LibraryName/folder/file.ext
|
|
122
|
+
const url = new URL(fileWebUrl);
|
|
123
|
+
|
|
124
|
+
// Extract library path from webUrl (e.g., "Shared%20Documents")
|
|
125
|
+
// Match pattern: /sites/{sitename}/{libraryname}/...
|
|
126
|
+
const libraryMatch = fileWebUrl.match(/\/sites\/[^/]+\/([^/]+)/);
|
|
127
|
+
if (!libraryMatch) return null;
|
|
128
|
+
|
|
129
|
+
const libraryUrlPart = libraryMatch[1]; // This keeps the original encoding from webUrl
|
|
130
|
+
|
|
131
|
+
// Construct site URL
|
|
132
|
+
const siteUrlMatch = fileWebUrl.match(/(https:\/\/[^/]+\/sites\/[^/]+)/);
|
|
133
|
+
if (!siteUrlMatch) return null;
|
|
134
|
+
|
|
135
|
+
const siteUrl = siteUrlMatch[1];
|
|
136
|
+
|
|
137
|
+
// Construct the full file path (decode the pathname to get raw path)
|
|
138
|
+
const filePath = decodeURIComponent(url.pathname);
|
|
139
|
+
|
|
140
|
+
// Construct parent path by removing the filename
|
|
141
|
+
const parentPath = filePath.substring(0, filePath.lastIndexOf("/"));
|
|
142
|
+
|
|
143
|
+
// Build the AllItems.aspx URL - don't re-encode the library name in path
|
|
144
|
+
return `${siteUrl}/${libraryUrlPart}/Forms/AllItems.aspx?id=${encodeURIComponent(filePath)}&parent=${encodeURIComponent(parentPath)}`;
|
|
145
|
+
} catch (error) {
|
|
146
|
+
console.error("Error constructing SharePoint view URL:", error);
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Fetches metadata for multiple files in parallel with individual error
|
|
153
|
+
* handling. Uses Promise.allSettled to ensure partial failures don't
|
|
154
|
+
* block successful fetches.
|
|
155
|
+
*
|
|
156
|
+
* @param {Object} $ - Pipedream step context for API calls
|
|
157
|
+
* @param {Array<{id: string, name: string}>} files
|
|
158
|
+
* Array of file objects with id property
|
|
159
|
+
* @param {string} siteId - SharePoint site ID
|
|
160
|
+
* @param {string} driveId - Drive ID within the site
|
|
161
|
+
* @param {Object} [options={}] - Configuration options
|
|
162
|
+
* @param {boolean} [options.includeDownloadUrl=true]
|
|
163
|
+
* Whether to include temporary downloadUrl in response
|
|
164
|
+
* @returns {Promise<{fileResults: Array, errors: Array}>}
|
|
165
|
+
* Object with successful results and errors
|
|
166
|
+
* @example
|
|
167
|
+
* const { fileResults, errors } = await this.fetchFileMetadata(
|
|
168
|
+
* $, files, siteId, driveId, { includeDownloadUrl: true }
|
|
169
|
+
* );
|
|
170
|
+
*/
|
|
171
|
+
async fetchFileMetadata($, files, siteId, driveId, options = {}) {
|
|
172
|
+
const { includeDownloadUrl = true } = options;
|
|
173
|
+
|
|
174
|
+
// Fetch metadata for all selected files in parallel, handling individual failures
|
|
175
|
+
const settledResults = await Promise.allSettled(
|
|
176
|
+
files.map(async (selected) => {
|
|
177
|
+
// When includeDownloadUrl is true, omit $select to get @microsoft.graph.downloadUrl
|
|
178
|
+
// (Graph API excludes downloadUrl when using $select)
|
|
179
|
+
const params = includeDownloadUrl
|
|
180
|
+
? {}
|
|
181
|
+
: {
|
|
182
|
+
$select: "id,name,size,webUrl,createdDateTime,lastModifiedDateTime,createdBy,lastModifiedBy,parentReference,file,folder,image,video,audio,photo,shared,fileSystemInfo,cTag,eTag,sharepointIds",
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const file = await this.sharepoint.getDriveItem({
|
|
186
|
+
$,
|
|
187
|
+
siteId,
|
|
188
|
+
driveId,
|
|
189
|
+
fileId: selected.id,
|
|
190
|
+
params,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Construct SharePoint library view URL
|
|
194
|
+
const sharepointViewUrl = this.constructSharePointViewUrl(file.webUrl);
|
|
195
|
+
|
|
196
|
+
const result = {
|
|
197
|
+
...file,
|
|
198
|
+
...(sharepointViewUrl && {
|
|
199
|
+
sharepointViewUrl,
|
|
200
|
+
}),
|
|
201
|
+
_meta: {
|
|
202
|
+
siteId,
|
|
203
|
+
driveId,
|
|
204
|
+
fileId: selected.id,
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// Remove the Graph API property name from spread
|
|
209
|
+
delete result["@microsoft.graph.downloadUrl"];
|
|
210
|
+
|
|
211
|
+
// Conditionally include downloadUrl based on options
|
|
212
|
+
if (includeDownloadUrl) {
|
|
213
|
+
result.downloadUrl = file["@microsoft.graph.downloadUrl"];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return result;
|
|
217
|
+
}),
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// Separate successful and failed results
|
|
221
|
+
const fileResults = [];
|
|
222
|
+
const errors = [];
|
|
223
|
+
|
|
224
|
+
settledResults.forEach((result, index) => {
|
|
225
|
+
if (result.status === "fulfilled") {
|
|
226
|
+
fileResults.push(result.value);
|
|
227
|
+
} else {
|
|
228
|
+
const selected = files[index];
|
|
229
|
+
const errorMessage = result.reason?.message || String(result.reason);
|
|
230
|
+
console.error(`Failed to fetch file ${selected.id} (${selected.name}): ${errorMessage}`);
|
|
231
|
+
errors.push({
|
|
232
|
+
fileId: selected.id,
|
|
233
|
+
fileName: selected.name,
|
|
234
|
+
error: errorMessage,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
fileResults,
|
|
241
|
+
errors,
|
|
242
|
+
};
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Processes and formats the final results with user-friendly summary
|
|
247
|
+
* export. Handles single file vs. multiple files formatting for UX.
|
|
248
|
+
*
|
|
249
|
+
* @param {Object} $ - Pipedream step context for exports
|
|
250
|
+
* @param {Array} fileResults - Successfully fetched file metadata
|
|
251
|
+
* @param {Array} errors - Failed file fetches with error details
|
|
252
|
+
* @param {Array} folders
|
|
253
|
+
* Selected folders (for informational purposes)
|
|
254
|
+
* @param {Object} [options={}] - Configuration options
|
|
255
|
+
* @param {string} [options.successVerb="Retrieved"]
|
|
256
|
+
* Verb for summary (e.g., "Retrieved", "Downloaded")
|
|
257
|
+
* @param {string} [options.successNoun="file(s)"]
|
|
258
|
+
* Noun for summary (e.g., "download URL(s)", "metadata")
|
|
259
|
+
* @returns {Object|Array} Single file object if one file, otherwise
|
|
260
|
+
* object with files/errors/folders arrays
|
|
261
|
+
* @throws {Error} If all file fetches failed
|
|
262
|
+
* @example
|
|
263
|
+
* return this.processResults($, fileResults, errors, folders, {
|
|
264
|
+
* successVerb: "Retrieved",
|
|
265
|
+
* successNoun: "download URL(s)"
|
|
266
|
+
* });
|
|
267
|
+
*/
|
|
268
|
+
processResults($, fileResults, errors, folders, options = {}) {
|
|
269
|
+
const {
|
|
270
|
+
successVerb = "Retrieved",
|
|
271
|
+
successNoun = "file(s)",
|
|
272
|
+
} = options;
|
|
273
|
+
|
|
274
|
+
// If all files failed, throw an error
|
|
275
|
+
if (fileResults.length === 0 && errors.length > 0) {
|
|
276
|
+
throw new Error(`Failed to fetch all selected files: ${errors.map((e) => e.fileName).join(", ")}`);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// If single file, return it directly for backwards compatibility
|
|
280
|
+
if (fileResults.length === 1 && folders.length === 0 && errors.length === 0) {
|
|
281
|
+
$.export("$summary", `${successVerb} ${successNoun} for: ${fileResults[0].name}`);
|
|
282
|
+
return fileResults[0];
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Multiple files: return as object with metadata
|
|
286
|
+
const fileNames = fileResults.map((f) => f.name).join(", ");
|
|
287
|
+
const summaryParts = [
|
|
288
|
+
`${successVerb} ${successNoun} for ${fileResults.length} file(s): ${fileNames}`,
|
|
289
|
+
];
|
|
290
|
+
if (errors.length > 0) {
|
|
291
|
+
summaryParts.push(`Failed to fetch ${errors.length} file(s): ${errors.map((e) => e.fileName).join(", ")}`);
|
|
292
|
+
}
|
|
293
|
+
$.export("$summary", summaryParts.join(". "));
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
files: fileResults,
|
|
297
|
+
...(errors.length > 0 && {
|
|
298
|
+
errors,
|
|
299
|
+
}),
|
|
300
|
+
...(folders.length > 0 && {
|
|
301
|
+
folders: folders.map((f) => ({
|
|
302
|
+
id: f.id,
|
|
303
|
+
name: f.name,
|
|
304
|
+
})),
|
|
305
|
+
}),
|
|
306
|
+
};
|
|
307
|
+
},
|
|
308
|
+
};
|