@opencloud-eu/n8n-nodes-opencloud 0.1.0
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/LICENSE.md +21 -0
- package/README.md +136 -0
- package/dist/credentials/OpenCloudApi.credentials.d.ts +10 -0
- package/dist/credentials/OpenCloudApi.credentials.js +61 -0
- package/dist/credentials/OpenCloudApi.credentials.js.map +1 -0
- package/dist/docs/smoke-workflow.png +0 -0
- package/dist/icons/opencloud.svg +3 -0
- package/dist/nodes/OpenCloud/GenericFunctions.d.ts +37 -0
- package/dist/nodes/OpenCloud/GenericFunctions.js +62 -0
- package/dist/nodes/OpenCloud/GenericFunctions.js.map +1 -0
- package/dist/nodes/OpenCloud/OpenCloud.node.d.ts +15 -0
- package/dist/nodes/OpenCloud/OpenCloud.node.js +1151 -0
- package/dist/nodes/OpenCloud/OpenCloud.node.js.map +1 -0
- package/dist/nodes/OpenCloud/opencloud.svg +3 -0
- package/dist/package.json +70 -0
- package/package.json +70 -0
|
@@ -0,0 +1,1151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenCloud = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const GenericFunctions_1 = require("./GenericFunctions");
|
|
6
|
+
function driveChildrenUrl(driveId, itemId) {
|
|
7
|
+
return `/graph/v1.0/drives/${encodeURIComponent(driveId)}/items/${encodeURIComponent(itemId)}/children`;
|
|
8
|
+
}
|
|
9
|
+
function splitPath(rawPath) {
|
|
10
|
+
return rawPath
|
|
11
|
+
.split('/')
|
|
12
|
+
.map((segment) => segment.trim())
|
|
13
|
+
.filter((segment) => segment.length > 0);
|
|
14
|
+
}
|
|
15
|
+
function joinPath(segments) {
|
|
16
|
+
return segments.length === 0 ? '' : '/' + segments.map(encodeURIComponent).join('/');
|
|
17
|
+
}
|
|
18
|
+
function spaceWebDavUrl(serverUrl, driveId, path) {
|
|
19
|
+
const base = serverUrl.replace(/\/+$/, '');
|
|
20
|
+
return `${base}/dav/spaces/${encodeURIComponent(driveId)}${joinPath(splitPath(path))}`;
|
|
21
|
+
}
|
|
22
|
+
function lastSegment(path) {
|
|
23
|
+
const segments = splitPath(path);
|
|
24
|
+
return segments.length === 0 ? '' : segments[segments.length - 1];
|
|
25
|
+
}
|
|
26
|
+
async function resolvePathToItemId(context, driveId, rawPath, itemIndex) {
|
|
27
|
+
if (splitPath(rawPath).length === 0)
|
|
28
|
+
return driveId;
|
|
29
|
+
return (await resolvePathToItem(context, driveId, rawPath, itemIndex)).id;
|
|
30
|
+
}
|
|
31
|
+
async function resolvePathToItem(context, driveId, rawPath, itemIndex) {
|
|
32
|
+
var _a;
|
|
33
|
+
const segments = splitPath(rawPath);
|
|
34
|
+
if (segments.length === 0) {
|
|
35
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Cannot resolve an empty path to a drive item', { itemIndex });
|
|
36
|
+
}
|
|
37
|
+
let currentItemId = driveId;
|
|
38
|
+
let lastMatch;
|
|
39
|
+
for (let i = 0; i < segments.length; i++) {
|
|
40
|
+
const segment = segments[i];
|
|
41
|
+
const isLast = i === segments.length - 1;
|
|
42
|
+
const stepResponse = (await GenericFunctions_1.openCloudApiRequest.call(context, 'GET', driveChildrenUrl(driveId, currentItemId), '', {}, true));
|
|
43
|
+
const match = ((_a = stepResponse.value) !== null && _a !== void 0 ? _a : []).find((child) => child.name === segment && (isLast || child.folder));
|
|
44
|
+
if (!(match === null || match === void 0 ? void 0 : match.id)) {
|
|
45
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Path not found: ${rawPath}`, { description: `Could not resolve segment "${segment}".`, itemIndex });
|
|
46
|
+
}
|
|
47
|
+
currentItemId = match.id;
|
|
48
|
+
lastMatch = match;
|
|
49
|
+
}
|
|
50
|
+
return lastMatch;
|
|
51
|
+
}
|
|
52
|
+
class OpenCloud {
|
|
53
|
+
constructor() {
|
|
54
|
+
this.description = {
|
|
55
|
+
displayName: 'OpenCloud',
|
|
56
|
+
name: 'openCloud',
|
|
57
|
+
icon: 'file:opencloud.svg',
|
|
58
|
+
group: ['input'],
|
|
59
|
+
version: 1,
|
|
60
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
61
|
+
description: 'Access data on OpenCloud',
|
|
62
|
+
defaults: {
|
|
63
|
+
name: 'OpenCloud',
|
|
64
|
+
},
|
|
65
|
+
usableAsTool: true,
|
|
66
|
+
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
67
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
68
|
+
credentials: [
|
|
69
|
+
{
|
|
70
|
+
name: 'openCloudApi',
|
|
71
|
+
required: true,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
properties: [
|
|
75
|
+
{
|
|
76
|
+
displayName: 'Resource',
|
|
77
|
+
name: 'resource',
|
|
78
|
+
type: 'options',
|
|
79
|
+
noDataExpression: true,
|
|
80
|
+
options: [
|
|
81
|
+
{
|
|
82
|
+
name: 'File',
|
|
83
|
+
value: 'file',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'Folder',
|
|
87
|
+
value: 'folder',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'Space',
|
|
91
|
+
value: 'space',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'User',
|
|
95
|
+
value: 'user',
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
default: 'folder',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
displayName: 'Operation',
|
|
102
|
+
name: 'operation',
|
|
103
|
+
type: 'options',
|
|
104
|
+
noDataExpression: true,
|
|
105
|
+
displayOptions: {
|
|
106
|
+
show: {
|
|
107
|
+
resource: ['space'],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
options: [
|
|
111
|
+
{
|
|
112
|
+
name: 'List',
|
|
113
|
+
value: 'list',
|
|
114
|
+
description: 'List all drives (Personal, Shares, Project) the authenticated user can see',
|
|
115
|
+
action: 'List spaces',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'Share',
|
|
119
|
+
value: 'share',
|
|
120
|
+
description: 'Create a public link or invite a user/group to the space (drive root)',
|
|
121
|
+
action: 'Share a space',
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
default: 'list',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
displayName: 'Operation',
|
|
128
|
+
name: 'operation',
|
|
129
|
+
type: 'options',
|
|
130
|
+
noDataExpression: true,
|
|
131
|
+
displayOptions: {
|
|
132
|
+
show: {
|
|
133
|
+
resource: ['user'],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
options: [
|
|
137
|
+
{
|
|
138
|
+
name: 'Create',
|
|
139
|
+
value: 'create',
|
|
140
|
+
description: 'Create a user (admin only)',
|
|
141
|
+
action: 'Create a user',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'Delete',
|
|
145
|
+
value: 'delete',
|
|
146
|
+
description: 'Delete a user (admin only)',
|
|
147
|
+
action: 'Delete a user',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'Get',
|
|
151
|
+
value: 'get',
|
|
152
|
+
description: 'Retrieve a single user by ID',
|
|
153
|
+
action: 'Get a user',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: 'Get Many',
|
|
157
|
+
value: 'getAll',
|
|
158
|
+
description: 'List many users',
|
|
159
|
+
action: 'Get many users',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'Update',
|
|
163
|
+
value: 'update',
|
|
164
|
+
description: 'Update a user',
|
|
165
|
+
action: 'Update a user',
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
default: 'getAll',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
displayName: 'User ID',
|
|
172
|
+
name: 'userId',
|
|
173
|
+
type: 'string',
|
|
174
|
+
default: '',
|
|
175
|
+
required: true,
|
|
176
|
+
placeholder: 'b1f74ec4-dd7e-11ef-a543-03775734d0f7',
|
|
177
|
+
displayOptions: {
|
|
178
|
+
show: {
|
|
179
|
+
resource: ['user'],
|
|
180
|
+
operation: ['get', 'update', 'delete'],
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
description: 'GUID of the user. Use the User → Get Many operation to find IDs.',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
displayName: 'Username',
|
|
187
|
+
name: 'userName',
|
|
188
|
+
type: 'string',
|
|
189
|
+
default: '',
|
|
190
|
+
required: true,
|
|
191
|
+
placeholder: 'jdoe',
|
|
192
|
+
displayOptions: {
|
|
193
|
+
show: {
|
|
194
|
+
resource: ['user'],
|
|
195
|
+
operation: ['create'],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
description: 'Login name (onPremisesSamAccountName). Must be unique on the server.',
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
displayName: 'Display Name',
|
|
202
|
+
name: 'displayName',
|
|
203
|
+
type: 'string',
|
|
204
|
+
default: '',
|
|
205
|
+
required: true,
|
|
206
|
+
placeholder: 'Jane Doe',
|
|
207
|
+
displayOptions: {
|
|
208
|
+
show: {
|
|
209
|
+
resource: ['user'],
|
|
210
|
+
operation: ['create'],
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
displayName: 'Email',
|
|
216
|
+
name: 'email',
|
|
217
|
+
type: 'string',
|
|
218
|
+
default: '',
|
|
219
|
+
required: true,
|
|
220
|
+
placeholder: 'jane@example.com',
|
|
221
|
+
displayOptions: {
|
|
222
|
+
show: {
|
|
223
|
+
resource: ['user'],
|
|
224
|
+
operation: ['create'],
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
displayName: 'Password',
|
|
230
|
+
name: 'password',
|
|
231
|
+
type: 'string',
|
|
232
|
+
typeOptions: { password: true },
|
|
233
|
+
default: '',
|
|
234
|
+
required: true,
|
|
235
|
+
displayOptions: {
|
|
236
|
+
show: {
|
|
237
|
+
resource: ['user'],
|
|
238
|
+
operation: ['create'],
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
description: 'Initial password. Must satisfy the server\'s password policy.',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
displayName: 'Update Fields',
|
|
245
|
+
name: 'updateFields',
|
|
246
|
+
type: 'collection',
|
|
247
|
+
placeholder: 'Add field',
|
|
248
|
+
default: {},
|
|
249
|
+
displayOptions: {
|
|
250
|
+
show: {
|
|
251
|
+
resource: ['user'],
|
|
252
|
+
operation: ['update'],
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
options: [
|
|
256
|
+
{ displayName: 'Display Name', name: 'displayName', type: 'string', default: '' },
|
|
257
|
+
{ displayName: 'Email', name: 'mail', type: 'string', default: '' },
|
|
258
|
+
{
|
|
259
|
+
displayName: 'Password',
|
|
260
|
+
name: 'password',
|
|
261
|
+
type: 'string',
|
|
262
|
+
typeOptions: { password: true },
|
|
263
|
+
default: '',
|
|
264
|
+
description: 'New password. Must satisfy the server policy.',
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
displayName: 'Account Enabled',
|
|
268
|
+
name: 'accountEnabled',
|
|
269
|
+
type: 'boolean',
|
|
270
|
+
default: true,
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
displayName: 'Operation',
|
|
276
|
+
name: 'operation',
|
|
277
|
+
type: 'options',
|
|
278
|
+
noDataExpression: true,
|
|
279
|
+
displayOptions: {
|
|
280
|
+
show: {
|
|
281
|
+
resource: ['folder'],
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
options: [
|
|
285
|
+
{
|
|
286
|
+
name: 'Copy',
|
|
287
|
+
value: 'copy',
|
|
288
|
+
description: 'Copy a folder',
|
|
289
|
+
action: 'Copy a folder',
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
name: 'Create',
|
|
293
|
+
value: 'create',
|
|
294
|
+
description: 'Create a new folder',
|
|
295
|
+
action: 'Create a folder',
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
name: 'Delete',
|
|
299
|
+
value: 'delete',
|
|
300
|
+
description: 'Delete a folder',
|
|
301
|
+
action: 'Delete a folder',
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: 'List',
|
|
305
|
+
value: 'list',
|
|
306
|
+
description: 'List the contents of a folder',
|
|
307
|
+
action: 'List a folder',
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
name: 'Move',
|
|
311
|
+
value: 'move',
|
|
312
|
+
description: 'Move (or rename) a folder',
|
|
313
|
+
action: 'Move a folder',
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
name: 'Share',
|
|
317
|
+
value: 'share',
|
|
318
|
+
description: 'Create a public sharing link for a folder',
|
|
319
|
+
action: 'Share a folder',
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
default: 'list',
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
displayName: 'Operation',
|
|
326
|
+
name: 'operation',
|
|
327
|
+
type: 'options',
|
|
328
|
+
noDataExpression: true,
|
|
329
|
+
displayOptions: {
|
|
330
|
+
show: {
|
|
331
|
+
resource: ['file'],
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
options: [
|
|
335
|
+
{
|
|
336
|
+
name: 'Copy',
|
|
337
|
+
value: 'copy',
|
|
338
|
+
description: 'Copy a file',
|
|
339
|
+
action: 'Copy a file',
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: 'Delete',
|
|
343
|
+
value: 'delete',
|
|
344
|
+
description: 'Delete a file',
|
|
345
|
+
action: 'Delete a file',
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
name: 'Download',
|
|
349
|
+
value: 'download',
|
|
350
|
+
description: 'Download a file',
|
|
351
|
+
action: 'Download a file',
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
name: 'Move',
|
|
355
|
+
value: 'move',
|
|
356
|
+
description: 'Move (or rename) a file',
|
|
357
|
+
action: 'Move a file',
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
name: 'Share',
|
|
361
|
+
value: 'share',
|
|
362
|
+
description: 'Create a public sharing link for a file',
|
|
363
|
+
action: 'Share a file',
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
name: 'Upload',
|
|
367
|
+
value: 'upload',
|
|
368
|
+
description: 'Upload a file',
|
|
369
|
+
action: 'Upload a file',
|
|
370
|
+
},
|
|
371
|
+
],
|
|
372
|
+
default: 'upload',
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
displayName: 'Space Name or ID',
|
|
376
|
+
name: 'space',
|
|
377
|
+
type: 'options',
|
|
378
|
+
typeOptions: {
|
|
379
|
+
loadOptionsMethod: 'getSpaces',
|
|
380
|
+
},
|
|
381
|
+
default: '',
|
|
382
|
+
required: true,
|
|
383
|
+
description: 'The OpenCloud space (drive) to operate in. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
384
|
+
displayOptions: {
|
|
385
|
+
show: {
|
|
386
|
+
resource: ['folder', 'file'],
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
displayName: 'Space Name or ID',
|
|
392
|
+
name: 'space',
|
|
393
|
+
type: 'options',
|
|
394
|
+
typeOptions: {
|
|
395
|
+
loadOptionsMethod: 'getSpaces',
|
|
396
|
+
},
|
|
397
|
+
default: '',
|
|
398
|
+
required: true,
|
|
399
|
+
description: 'The OpenCloud space (drive) to operate in. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
400
|
+
displayOptions: {
|
|
401
|
+
show: {
|
|
402
|
+
resource: ['space'],
|
|
403
|
+
operation: ['share'],
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
displayName: 'Path',
|
|
409
|
+
name: 'path',
|
|
410
|
+
type: 'string',
|
|
411
|
+
default: '',
|
|
412
|
+
displayOptions: {
|
|
413
|
+
show: {
|
|
414
|
+
resource: ['folder'],
|
|
415
|
+
operation: ['list', 'create', 'delete', 'copy', 'move', 'share'],
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
placeholder: '/Documents',
|
|
419
|
+
description: 'Folder path within the selected space. For Create, this is the parent folder. For Copy/Move, this is the source folder. Leave empty for the space root.',
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
displayName: 'Path',
|
|
423
|
+
name: 'path',
|
|
424
|
+
type: 'string',
|
|
425
|
+
default: '',
|
|
426
|
+
required: true,
|
|
427
|
+
displayOptions: {
|
|
428
|
+
show: {
|
|
429
|
+
resource: ['file'],
|
|
430
|
+
operation: ['delete', 'download', 'copy', 'move', 'share'],
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
placeholder: '/Documents/report.pdf',
|
|
434
|
+
description: 'Full path of the file within the selected space',
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
displayName: 'Destination Space Name or ID',
|
|
438
|
+
name: 'destSpace',
|
|
439
|
+
type: 'options',
|
|
440
|
+
typeOptions: {
|
|
441
|
+
loadOptionsMethod: 'getSpaces',
|
|
442
|
+
},
|
|
443
|
+
default: '',
|
|
444
|
+
description: 'Target space (drive) for the copy or move. Leave empty to use the source space. For Move, must be the same storage as source — cross-storage moves are rejected by the server. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
445
|
+
displayOptions: {
|
|
446
|
+
show: {
|
|
447
|
+
resource: ['file', 'folder'],
|
|
448
|
+
operation: ['copy', 'move'],
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
displayName: 'Destination Parent Path',
|
|
454
|
+
name: 'destParentPath',
|
|
455
|
+
type: 'string',
|
|
456
|
+
default: '',
|
|
457
|
+
displayOptions: {
|
|
458
|
+
show: {
|
|
459
|
+
resource: ['file', 'folder'],
|
|
460
|
+
operation: ['copy', 'move'],
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
placeholder: '/Archive',
|
|
464
|
+
description: 'Folder under which to place the copied/moved item. Leave empty for the space root.',
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
displayName: 'New Name',
|
|
468
|
+
name: 'destName',
|
|
469
|
+
type: 'string',
|
|
470
|
+
default: '',
|
|
471
|
+
displayOptions: {
|
|
472
|
+
show: {
|
|
473
|
+
resource: ['file', 'folder'],
|
|
474
|
+
operation: ['copy', 'move'],
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
placeholder: '(keep source name)',
|
|
478
|
+
description: 'Optional new name for the copied/moved item. Leave empty to keep the source name.',
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
displayName: 'Parent Path',
|
|
482
|
+
name: 'path',
|
|
483
|
+
type: 'string',
|
|
484
|
+
default: '',
|
|
485
|
+
displayOptions: {
|
|
486
|
+
show: {
|
|
487
|
+
resource: ['file'],
|
|
488
|
+
operation: ['upload'],
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
placeholder: '/Documents',
|
|
492
|
+
description: 'Folder to upload the file into. Leave empty for the space root.',
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
displayName: 'Name',
|
|
496
|
+
name: 'name',
|
|
497
|
+
type: 'string',
|
|
498
|
+
default: '',
|
|
499
|
+
required: true,
|
|
500
|
+
displayOptions: {
|
|
501
|
+
show: {
|
|
502
|
+
resource: ['file'],
|
|
503
|
+
operation: ['upload'],
|
|
504
|
+
},
|
|
505
|
+
},
|
|
506
|
+
placeholder: 'report.pdf',
|
|
507
|
+
description: 'Filename to create in the parent folder',
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
displayName: 'Binary File',
|
|
511
|
+
name: 'binaryDataUpload',
|
|
512
|
+
type: 'boolean',
|
|
513
|
+
default: true,
|
|
514
|
+
displayOptions: {
|
|
515
|
+
show: {
|
|
516
|
+
resource: ['file'],
|
|
517
|
+
operation: ['upload'],
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
description: 'Whether to read the file bytes from a binary property on the input item. Turn off to upload literal text content from the field below.',
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
displayName: 'Input Binary Field',
|
|
524
|
+
name: 'binaryProperty',
|
|
525
|
+
type: 'string',
|
|
526
|
+
default: 'data',
|
|
527
|
+
required: true,
|
|
528
|
+
displayOptions: {
|
|
529
|
+
show: {
|
|
530
|
+
resource: ['file'],
|
|
531
|
+
operation: ['upload'],
|
|
532
|
+
binaryDataUpload: [true],
|
|
533
|
+
},
|
|
534
|
+
},
|
|
535
|
+
description: 'Name of the binary property on the input item that contains the file bytes',
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
displayName: 'File Content',
|
|
539
|
+
name: 'fileContent',
|
|
540
|
+
type: 'string',
|
|
541
|
+
typeOptions: { rows: 4 },
|
|
542
|
+
default: '',
|
|
543
|
+
displayOptions: {
|
|
544
|
+
show: {
|
|
545
|
+
resource: ['file'],
|
|
546
|
+
operation: ['upload'],
|
|
547
|
+
binaryDataUpload: [false],
|
|
548
|
+
},
|
|
549
|
+
},
|
|
550
|
+
placeholder: 'Hello, OpenCloud!',
|
|
551
|
+
description: 'Literal text content to upload as the file. Sent with Content-Type text/plain.',
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
displayName: 'Put Output File in Field',
|
|
555
|
+
name: 'binaryProperty',
|
|
556
|
+
type: 'string',
|
|
557
|
+
default: 'data',
|
|
558
|
+
required: true,
|
|
559
|
+
displayOptions: {
|
|
560
|
+
show: {
|
|
561
|
+
resource: ['file'],
|
|
562
|
+
operation: ['download'],
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
description: 'Name of the binary property on the output item to store the downloaded bytes in',
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
displayName: 'Name',
|
|
569
|
+
name: 'name',
|
|
570
|
+
type: 'string',
|
|
571
|
+
default: '',
|
|
572
|
+
required: true,
|
|
573
|
+
displayOptions: {
|
|
574
|
+
show: {
|
|
575
|
+
resource: ['folder'],
|
|
576
|
+
operation: ['create'],
|
|
577
|
+
},
|
|
578
|
+
},
|
|
579
|
+
placeholder: 'Reports/2024',
|
|
580
|
+
description: 'Name of the folder to create. Use forward slashes to create nested folders in one step (e.g. "Reports/2024" creates Reports and, inside it, 2024). Each missing level is created automatically.',
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
displayName: 'Recipient Type',
|
|
584
|
+
name: 'recipientType',
|
|
585
|
+
type: 'options',
|
|
586
|
+
default: 'publicLink',
|
|
587
|
+
displayOptions: {
|
|
588
|
+
show: {
|
|
589
|
+
resource: ['file', 'folder', 'space'],
|
|
590
|
+
operation: ['share'],
|
|
591
|
+
},
|
|
592
|
+
},
|
|
593
|
+
options: [
|
|
594
|
+
{
|
|
595
|
+
name: 'Group',
|
|
596
|
+
value: 'group',
|
|
597
|
+
description: 'Invite a group (by name or ID) with a unified role',
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
name: 'Public Link',
|
|
601
|
+
value: 'publicLink',
|
|
602
|
+
description: 'Generate a shareable URL (createLink). Anyone with the URL can access according to the link type.',
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
name: 'User',
|
|
606
|
+
value: 'user',
|
|
607
|
+
description: 'Invite a specific user (by name or ID) with a unified role',
|
|
608
|
+
},
|
|
609
|
+
],
|
|
610
|
+
description: 'How to share the resource',
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
displayName: 'Link Type Name or ID',
|
|
614
|
+
name: 'linkType',
|
|
615
|
+
type: 'options',
|
|
616
|
+
typeOptions: {
|
|
617
|
+
loadOptionsMethod: 'getLinkTypes',
|
|
618
|
+
loadOptionsDependsOn: ['resource'],
|
|
619
|
+
},
|
|
620
|
+
default: 'view',
|
|
621
|
+
displayOptions: {
|
|
622
|
+
show: {
|
|
623
|
+
resource: ['file', 'folder', 'space'],
|
|
624
|
+
operation: ['share'],
|
|
625
|
+
recipientType: ['publicLink'],
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
description: 'Permission level granted by the link. The list is filtered by resource type (e.g. Upload and Create Only only apply to folders). Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
displayName: 'Password',
|
|
632
|
+
name: 'password',
|
|
633
|
+
type: 'string',
|
|
634
|
+
typeOptions: { password: true },
|
|
635
|
+
default: '',
|
|
636
|
+
displayOptions: {
|
|
637
|
+
show: {
|
|
638
|
+
resource: ['file', 'folder', 'space'],
|
|
639
|
+
operation: ['share'],
|
|
640
|
+
recipientType: ['publicLink'],
|
|
641
|
+
},
|
|
642
|
+
},
|
|
643
|
+
description: 'Optional password protecting the link. The server may require a password and may enforce a password policy (see the `password_policy` capability).',
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
displayName: 'Recipient',
|
|
647
|
+
name: 'recipientId',
|
|
648
|
+
type: 'resourceLocator',
|
|
649
|
+
default: { mode: 'list', value: '' },
|
|
650
|
+
required: true,
|
|
651
|
+
modes: [
|
|
652
|
+
{
|
|
653
|
+
displayName: 'From List',
|
|
654
|
+
name: 'list',
|
|
655
|
+
type: 'list',
|
|
656
|
+
typeOptions: {
|
|
657
|
+
searchListMethod: 'searchRecipients',
|
|
658
|
+
searchable: true,
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
displayName: 'By ID',
|
|
663
|
+
name: 'id',
|
|
664
|
+
type: 'string',
|
|
665
|
+
placeholder: 'b1f74ec4-dd7e-11ef-a543-03775734d0f7',
|
|
666
|
+
validation: [
|
|
667
|
+
{
|
|
668
|
+
type: 'regex',
|
|
669
|
+
properties: {
|
|
670
|
+
regex: '^[0-9a-fA-F-]+$',
|
|
671
|
+
errorMessage: 'Recipient ID must be a GUID (hex digits and dashes)',
|
|
672
|
+
},
|
|
673
|
+
},
|
|
674
|
+
],
|
|
675
|
+
},
|
|
676
|
+
],
|
|
677
|
+
displayOptions: {
|
|
678
|
+
show: {
|
|
679
|
+
resource: ['file', 'folder', 'space'],
|
|
680
|
+
operation: ['share'],
|
|
681
|
+
recipientType: ['user', 'group'],
|
|
682
|
+
},
|
|
683
|
+
},
|
|
684
|
+
description: 'User or group to invite. Search the directory (admin or matching the server\'s minimum search length for regular users), or paste a known ID.',
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
displayName: 'Role Name or ID',
|
|
688
|
+
name: 'role',
|
|
689
|
+
type: 'options',
|
|
690
|
+
typeOptions: {
|
|
691
|
+
loadOptionsMethod: 'getShareRoles',
|
|
692
|
+
loadOptionsDependsOn: ['resource'],
|
|
693
|
+
},
|
|
694
|
+
default: '',
|
|
695
|
+
required: true,
|
|
696
|
+
displayOptions: {
|
|
697
|
+
show: {
|
|
698
|
+
resource: ['file', 'folder', 'space'],
|
|
699
|
+
operation: ['share'],
|
|
700
|
+
recipientType: ['user', 'group'],
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
description: 'Unified role granted to the recipient. The list is filtered by resource type. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
displayName: 'Expiration',
|
|
707
|
+
name: 'expirationDateTime',
|
|
708
|
+
type: 'string',
|
|
709
|
+
default: '',
|
|
710
|
+
displayOptions: {
|
|
711
|
+
show: {
|
|
712
|
+
resource: ['file', 'folder', 'space'],
|
|
713
|
+
operation: ['share'],
|
|
714
|
+
},
|
|
715
|
+
},
|
|
716
|
+
placeholder: '2026-12-31T23:59:59Z',
|
|
717
|
+
description: 'Optional ISO-8601 timestamp when the link or invite should expire. Leave empty for no expiration.',
|
|
718
|
+
},
|
|
719
|
+
],
|
|
720
|
+
};
|
|
721
|
+
this.methods = {
|
|
722
|
+
loadOptions: {
|
|
723
|
+
async getSpaces() {
|
|
724
|
+
var _a;
|
|
725
|
+
const response = (await GenericFunctions_1.openCloudApiRequest.call(this, 'GET', '/graph/v1.0/me/drives', '', {}, true));
|
|
726
|
+
return ((_a = response.value) !== null && _a !== void 0 ? _a : []).map((drive) => {
|
|
727
|
+
var _a, _b;
|
|
728
|
+
return ({
|
|
729
|
+
name: `${drive.name} (${(_a = drive.driveType) !== null && _a !== void 0 ? _a : 'drive'})`,
|
|
730
|
+
value: (_b = drive.id) !== null && _b !== void 0 ? _b : '',
|
|
731
|
+
});
|
|
732
|
+
});
|
|
733
|
+
},
|
|
734
|
+
async getLinkTypes() {
|
|
735
|
+
const catalog = [
|
|
736
|
+
{
|
|
737
|
+
value: 'view',
|
|
738
|
+
name: 'View',
|
|
739
|
+
description: 'Recipients can view the item',
|
|
740
|
+
appliesTo: ['file', 'folder', 'space'],
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
value: 'edit',
|
|
744
|
+
name: 'Edit',
|
|
745
|
+
description: 'Recipients can view and edit',
|
|
746
|
+
appliesTo: ['file', 'folder', 'space'],
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
value: 'upload',
|
|
750
|
+
name: 'Upload',
|
|
751
|
+
description: 'Recipients can add new items (folder only)',
|
|
752
|
+
appliesTo: ['folder'],
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
value: 'createOnly',
|
|
756
|
+
name: 'Create Only',
|
|
757
|
+
description: 'Recipients can add but not list (folder only)',
|
|
758
|
+
appliesTo: ['folder'],
|
|
759
|
+
},
|
|
760
|
+
];
|
|
761
|
+
const resource = this.getCurrentNodeParameter('resource');
|
|
762
|
+
return catalog
|
|
763
|
+
.filter((entry) => !resource || entry.appliesTo.includes(resource))
|
|
764
|
+
.map((entry) => ({
|
|
765
|
+
name: entry.name,
|
|
766
|
+
value: entry.value,
|
|
767
|
+
description: entry.description,
|
|
768
|
+
}));
|
|
769
|
+
},
|
|
770
|
+
async getShareRoles() {
|
|
771
|
+
const response = (await GenericFunctions_1.openCloudApiRequest.call(this, 'GET', '/graph/v1beta1/roleManagement/permissions/roleDefinitions', '', {}, true));
|
|
772
|
+
const resource = this.getCurrentNodeParameter('resource');
|
|
773
|
+
let conditionMatch = null;
|
|
774
|
+
if (resource === 'file')
|
|
775
|
+
conditionMatch = '@Resource.File';
|
|
776
|
+
else if (resource === 'folder')
|
|
777
|
+
conditionMatch = '@Resource.Folder';
|
|
778
|
+
else if (resource === 'space')
|
|
779
|
+
conditionMatch = '@Resource.Root';
|
|
780
|
+
const roleApplies = (role) => {
|
|
781
|
+
var _a;
|
|
782
|
+
if (!conditionMatch)
|
|
783
|
+
return true;
|
|
784
|
+
return ((_a = role.rolePermissions) !== null && _a !== void 0 ? _a : []).some((p) => { var _a; return ((_a = p.condition) !== null && _a !== void 0 ? _a : '').includes(conditionMatch); });
|
|
785
|
+
};
|
|
786
|
+
return (response !== null && response !== void 0 ? response : [])
|
|
787
|
+
.filter((role) => typeof role.id === 'string' && role.id.length > 0)
|
|
788
|
+
.filter(roleApplies)
|
|
789
|
+
.map((role) => {
|
|
790
|
+
var _a, _b;
|
|
791
|
+
return ({
|
|
792
|
+
name: (_a = role.displayName) !== null && _a !== void 0 ? _a : role.id,
|
|
793
|
+
value: role.id,
|
|
794
|
+
description: (_b = role.description) !== null && _b !== void 0 ? _b : undefined,
|
|
795
|
+
});
|
|
796
|
+
});
|
|
797
|
+
},
|
|
798
|
+
},
|
|
799
|
+
listSearch: {
|
|
800
|
+
async searchRecipients(filter, paginationToken) {
|
|
801
|
+
var _a;
|
|
802
|
+
const recipientType = this.getCurrentNodeParameter('recipientType') || 'user';
|
|
803
|
+
const basePath = recipientType === 'group' ? '/graph/v1.0/groups' : '/graph/v1.0/users';
|
|
804
|
+
const params = ['$top=100'];
|
|
805
|
+
if (filter && filter.trim().length > 0) {
|
|
806
|
+
params.push(`$search=${encodeURIComponent(`"${filter.trim()}"`)}`);
|
|
807
|
+
}
|
|
808
|
+
const endpoint = typeof paginationToken === 'string' && paginationToken.length > 0
|
|
809
|
+
? paginationToken
|
|
810
|
+
: `${basePath}?${params.join('&')}`;
|
|
811
|
+
const response = (await GenericFunctions_1.openCloudApiRequest.call(this, 'GET', endpoint, '', {}, true));
|
|
812
|
+
const results = ((_a = response.value) !== null && _a !== void 0 ? _a : [])
|
|
813
|
+
.filter((entry) => typeof entry.id === 'string' && entry.id.length > 0)
|
|
814
|
+
.map((entry) => {
|
|
815
|
+
var _a, _b, _c;
|
|
816
|
+
const label = (_b = (_a = entry.displayName) !== null && _a !== void 0 ? _a : entry.onPremisesSamAccountName) !== null && _b !== void 0 ? _b : entry.id;
|
|
817
|
+
const hint = (_c = entry.mail) !== null && _c !== void 0 ? _c : entry.onPremisesSamAccountName;
|
|
818
|
+
return {
|
|
819
|
+
name: hint && hint !== label ? `${label} (${hint})` : label,
|
|
820
|
+
value: entry.id,
|
|
821
|
+
};
|
|
822
|
+
});
|
|
823
|
+
return {
|
|
824
|
+
results,
|
|
825
|
+
paginationToken: response['@odata.nextLink'],
|
|
826
|
+
};
|
|
827
|
+
},
|
|
828
|
+
},
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
async execute() {
|
|
832
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
833
|
+
const items = this.getInputData();
|
|
834
|
+
const returnData = [];
|
|
835
|
+
const resource = this.getNodeParameter('resource', 0);
|
|
836
|
+
const operation = this.getNodeParameter('operation', 0);
|
|
837
|
+
for (let i = 0; i < items.length; i++) {
|
|
838
|
+
try {
|
|
839
|
+
if (resource === 'space' && operation === 'list') {
|
|
840
|
+
const response = (await GenericFunctions_1.openCloudApiRequest.call(this, 'GET', '/graph/v1.0/me/drives', '', {}, true));
|
|
841
|
+
for (const drive of (_a = response.value) !== null && _a !== void 0 ? _a : []) {
|
|
842
|
+
returnData.push({
|
|
843
|
+
json: drive,
|
|
844
|
+
pairedItem: { item: i },
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
else if (resource === 'user' && operation === 'getAll') {
|
|
849
|
+
const response = (await GenericFunctions_1.openCloudApiRequest.call(this, 'GET', '/graph/v1.0/users', '', {}, true));
|
|
850
|
+
for (const user of (_b = response.value) !== null && _b !== void 0 ? _b : []) {
|
|
851
|
+
returnData.push({ json: user, pairedItem: { item: i } });
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
else if (resource === 'user' && operation === 'get') {
|
|
855
|
+
const userId = this.getNodeParameter('userId', i);
|
|
856
|
+
const response = (await GenericFunctions_1.openCloudApiRequest.call(this, 'GET', `/graph/v1.0/users/${encodeURIComponent(userId)}`, '', {}, true));
|
|
857
|
+
returnData.push({ json: response, pairedItem: { item: i } });
|
|
858
|
+
}
|
|
859
|
+
else if (resource === 'user' && operation === 'create') {
|
|
860
|
+
const userName = this.getNodeParameter('userName', i).trim();
|
|
861
|
+
const displayName = this.getNodeParameter('displayName', i).trim();
|
|
862
|
+
const email = this.getNodeParameter('email', i).trim();
|
|
863
|
+
const password = this.getNodeParameter('password', i);
|
|
864
|
+
if (!userName || !displayName || !email || !password) {
|
|
865
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Username, Display Name, Email, and Password are all required', { itemIndex: i });
|
|
866
|
+
}
|
|
867
|
+
const body = {
|
|
868
|
+
onPremisesSamAccountName: userName,
|
|
869
|
+
displayName,
|
|
870
|
+
mail: email,
|
|
871
|
+
passwordProfile: { password },
|
|
872
|
+
};
|
|
873
|
+
const response = (await GenericFunctions_1.openCloudApiRequest.call(this, 'POST', '/graph/v1.0/users', body, { 'Content-Type': 'application/json' }, true));
|
|
874
|
+
returnData.push({ json: response, pairedItem: { item: i } });
|
|
875
|
+
}
|
|
876
|
+
else if (resource === 'user' && operation === 'update') {
|
|
877
|
+
const userId = this.getNodeParameter('userId', i);
|
|
878
|
+
const updates = this.getNodeParameter('updateFields', i, {});
|
|
879
|
+
if (Object.keys(updates).length === 0) {
|
|
880
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'At least one field to update is required', { itemIndex: i });
|
|
881
|
+
}
|
|
882
|
+
const body = { ...updates };
|
|
883
|
+
if (typeof body.password === 'string' && body.password.length > 0) {
|
|
884
|
+
body.passwordProfile = { password: body.password };
|
|
885
|
+
}
|
|
886
|
+
delete body.password;
|
|
887
|
+
const updatedUser = (await GenericFunctions_1.openCloudApiRequest.call(this, 'PATCH', `/graph/v1.0/users/${encodeURIComponent(userId)}`, body, { 'Content-Type': 'application/json' }, true));
|
|
888
|
+
returnData.push({ json: updatedUser, pairedItem: { item: i } });
|
|
889
|
+
}
|
|
890
|
+
else if (resource === 'user' && operation === 'delete') {
|
|
891
|
+
const userId = this.getNodeParameter('userId', i);
|
|
892
|
+
await GenericFunctions_1.openCloudApiRequest.call(this, 'DELETE', `/graph/v1.0/users/${encodeURIComponent(userId)}`, '', {}, true);
|
|
893
|
+
returnData.push({ json: {}, pairedItem: { item: i } });
|
|
894
|
+
}
|
|
895
|
+
else if (resource === 'folder' && operation === 'list') {
|
|
896
|
+
const driveId = this.getNodeParameter('space', i);
|
|
897
|
+
const rawPath = this.getNodeParameter('path', i);
|
|
898
|
+
const targetItemId = await resolvePathToItemId(this, driveId, rawPath, i);
|
|
899
|
+
const response = (await GenericFunctions_1.openCloudApiRequest.call(this, 'GET', driveChildrenUrl(driveId, targetItemId), '', {}, true));
|
|
900
|
+
for (const driveItem of (_c = response.value) !== null && _c !== void 0 ? _c : []) {
|
|
901
|
+
returnData.push({
|
|
902
|
+
json: driveItem,
|
|
903
|
+
pairedItem: { item: i },
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
else if (resource === 'folder' && operation === 'create') {
|
|
908
|
+
const driveId = this.getNodeParameter('space', i);
|
|
909
|
+
const parentPath = this.getNodeParameter('path', i);
|
|
910
|
+
const name = this.getNodeParameter('name', i);
|
|
911
|
+
if (!name.trim()) {
|
|
912
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Folder name is required', {
|
|
913
|
+
itemIndex: i,
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
const credentials = await this.getCredentials('openCloudApi');
|
|
917
|
+
const nameSegments = splitPath(name);
|
|
918
|
+
const parentSegments = splitPath(parentPath);
|
|
919
|
+
const finalPath = '/' + [...parentSegments, ...nameSegments].join('/');
|
|
920
|
+
for (let j = 0; j < nameSegments.length; j++) {
|
|
921
|
+
const segPath = '/' + [...parentSegments, ...nameSegments.slice(0, j + 1)].join('/');
|
|
922
|
+
const url = spaceWebDavUrl(credentials.serverUrl, driveId, segPath);
|
|
923
|
+
try {
|
|
924
|
+
await GenericFunctions_1.openCloudApiRequest.call(this, 'MKCOL', url, '', {}, false);
|
|
925
|
+
}
|
|
926
|
+
catch (error) {
|
|
927
|
+
const httpCode = String((_e = (_d = error.httpCode) !== null && _d !== void 0 ? _d : error.statusCode) !== null && _e !== void 0 ? _e : '');
|
|
928
|
+
if (httpCode === '405')
|
|
929
|
+
continue;
|
|
930
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, { itemIndex: i });
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
const createdItem = await resolvePathToItem(this, driveId, finalPath, i);
|
|
934
|
+
returnData.push({
|
|
935
|
+
json: createdItem,
|
|
936
|
+
pairedItem: { item: i },
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
else if (resource === 'file' && operation === 'upload') {
|
|
940
|
+
const driveId = this.getNodeParameter('space', i);
|
|
941
|
+
const parentPath = this.getNodeParameter('path', i);
|
|
942
|
+
const name = this.getNodeParameter('name', i);
|
|
943
|
+
const isBinary = this.getNodeParameter('binaryDataUpload', i, true);
|
|
944
|
+
if (!name.trim()) {
|
|
945
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'File name is required', {
|
|
946
|
+
itemIndex: i,
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
let body;
|
|
950
|
+
let contentType;
|
|
951
|
+
if (isBinary) {
|
|
952
|
+
const binaryProperty = this.getNodeParameter('binaryProperty', i);
|
|
953
|
+
this.helpers.assertBinaryData(i, binaryProperty);
|
|
954
|
+
body = await this.helpers.getBinaryDataBuffer(i, binaryProperty);
|
|
955
|
+
contentType = 'application/octet-stream';
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
body = this.getNodeParameter('fileContent', i, '');
|
|
959
|
+
contentType = 'text/plain; charset=utf-8';
|
|
960
|
+
}
|
|
961
|
+
const credentials = await this.getCredentials('openCloudApi');
|
|
962
|
+
const filePath = '/' + [...splitPath(parentPath), name].join('/');
|
|
963
|
+
const url = spaceWebDavUrl(credentials.serverUrl, driveId, filePath);
|
|
964
|
+
await GenericFunctions_1.openCloudApiRequest.call(this, 'PUT', url, body, { 'Content-Type': contentType }, false);
|
|
965
|
+
const uploadedItem = await resolvePathToItem(this, driveId, filePath, i);
|
|
966
|
+
returnData.push({
|
|
967
|
+
json: uploadedItem,
|
|
968
|
+
pairedItem: { item: i },
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
else if (resource === 'file' && operation === 'download') {
|
|
972
|
+
const driveId = this.getNodeParameter('space', i);
|
|
973
|
+
const rawPath = this.getNodeParameter('path', i);
|
|
974
|
+
const outputProp = this.getNodeParameter('binaryProperty', i);
|
|
975
|
+
if (!rawPath.trim()) {
|
|
976
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Path is required for download', {
|
|
977
|
+
itemIndex: i,
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
const credentials = await this.getCredentials('openCloudApi');
|
|
981
|
+
const url = spaceWebDavUrl(credentials.serverUrl, driveId, rawPath);
|
|
982
|
+
const data = (await GenericFunctions_1.openCloudApiRequest.call(this, 'GET', url, '', {}, false, 'arraybuffer'));
|
|
983
|
+
const fileName = lastSegment(rawPath);
|
|
984
|
+
const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
985
|
+
returnData.push({
|
|
986
|
+
json: items[i].json,
|
|
987
|
+
binary: {
|
|
988
|
+
[outputProp]: await this.helpers.prepareBinaryData(buffer, fileName),
|
|
989
|
+
},
|
|
990
|
+
pairedItem: { item: i },
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
else if ((operation === 'copy' || operation === 'move') &&
|
|
994
|
+
(resource === 'folder' || resource === 'file')) {
|
|
995
|
+
const driveId = this.getNodeParameter('space', i);
|
|
996
|
+
const srcPath = this.getNodeParameter('path', i);
|
|
997
|
+
const destDriveIdRaw = this.getNodeParameter('destSpace', i, '');
|
|
998
|
+
const destDriveId = destDriveIdRaw || driveId;
|
|
999
|
+
const destParentPath = this.getNodeParameter('destParentPath', i);
|
|
1000
|
+
const destNameRaw = this.getNodeParameter('destName', i, '').trim();
|
|
1001
|
+
if (!srcPath.trim()) {
|
|
1002
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Source path is required', {
|
|
1003
|
+
itemIndex: i,
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
const destName = destNameRaw || lastSegment(srcPath);
|
|
1007
|
+
if (!destName) {
|
|
1008
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Destination name could not be derived from source — set "New Name"', { itemIndex: i });
|
|
1009
|
+
}
|
|
1010
|
+
const credentials = await this.getCredentials('openCloudApi');
|
|
1011
|
+
const srcUrl = spaceWebDavUrl(credentials.serverUrl, driveId, srcPath);
|
|
1012
|
+
const destFullPath = '/' + [...splitPath(destParentPath), destName].join('/');
|
|
1013
|
+
const destUrl = spaceWebDavUrl(credentials.serverUrl, destDriveId, destFullPath);
|
|
1014
|
+
const httpMethod = (operation === 'copy' ? 'COPY' : 'MOVE');
|
|
1015
|
+
try {
|
|
1016
|
+
await GenericFunctions_1.openCloudApiRequest.call(this, httpMethod, srcUrl, '', { Destination: destUrl }, false);
|
|
1017
|
+
}
|
|
1018
|
+
catch (error) {
|
|
1019
|
+
const httpCode = String((_g = (_f = error.httpCode) !== null && _f !== void 0 ? _f : error.statusCode) !== null && _g !== void 0 ? _g : '');
|
|
1020
|
+
if (operation === 'move' && httpCode === '502') {
|
|
1021
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Cross-storage move not supported', {
|
|
1022
|
+
description: 'OpenCloud cannot move items between different storage providers. Use Copy followed by Delete instead.',
|
|
1023
|
+
itemIndex: i,
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, { itemIndex: i });
|
|
1027
|
+
}
|
|
1028
|
+
const destinationItem = await resolvePathToItem(this, destDriveId, destFullPath, i);
|
|
1029
|
+
returnData.push({
|
|
1030
|
+
json: destinationItem,
|
|
1031
|
+
pairedItem: { item: i },
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
else if (operation === 'share' &&
|
|
1035
|
+
(resource === 'folder' || resource === 'file' || resource === 'space')) {
|
|
1036
|
+
const driveId = this.getNodeParameter('space', i);
|
|
1037
|
+
const recipientType = this.getNodeParameter('recipientType', i, 'publicLink');
|
|
1038
|
+
const expirationDateTime = this.getNodeParameter('expirationDateTime', i, '').trim();
|
|
1039
|
+
let endpointBase;
|
|
1040
|
+
if (resource === 'space') {
|
|
1041
|
+
endpointBase = `/graph/v1beta1/drives/${encodeURIComponent(driveId)}/root`;
|
|
1042
|
+
}
|
|
1043
|
+
else {
|
|
1044
|
+
const rawPath = this.getNodeParameter('path', i);
|
|
1045
|
+
if (!rawPath.trim()) {
|
|
1046
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Path is required for share', {
|
|
1047
|
+
itemIndex: i,
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
const itemId = await resolvePathToItemId(this, driveId, rawPath, i);
|
|
1051
|
+
endpointBase = `/graph/v1beta1/drives/${encodeURIComponent(driveId)}/items/${encodeURIComponent(itemId)}`;
|
|
1052
|
+
}
|
|
1053
|
+
if (recipientType === 'publicLink') {
|
|
1054
|
+
const linkType = this.getNodeParameter('linkType', i);
|
|
1055
|
+
const password = this.getNodeParameter('password', i, '').trim();
|
|
1056
|
+
const body = { type: linkType };
|
|
1057
|
+
if (password)
|
|
1058
|
+
body.password = password;
|
|
1059
|
+
if (expirationDateTime)
|
|
1060
|
+
body.expirationDateTime = expirationDateTime;
|
|
1061
|
+
try {
|
|
1062
|
+
const response = (await GenericFunctions_1.openCloudApiRequest.call(this, 'POST', `${endpointBase}/createLink`, body, { 'Content-Type': 'application/json' }, true));
|
|
1063
|
+
returnData.push({
|
|
1064
|
+
json: response,
|
|
1065
|
+
pairedItem: { item: i },
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
1068
|
+
catch (error) {
|
|
1069
|
+
const code = String((_l = (_j = (_h = error.httpCode) !== null && _h !== void 0 ? _h : error.statusCode) !== null && _j !== void 0 ? _j : (_k = error.cause) === null || _k === void 0 ? void 0 : _k.statusCode) !== null && _l !== void 0 ? _l : '');
|
|
1070
|
+
if (code === '400') {
|
|
1071
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Public link rejected: password requirement not met', {
|
|
1072
|
+
description: 'The server may require a password for this link type and may enforce a password policy (min length, character classes, etc). See the `password_policy` and `files_sharing.public.password` capabilities for the exact rules.',
|
|
1073
|
+
itemIndex: i,
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, { itemIndex: i });
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
else {
|
|
1080
|
+
const recipientId = this.getNodeParameter('recipientId', i, '', {
|
|
1081
|
+
extractValue: true,
|
|
1082
|
+
}).trim();
|
|
1083
|
+
const role = this.getNodeParameter('role', i).trim();
|
|
1084
|
+
if (!recipientId) {
|
|
1085
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Recipient ID is required for invite', { itemIndex: i });
|
|
1086
|
+
}
|
|
1087
|
+
if (!role) {
|
|
1088
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Role is required for invite', {
|
|
1089
|
+
itemIndex: i,
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
const body = {
|
|
1093
|
+
recipients: [
|
|
1094
|
+
{
|
|
1095
|
+
objectId: recipientId,
|
|
1096
|
+
'@libre.graph.recipient.type': recipientType,
|
|
1097
|
+
},
|
|
1098
|
+
],
|
|
1099
|
+
roles: [role],
|
|
1100
|
+
};
|
|
1101
|
+
if (expirationDateTime)
|
|
1102
|
+
body.expirationDateTime = expirationDateTime;
|
|
1103
|
+
const response = (await GenericFunctions_1.openCloudApiRequest.call(this, 'POST', `${endpointBase}/invite`, body, { 'Content-Type': 'application/json' }, true));
|
|
1104
|
+
for (const permission of (_m = response.value) !== null && _m !== void 0 ? _m : []) {
|
|
1105
|
+
returnData.push({
|
|
1106
|
+
json: permission,
|
|
1107
|
+
pairedItem: { item: i },
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
else if (operation === 'delete' && (resource === 'folder' || resource === 'file')) {
|
|
1113
|
+
const driveId = this.getNodeParameter('space', i);
|
|
1114
|
+
const rawPath = this.getNodeParameter('path', i);
|
|
1115
|
+
if (!rawPath.trim()) {
|
|
1116
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Path is required for delete', {
|
|
1117
|
+
itemIndex: i,
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
const credentials = await this.getCredentials('openCloudApi');
|
|
1121
|
+
const url = spaceWebDavUrl(credentials.serverUrl, driveId, rawPath);
|
|
1122
|
+
await GenericFunctions_1.openCloudApiRequest.call(this, 'DELETE', url, '', {}, false);
|
|
1123
|
+
returnData.push({
|
|
1124
|
+
json: {},
|
|
1125
|
+
pairedItem: { item: i },
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
catch (error) {
|
|
1130
|
+
if (this.continueOnFail()) {
|
|
1131
|
+
const e = error;
|
|
1132
|
+
returnData.push({
|
|
1133
|
+
json: {
|
|
1134
|
+
error: e.message,
|
|
1135
|
+
...(e.description ? { errorDescription: e.description } : {}),
|
|
1136
|
+
},
|
|
1137
|
+
pairedItem: { item: i },
|
|
1138
|
+
});
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
if (error instanceof n8n_workflow_1.NodeApiError || error instanceof n8n_workflow_1.NodeOperationError) {
|
|
1142
|
+
throw error;
|
|
1143
|
+
}
|
|
1144
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, { itemIndex: i });
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
return [returnData];
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
exports.OpenCloud = OpenCloud;
|
|
1151
|
+
//# sourceMappingURL=OpenCloud.node.js.map
|