n8n-nodes-onedrive-business-sp 1.0.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/README.md +272 -0
- package/dist/credentials/MicrosoftOneDriveBusinessOAuth2Api.credentials.d.ts +10 -0
- package/dist/credentials/MicrosoftOneDriveBusinessOAuth2Api.credentials.js +64 -0
- package/dist/nodes/MicrosoftOneDriveBusiness/MicrosoftOneDriveBusiness.node.d.ts +5 -0
- package/dist/nodes/MicrosoftOneDriveBusiness/MicrosoftOneDriveBusiness.node.js +583 -0
- package/dist/nodes/MicrosoftOneDriveBusiness/MicrosoftOneDriveBusinessTrigger.node.d.ts +12 -0
- package/dist/nodes/MicrosoftOneDriveBusiness/MicrosoftOneDriveBusinessTrigger.node.js +273 -0
- package/dist/nodes/MicrosoftOneDriveBusiness/onedrive.svg +6 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Microsoft OneDrive (Business) Node for n8n
|
|
2
|
+
|
|
3
|
+
This is a complete implementation of a Microsoft OneDrive for Business node for n8n, built on SharePoint Document Library with Microsoft Graph API.
|
|
4
|
+
|
|
5
|
+
## 🚀 Features
|
|
6
|
+
|
|
7
|
+
### Resources & Operations
|
|
8
|
+
|
|
9
|
+
#### File Operations
|
|
10
|
+
- ✅ **Delete** - Remove files from OneDrive
|
|
11
|
+
- ✅ **Download** - Download file content as binary data
|
|
12
|
+
- ✅ **Get** - Retrieve file metadata
|
|
13
|
+
- ✅ **Rename** - Change file names
|
|
14
|
+
- ✅ **Search** - Find files by query
|
|
15
|
+
- ✅ **Share** - Create sharing links with configurable permissions
|
|
16
|
+
- ✅ **Upload** - Upload files from binary data
|
|
17
|
+
|
|
18
|
+
#### Folder Operations
|
|
19
|
+
- ✅ **Create** - Create new folders
|
|
20
|
+
- ✅ **Delete** - Remove folders
|
|
21
|
+
- ✅ **Get Items** - List contents of a folder
|
|
22
|
+
- ✅ **Rename** - Change folder names
|
|
23
|
+
- ✅ **Search** - Find folders by query
|
|
24
|
+
- ✅ **Share** - Create sharing links with configurable permissions
|
|
25
|
+
|
|
26
|
+
### Triggers (Webhook-based)
|
|
27
|
+
- ⚡ **On File Created** - Triggers when a new file is created
|
|
28
|
+
- ⚡ **On File Updated** - Triggers when a file is modified
|
|
29
|
+
- ⚡ **On Folder Created** - Triggers when a new folder is created
|
|
30
|
+
- ⚡ **On Folder Updated** - Triggers when a folder is modified
|
|
31
|
+
|
|
32
|
+
## 📋 Prerequisites
|
|
33
|
+
|
|
34
|
+
### Microsoft Azure App Registration
|
|
35
|
+
|
|
36
|
+
1. Go to [Azure Portal](https://portal.azure.com/)
|
|
37
|
+
2. Navigate to **Azure Active Directory** > **App registrations** > **New registration**
|
|
38
|
+
3. Configure:
|
|
39
|
+
- Name: `n8n OneDrive Business Integration`
|
|
40
|
+
- Supported account types: **Accounts in any organizational directory**
|
|
41
|
+
- Redirect URI: `https://your-n8n-instance.com/rest/oauth2-credential/callback`
|
|
42
|
+
|
|
43
|
+
4. After creation, note down:
|
|
44
|
+
- **Application (client) ID**
|
|
45
|
+
- **Directory (tenant) ID**
|
|
46
|
+
|
|
47
|
+
5. Go to **Certificates & secrets** > **New client secret**
|
|
48
|
+
- Note down the **Client secret value** (shown only once!)
|
|
49
|
+
|
|
50
|
+
6. Go to **API permissions** > **Add a permission** > **Microsoft Graph** > **Delegated permissions**
|
|
51
|
+
- Add these permissions:
|
|
52
|
+
- `Files.ReadWrite.All`
|
|
53
|
+
- `Sites.Read.All`
|
|
54
|
+
- `Sites.ReadWrite.All`
|
|
55
|
+
- `offline_access`
|
|
56
|
+
- Click **Grant admin consent**
|
|
57
|
+
|
|
58
|
+
## 🔧 Installation
|
|
59
|
+
|
|
60
|
+
### For n8n Community Nodes
|
|
61
|
+
|
|
62
|
+
1. **Copy Files to n8n Custom Nodes Directory:**
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Navigate to your n8n installation
|
|
66
|
+
cd ~/.n8n/custom
|
|
67
|
+
|
|
68
|
+
# Create directory structure
|
|
69
|
+
mkdir -p nodes/MicrosoftOneDriveBusiness
|
|
70
|
+
mkdir -p credentials
|
|
71
|
+
|
|
72
|
+
# Copy credential file
|
|
73
|
+
cp credentials/MicrosoftOneDriveBusinessOAuth2Api.credentials.ts ~/.n8n/custom/credentials/
|
|
74
|
+
|
|
75
|
+
# Copy node files
|
|
76
|
+
cp nodes/MicrosoftOneDriveBusiness/* ~/.n8n/custom/nodes/MicrosoftOneDriveBusiness/
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
2. **Install as Community Node (Alternative):**
|
|
80
|
+
|
|
81
|
+
If published as an npm package:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# In n8n UI: Settings > Community Nodes > Install
|
|
85
|
+
# Package name: n8n-nodes-microsoft-onedrive-business
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### For Development
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Clone repository
|
|
92
|
+
git clone <repository-url>
|
|
93
|
+
cd n8n-onedrive-business
|
|
94
|
+
|
|
95
|
+
# Install dependencies
|
|
96
|
+
npm install
|
|
97
|
+
|
|
98
|
+
# Link to n8n
|
|
99
|
+
npm link
|
|
100
|
+
|
|
101
|
+
# In your n8n directory
|
|
102
|
+
npm link n8n-nodes-microsoft-onedrive-business
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## ⚙️ Configuration
|
|
106
|
+
|
|
107
|
+
### 1. Add Credentials in n8n
|
|
108
|
+
|
|
109
|
+
1. Go to **Credentials** > **New** > **Microsoft OneDrive (Business) OAuth2 API**
|
|
110
|
+
2. Enter:
|
|
111
|
+
- **Client ID**: Your Azure App's Application (client) ID
|
|
112
|
+
- **Client Secret**: Your Azure App's client secret
|
|
113
|
+
3. Click **Connect my account** and authorize
|
|
114
|
+
|
|
115
|
+
### 2. Get Site ID and Drive ID
|
|
116
|
+
|
|
117
|
+
To use the node, you need your SharePoint site ID:
|
|
118
|
+
|
|
119
|
+
**Get Site ID:**
|
|
120
|
+
```bash
|
|
121
|
+
GET https://graph.microsoft.com/v1.0/sites/{hostname}:/{site-path}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Example:
|
|
125
|
+
```bash
|
|
126
|
+
GET https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/TeamSite
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Get Drive ID** (optional - will auto-fetch if not provided):
|
|
130
|
+
```bash
|
|
131
|
+
GET https://graph.microsoft.com/v1.0/sites/{site-id}/drive
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## 📖 Usage Examples
|
|
135
|
+
|
|
136
|
+
### Example 1: Upload a File
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
{
|
|
140
|
+
"nodes": [
|
|
141
|
+
{
|
|
142
|
+
"parameters": {
|
|
143
|
+
"resource": "file",
|
|
144
|
+
"operation": "upload",
|
|
145
|
+
"siteId": "contoso.sharepoint.com,abc123,def456",
|
|
146
|
+
"parentFolderId": "root",
|
|
147
|
+
"fileName": "report.pdf",
|
|
148
|
+
"binaryPropertyName": "data"
|
|
149
|
+
},
|
|
150
|
+
"name": "Upload to OneDrive",
|
|
151
|
+
"type": "n8n-nodes-microsoftOneDriveBusiness.microsoftOneDriveBusiness",
|
|
152
|
+
"credentials": {
|
|
153
|
+
"microsoftOneDriveBusinessOAuth2Api": "OneDrive Business Credentials"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Example 2: Search and Download Files
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
{
|
|
164
|
+
"nodes": [
|
|
165
|
+
{
|
|
166
|
+
"parameters": {
|
|
167
|
+
"resource": "file",
|
|
168
|
+
"operation": "search",
|
|
169
|
+
"siteId": "contoso.sharepoint.com,abc123,def456",
|
|
170
|
+
"query": "quarterly report"
|
|
171
|
+
},
|
|
172
|
+
"name": "Search Files"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"parameters": {
|
|
176
|
+
"resource": "file",
|
|
177
|
+
"operation": "download",
|
|
178
|
+
"fileId": "={{ $json.id }}",
|
|
179
|
+
"binaryProperty": "data"
|
|
180
|
+
},
|
|
181
|
+
"name": "Download File"
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Example 3: Trigger on New Files
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
{
|
|
191
|
+
"nodes": [
|
|
192
|
+
{
|
|
193
|
+
"parameters": {
|
|
194
|
+
"siteId": "contoso.sharepoint.com,abc123,def456",
|
|
195
|
+
"event": "fileCreated",
|
|
196
|
+
"watchFolderId": "root"
|
|
197
|
+
},
|
|
198
|
+
"name": "OneDrive Trigger",
|
|
199
|
+
"type": "n8n-nodes-microsoftOneDriveBusiness.microsoftOneDriveBusinessTrigger"
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## 🔑 Key Differences from OneDrive Personal
|
|
206
|
+
|
|
207
|
+
| Feature | OneDrive Personal | OneDrive Business |
|
|
208
|
+
|---------|-------------------|-------------------|
|
|
209
|
+
| Backend | Consumer OneDrive | SharePoint |
|
|
210
|
+
| Drive Type | `personal` | `business` |
|
|
211
|
+
| API Base | `/me/drive` | `/sites/{id}/drive` |
|
|
212
|
+
| Authentication | Personal Microsoft Account | Azure AD (Work/School) |
|
|
213
|
+
| Organization Features | ❌ | ✅ (Sharing policies, DLP, etc.) |
|
|
214
|
+
|
|
215
|
+
## 🛠️ API Endpoints Used
|
|
216
|
+
|
|
217
|
+
- `GET /sites/{site-id}/drive` - Get drive information
|
|
218
|
+
- `PUT /drives/{drive-id}/items/{parent-id}:/{filename}:/content` - Upload file
|
|
219
|
+
- `GET /drives/{drive-id}/items/{item-id}/content` - Download file
|
|
220
|
+
- `GET /drives/{drive-id}/items/{item-id}` - Get metadata
|
|
221
|
+
- `DELETE /drives/{drive-id}/items/{item-id}` - Delete item
|
|
222
|
+
- `PATCH /drives/{drive-id}/items/{item-id}` - Update item
|
|
223
|
+
- `GET /drives/{drive-id}/root/search(q='{query}')` - Search
|
|
224
|
+
- `POST /drives/{drive-id}/items/{item-id}/createLink` - Create sharing link
|
|
225
|
+
- `POST /subscriptions` - Create webhook subscription (triggers)
|
|
226
|
+
- `GET /drives/{drive-id}/root/delta` - Get delta changes (triggers)
|
|
227
|
+
|
|
228
|
+
## 🐛 Troubleshooting
|
|
229
|
+
|
|
230
|
+
### "Drive not found" error
|
|
231
|
+
- Verify your Site ID is correct
|
|
232
|
+
- Ensure user has access to the SharePoint site
|
|
233
|
+
- Check that the drive exists for the site
|
|
234
|
+
|
|
235
|
+
### "Insufficient privileges" error
|
|
236
|
+
- Verify all required Graph API permissions are granted
|
|
237
|
+
- Ensure admin consent is given for tenant-wide permissions
|
|
238
|
+
- Check that the user has appropriate SharePoint permissions
|
|
239
|
+
|
|
240
|
+
### Webhook/Trigger not working
|
|
241
|
+
- Ensure your n8n instance is publicly accessible
|
|
242
|
+
- Verify the webhook URL is correct
|
|
243
|
+
- Check that subscriptions are being created (they expire after 72 hours)
|
|
244
|
+
- Microsoft Graph webhook delivery can have delays
|
|
245
|
+
|
|
246
|
+
### File upload fails
|
|
247
|
+
- Check file size (large files >4MB need resumable upload session)
|
|
248
|
+
- Verify binary data property name is correct
|
|
249
|
+
- Ensure mime type is set correctly
|
|
250
|
+
|
|
251
|
+
## 📚 Resources
|
|
252
|
+
|
|
253
|
+
- [Microsoft Graph API Documentation](https://docs.microsoft.com/en-us/graph/api/resources/onedrive)
|
|
254
|
+
- [SharePoint API Documentation](https://docs.microsoft.com/en-us/graph/api/resources/sharepoint)
|
|
255
|
+
- [n8n Node Development](https://docs.n8n.io/integrations/creating-nodes/)
|
|
256
|
+
- [Azure App Registration](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app)
|
|
257
|
+
|
|
258
|
+
## 📄 License
|
|
259
|
+
|
|
260
|
+
MIT License - Feel free to use and modify as needed.
|
|
261
|
+
|
|
262
|
+
## 🤝 Contributing
|
|
263
|
+
|
|
264
|
+
Contributions are welcome! Please:
|
|
265
|
+
1. Fork the repository
|
|
266
|
+
2. Create a feature branch
|
|
267
|
+
3. Submit a pull request
|
|
268
|
+
|
|
269
|
+
## ✨ Credits
|
|
270
|
+
|
|
271
|
+
Built for n8n following official node development guidelines.
|
|
272
|
+
Implements OneDrive for Business (SharePoint) only - does not support OneDrive Personal.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class MicrosoftOneDriveBusinessOAuth2Api implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
extends: string[];
|
|
5
|
+
displayName: string;
|
|
6
|
+
documentationUrl: string;
|
|
7
|
+
properties: INodeProperties[];
|
|
8
|
+
authenticate: IAuthenticateGeneric;
|
|
9
|
+
test: ICredentialTestRequest;
|
|
10
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MicrosoftOneDriveBusinessOAuth2Api = void 0;
|
|
4
|
+
class MicrosoftOneDriveBusinessOAuth2Api {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'microsoftOneDriveBusinessOAuth2Api';
|
|
7
|
+
this.extends = ['oAuth2Api'];
|
|
8
|
+
this.displayName = 'Microsoft OneDrive (Business) OAuth2 API';
|
|
9
|
+
this.documentationUrl = 'microsoft';
|
|
10
|
+
this.properties = [
|
|
11
|
+
{
|
|
12
|
+
displayName: 'Grant Type',
|
|
13
|
+
name: 'grantType',
|
|
14
|
+
type: 'hidden',
|
|
15
|
+
default: 'authorizationCode',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
displayName: 'Authorization URL',
|
|
19
|
+
name: 'authUrl',
|
|
20
|
+
type: 'hidden',
|
|
21
|
+
default: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
displayName: 'Access Token URL',
|
|
25
|
+
name: 'accessTokenUrl',
|
|
26
|
+
type: 'hidden',
|
|
27
|
+
default: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
displayName: 'Scope',
|
|
31
|
+
name: 'scope',
|
|
32
|
+
type: 'hidden',
|
|
33
|
+
default: 'Files.ReadWrite.All Sites.Read.All Sites.ReadWrite.All offline_access',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
displayName: 'Auth URI Query Parameters',
|
|
37
|
+
name: 'authQueryParameters',
|
|
38
|
+
type: 'hidden',
|
|
39
|
+
default: 'response_mode=query',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
displayName: 'Authentication',
|
|
43
|
+
name: 'authentication',
|
|
44
|
+
type: 'hidden',
|
|
45
|
+
default: 'body',
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
this.authenticate = {
|
|
49
|
+
type: 'generic',
|
|
50
|
+
properties: {
|
|
51
|
+
headers: {
|
|
52
|
+
Authorization: '={{"Bearer " + $credentials.oauthTokenData.access_token}}',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
this.test = {
|
|
57
|
+
request: {
|
|
58
|
+
baseURL: 'https://graph.microsoft.com/v1.0',
|
|
59
|
+
url: '/me',
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.MicrosoftOneDriveBusinessOAuth2Api = MicrosoftOneDriveBusinessOAuth2Api;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class MicrosoftOneDriveBusiness implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MicrosoftOneDriveBusiness = void 0;
|
|
4
|
+
class MicrosoftOneDriveBusiness {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.description = {
|
|
7
|
+
displayName: 'Microsoft OneDrive (Business)',
|
|
8
|
+
name: 'microsoftOneDriveBusiness',
|
|
9
|
+
icon: 'file:onedrive.svg',
|
|
10
|
+
group: ['input', 'output'],
|
|
11
|
+
version: 1,
|
|
12
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
13
|
+
description: 'Work with OneDrive for Business (SharePoint)',
|
|
14
|
+
defaults: {
|
|
15
|
+
name: 'Microsoft OneDrive (Business)',
|
|
16
|
+
},
|
|
17
|
+
inputs: ['main'],
|
|
18
|
+
outputs: ['main'],
|
|
19
|
+
credentials: [
|
|
20
|
+
{
|
|
21
|
+
name: 'microsoftOneDriveBusinessOAuth2Api',
|
|
22
|
+
required: true,
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
properties: [
|
|
26
|
+
{
|
|
27
|
+
displayName: 'Resource',
|
|
28
|
+
name: 'resource',
|
|
29
|
+
type: 'options',
|
|
30
|
+
noDataExpression: true,
|
|
31
|
+
options: [
|
|
32
|
+
{
|
|
33
|
+
name: 'File',
|
|
34
|
+
value: 'file',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'Folder',
|
|
38
|
+
value: 'folder',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
default: 'file',
|
|
42
|
+
},
|
|
43
|
+
// File Operations
|
|
44
|
+
{
|
|
45
|
+
displayName: 'Operation',
|
|
46
|
+
name: 'operation',
|
|
47
|
+
type: 'options',
|
|
48
|
+
noDataExpression: true,
|
|
49
|
+
displayOptions: {
|
|
50
|
+
show: {
|
|
51
|
+
resource: ['file'],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
options: [
|
|
55
|
+
{
|
|
56
|
+
name: 'Delete',
|
|
57
|
+
value: 'delete',
|
|
58
|
+
description: 'Delete a file',
|
|
59
|
+
action: 'Delete a file',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'Download',
|
|
63
|
+
value: 'download',
|
|
64
|
+
description: 'Download a file',
|
|
65
|
+
action: 'Download a file',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'Get',
|
|
69
|
+
value: 'get',
|
|
70
|
+
description: 'Get file metadata',
|
|
71
|
+
action: 'Get a file',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'Rename',
|
|
75
|
+
value: 'rename',
|
|
76
|
+
description: 'Rename a file',
|
|
77
|
+
action: 'Rename a file',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'Search',
|
|
81
|
+
value: 'search',
|
|
82
|
+
description: 'Search for files',
|
|
83
|
+
action: 'Search files',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'Share',
|
|
87
|
+
value: 'share',
|
|
88
|
+
description: 'Share a file',
|
|
89
|
+
action: 'Share a file',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'Upload',
|
|
93
|
+
value: 'upload',
|
|
94
|
+
description: 'Upload a file',
|
|
95
|
+
action: 'Upload a file',
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
default: 'upload',
|
|
99
|
+
},
|
|
100
|
+
// Folder Operations
|
|
101
|
+
{
|
|
102
|
+
displayName: 'Operation',
|
|
103
|
+
name: 'operation',
|
|
104
|
+
type: 'options',
|
|
105
|
+
noDataExpression: true,
|
|
106
|
+
displayOptions: {
|
|
107
|
+
show: {
|
|
108
|
+
resource: ['folder'],
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
options: [
|
|
112
|
+
{
|
|
113
|
+
name: 'Create',
|
|
114
|
+
value: 'create',
|
|
115
|
+
description: 'Create a folder',
|
|
116
|
+
action: 'Create a folder',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: 'Delete',
|
|
120
|
+
value: 'delete',
|
|
121
|
+
description: 'Delete a folder',
|
|
122
|
+
action: 'Delete a folder',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'Get Items',
|
|
126
|
+
value: 'getItems',
|
|
127
|
+
description: 'Get items in a folder',
|
|
128
|
+
action: 'Get items in a folder',
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: 'Rename',
|
|
132
|
+
value: 'rename',
|
|
133
|
+
description: 'Rename a folder',
|
|
134
|
+
action: 'Rename a folder',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'Search',
|
|
138
|
+
value: 'search',
|
|
139
|
+
description: 'Search for folders',
|
|
140
|
+
action: 'Search folders',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'Share',
|
|
144
|
+
value: 'share',
|
|
145
|
+
description: 'Share a folder',
|
|
146
|
+
action: 'Share a folder',
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
default: 'create',
|
|
150
|
+
},
|
|
151
|
+
// Common Fields
|
|
152
|
+
{
|
|
153
|
+
displayName: 'Site ID',
|
|
154
|
+
name: 'siteId',
|
|
155
|
+
type: 'string',
|
|
156
|
+
default: '',
|
|
157
|
+
required: true,
|
|
158
|
+
description: 'The SharePoint site ID',
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
displayName: 'Drive ID',
|
|
162
|
+
name: 'driveId',
|
|
163
|
+
type: 'string',
|
|
164
|
+
default: '',
|
|
165
|
+
description: 'The drive ID. If not specified, the default drive for the site will be used.',
|
|
166
|
+
},
|
|
167
|
+
// File: Delete
|
|
168
|
+
{
|
|
169
|
+
displayName: 'File ID',
|
|
170
|
+
name: 'fileId',
|
|
171
|
+
type: 'string',
|
|
172
|
+
displayOptions: {
|
|
173
|
+
show: {
|
|
174
|
+
resource: ['file'],
|
|
175
|
+
operation: ['delete', 'get', 'download', 'rename', 'share'],
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
default: '',
|
|
179
|
+
required: true,
|
|
180
|
+
description: 'The ID of the file',
|
|
181
|
+
},
|
|
182
|
+
// File: Upload
|
|
183
|
+
{
|
|
184
|
+
displayName: 'Parent Folder ID',
|
|
185
|
+
name: 'parentFolderId',
|
|
186
|
+
type: 'string',
|
|
187
|
+
displayOptions: {
|
|
188
|
+
show: {
|
|
189
|
+
resource: ['file'],
|
|
190
|
+
operation: ['upload'],
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
default: 'root',
|
|
194
|
+
description: 'The ID of the parent folder. Use "root" for the root folder.',
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
displayName: 'File Name',
|
|
198
|
+
name: 'fileName',
|
|
199
|
+
type: 'string',
|
|
200
|
+
displayOptions: {
|
|
201
|
+
show: {
|
|
202
|
+
resource: ['file'],
|
|
203
|
+
operation: ['upload'],
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
default: '',
|
|
207
|
+
required: true,
|
|
208
|
+
description: 'The name of the file to upload',
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
displayName: 'Binary Property',
|
|
212
|
+
name: 'binaryPropertyName',
|
|
213
|
+
type: 'string',
|
|
214
|
+
displayOptions: {
|
|
215
|
+
show: {
|
|
216
|
+
resource: ['file'],
|
|
217
|
+
operation: ['upload'],
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
default: 'data',
|
|
221
|
+
required: true,
|
|
222
|
+
description: 'Name of the binary property containing the file data',
|
|
223
|
+
},
|
|
224
|
+
// File: Rename
|
|
225
|
+
{
|
|
226
|
+
displayName: 'New Name',
|
|
227
|
+
name: 'newName',
|
|
228
|
+
type: 'string',
|
|
229
|
+
displayOptions: {
|
|
230
|
+
show: {
|
|
231
|
+
resource: ['file', 'folder'],
|
|
232
|
+
operation: ['rename'],
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
default: '',
|
|
236
|
+
required: true,
|
|
237
|
+
description: 'The new name for the file or folder',
|
|
238
|
+
},
|
|
239
|
+
// File: Search
|
|
240
|
+
{
|
|
241
|
+
displayName: 'Query',
|
|
242
|
+
name: 'query',
|
|
243
|
+
type: 'string',
|
|
244
|
+
displayOptions: {
|
|
245
|
+
show: {
|
|
246
|
+
resource: ['file', 'folder'],
|
|
247
|
+
operation: ['search'],
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
default: '',
|
|
251
|
+
required: true,
|
|
252
|
+
description: 'The search query',
|
|
253
|
+
},
|
|
254
|
+
// File: Share
|
|
255
|
+
{
|
|
256
|
+
displayName: 'Link Type',
|
|
257
|
+
name: 'linkType',
|
|
258
|
+
type: 'options',
|
|
259
|
+
displayOptions: {
|
|
260
|
+
show: {
|
|
261
|
+
resource: ['file', 'folder'],
|
|
262
|
+
operation: ['share'],
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
options: [
|
|
266
|
+
{
|
|
267
|
+
name: 'View',
|
|
268
|
+
value: 'view',
|
|
269
|
+
description: 'View only',
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: 'Edit',
|
|
273
|
+
value: 'edit',
|
|
274
|
+
description: 'Edit access',
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: 'Embed',
|
|
278
|
+
value: 'embed',
|
|
279
|
+
description: 'Embed link',
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
default: 'view',
|
|
283
|
+
description: 'The type of sharing link to create',
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
displayName: 'Link Scope',
|
|
287
|
+
name: 'linkScope',
|
|
288
|
+
type: 'options',
|
|
289
|
+
displayOptions: {
|
|
290
|
+
show: {
|
|
291
|
+
resource: ['file', 'folder'],
|
|
292
|
+
operation: ['share'],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
options: [
|
|
296
|
+
{
|
|
297
|
+
name: 'Anonymous',
|
|
298
|
+
value: 'anonymous',
|
|
299
|
+
description: 'Anyone with the link',
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
name: 'Organization',
|
|
303
|
+
value: 'organization',
|
|
304
|
+
description: 'People in your organization',
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
default: 'organization',
|
|
308
|
+
description: 'The scope of the sharing link',
|
|
309
|
+
},
|
|
310
|
+
// Folder: Create
|
|
311
|
+
{
|
|
312
|
+
displayName: 'Folder Name',
|
|
313
|
+
name: 'folderName',
|
|
314
|
+
type: 'string',
|
|
315
|
+
displayOptions: {
|
|
316
|
+
show: {
|
|
317
|
+
resource: ['folder'],
|
|
318
|
+
operation: ['create'],
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
default: '',
|
|
322
|
+
required: true,
|
|
323
|
+
description: 'The name of the folder to create',
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
displayName: 'Parent Folder ID',
|
|
327
|
+
name: 'parentFolderId',
|
|
328
|
+
type: 'string',
|
|
329
|
+
displayOptions: {
|
|
330
|
+
show: {
|
|
331
|
+
resource: ['folder'],
|
|
332
|
+
operation: ['create', 'getItems'],
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
default: 'root',
|
|
336
|
+
description: 'The ID of the parent folder. Use "root" for the root folder.',
|
|
337
|
+
},
|
|
338
|
+
// Folder: Delete, Rename, Share
|
|
339
|
+
{
|
|
340
|
+
displayName: 'Folder ID',
|
|
341
|
+
name: 'folderId',
|
|
342
|
+
type: 'string',
|
|
343
|
+
displayOptions: {
|
|
344
|
+
show: {
|
|
345
|
+
resource: ['folder'],
|
|
346
|
+
operation: ['delete', 'rename', 'share'],
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
default: '',
|
|
350
|
+
required: true,
|
|
351
|
+
description: 'The ID of the folder',
|
|
352
|
+
},
|
|
353
|
+
// Download Options
|
|
354
|
+
{
|
|
355
|
+
displayName: 'Put Output in Field',
|
|
356
|
+
name: 'binaryProperty',
|
|
357
|
+
type: 'string',
|
|
358
|
+
displayOptions: {
|
|
359
|
+
show: {
|
|
360
|
+
resource: ['file'],
|
|
361
|
+
operation: ['download'],
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
default: 'data',
|
|
365
|
+
required: true,
|
|
366
|
+
description: 'The name of the output binary field to put the file in',
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
async execute() {
|
|
372
|
+
const items = this.getInputData();
|
|
373
|
+
const returnData = [];
|
|
374
|
+
const resource = this.getNodeParameter('resource', 0);
|
|
375
|
+
const operation = this.getNodeParameter('operation', 0);
|
|
376
|
+
let responseData = {};
|
|
377
|
+
for (let i = 0; i < items.length; i++) {
|
|
378
|
+
try {
|
|
379
|
+
const siteId = this.getNodeParameter('siteId', i);
|
|
380
|
+
const driveId = this.getNodeParameter('driveId', i, '');
|
|
381
|
+
// Get drive ID if not provided
|
|
382
|
+
let actualDriveId = driveId;
|
|
383
|
+
if (!actualDriveId) {
|
|
384
|
+
const driveResponse = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
385
|
+
method: 'GET',
|
|
386
|
+
url: `https://graph.microsoft.com/v1.0/sites/${siteId}/drive`,
|
|
387
|
+
json: true,
|
|
388
|
+
});
|
|
389
|
+
actualDriveId = driveResponse.id;
|
|
390
|
+
}
|
|
391
|
+
if (resource === 'file') {
|
|
392
|
+
// FILE OPERATIONS
|
|
393
|
+
if (operation === 'delete') {
|
|
394
|
+
const fileId = this.getNodeParameter('fileId', i);
|
|
395
|
+
await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
396
|
+
method: 'DELETE',
|
|
397
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}`,
|
|
398
|
+
json: true,
|
|
399
|
+
});
|
|
400
|
+
responseData = { success: true, fileId };
|
|
401
|
+
}
|
|
402
|
+
else if (operation === 'download') {
|
|
403
|
+
const fileId = this.getNodeParameter('fileId', i);
|
|
404
|
+
const binaryProperty = this.getNodeParameter('binaryProperty', i);
|
|
405
|
+
// Get file metadata first
|
|
406
|
+
const fileMetadata = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
407
|
+
method: 'GET',
|
|
408
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}`,
|
|
409
|
+
json: true,
|
|
410
|
+
});
|
|
411
|
+
// Download file content
|
|
412
|
+
const fileContent = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
413
|
+
method: 'GET',
|
|
414
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}/content`,
|
|
415
|
+
json: false,
|
|
416
|
+
encoding: null,
|
|
417
|
+
});
|
|
418
|
+
const fileName = fileMetadata.name || 'file';
|
|
419
|
+
const mimeType = fileMetadata.file?.mimeType || undefined;
|
|
420
|
+
const binaryData = await this.helpers.prepareBinaryData(fileContent, fileName, mimeType);
|
|
421
|
+
returnData.push({
|
|
422
|
+
json: fileMetadata,
|
|
423
|
+
binary: {
|
|
424
|
+
[binaryProperty]: binaryData,
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
else if (operation === 'get') {
|
|
430
|
+
const fileId = this.getNodeParameter('fileId', i);
|
|
431
|
+
responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
432
|
+
method: 'GET',
|
|
433
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}`,
|
|
434
|
+
json: true,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
else if (operation === 'rename') {
|
|
438
|
+
const fileId = this.getNodeParameter('fileId', i);
|
|
439
|
+
const newName = this.getNodeParameter('newName', i);
|
|
440
|
+
responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
441
|
+
method: 'PATCH',
|
|
442
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}`,
|
|
443
|
+
body: {
|
|
444
|
+
name: newName,
|
|
445
|
+
},
|
|
446
|
+
json: true,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
else if (operation === 'search') {
|
|
450
|
+
const query = this.getNodeParameter('query', i);
|
|
451
|
+
const result = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
452
|
+
method: 'GET',
|
|
453
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/root/search(q='${encodeURIComponent(query)}')`,
|
|
454
|
+
json: true,
|
|
455
|
+
});
|
|
456
|
+
const items = result.value || [];
|
|
457
|
+
responseData = items.filter((item) => item.file !== undefined);
|
|
458
|
+
}
|
|
459
|
+
else if (operation === 'share') {
|
|
460
|
+
const fileId = this.getNodeParameter('fileId', i);
|
|
461
|
+
const linkType = this.getNodeParameter('linkType', i);
|
|
462
|
+
const linkScope = this.getNodeParameter('linkScope', i);
|
|
463
|
+
responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
464
|
+
method: 'POST',
|
|
465
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${fileId}/createLink`,
|
|
466
|
+
body: {
|
|
467
|
+
type: linkType,
|
|
468
|
+
scope: linkScope,
|
|
469
|
+
},
|
|
470
|
+
json: true,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
else if (operation === 'upload') {
|
|
474
|
+
const parentFolderId = this.getNodeParameter('parentFolderId', i);
|
|
475
|
+
const fileName = this.getNodeParameter('fileName', i);
|
|
476
|
+
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i);
|
|
477
|
+
const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
|
|
478
|
+
const fileBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
479
|
+
const parentPath = parentFolderId === 'root' ? 'root' : `items/${parentFolderId}`;
|
|
480
|
+
responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
481
|
+
method: 'PUT',
|
|
482
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/${parentPath}:/${fileName}:/content`,
|
|
483
|
+
body: fileBuffer,
|
|
484
|
+
headers: {
|
|
485
|
+
'Content-Type': binaryData.mimeType || 'application/octet-stream',
|
|
486
|
+
},
|
|
487
|
+
json: true,
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
else if (resource === 'folder') {
|
|
492
|
+
// FOLDER OPERATIONS
|
|
493
|
+
if (operation === 'create') {
|
|
494
|
+
const folderName = this.getNodeParameter('folderName', i);
|
|
495
|
+
const parentFolderId = this.getNodeParameter('parentFolderId', i);
|
|
496
|
+
const parentPath = parentFolderId === 'root' ? 'root' : `items/${parentFolderId}`;
|
|
497
|
+
responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
498
|
+
method: 'POST',
|
|
499
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/${parentPath}/children`,
|
|
500
|
+
body: {
|
|
501
|
+
name: folderName,
|
|
502
|
+
folder: {},
|
|
503
|
+
'@microsoft.graph.conflictBehavior': 'rename',
|
|
504
|
+
},
|
|
505
|
+
json: true,
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
else if (operation === 'delete') {
|
|
509
|
+
const folderId = this.getNodeParameter('folderId', i);
|
|
510
|
+
await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
511
|
+
method: 'DELETE',
|
|
512
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${folderId}`,
|
|
513
|
+
json: true,
|
|
514
|
+
});
|
|
515
|
+
responseData = { success: true, folderId };
|
|
516
|
+
}
|
|
517
|
+
else if (operation === 'getItems') {
|
|
518
|
+
const parentFolderId = this.getNodeParameter('parentFolderId', i);
|
|
519
|
+
const parentPath = parentFolderId === 'root' ? 'root' : `items/${parentFolderId}`;
|
|
520
|
+
const result = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
521
|
+
method: 'GET',
|
|
522
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/${parentPath}/children`,
|
|
523
|
+
json: true,
|
|
524
|
+
});
|
|
525
|
+
responseData = result.value || [];
|
|
526
|
+
}
|
|
527
|
+
else if (operation === 'rename') {
|
|
528
|
+
const folderId = this.getNodeParameter('folderId', i);
|
|
529
|
+
const newName = this.getNodeParameter('newName', i);
|
|
530
|
+
responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
531
|
+
method: 'PATCH',
|
|
532
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${folderId}`,
|
|
533
|
+
body: {
|
|
534
|
+
name: newName,
|
|
535
|
+
},
|
|
536
|
+
json: true,
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
else if (operation === 'search') {
|
|
540
|
+
const query = this.getNodeParameter('query', i);
|
|
541
|
+
const result = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
542
|
+
method: 'GET',
|
|
543
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/root/search(q='${encodeURIComponent(query)}')`,
|
|
544
|
+
json: true,
|
|
545
|
+
});
|
|
546
|
+
const items = result.value || [];
|
|
547
|
+
responseData = items.filter((item) => item.folder !== undefined);
|
|
548
|
+
}
|
|
549
|
+
else if (operation === 'share') {
|
|
550
|
+
const folderId = this.getNodeParameter('folderId', i);
|
|
551
|
+
const linkType = this.getNodeParameter('linkType', i);
|
|
552
|
+
const linkScope = this.getNodeParameter('linkScope', i);
|
|
553
|
+
responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
554
|
+
method: 'POST',
|
|
555
|
+
url: `https://graph.microsoft.com/v1.0/drives/${actualDriveId}/items/${folderId}/createLink`,
|
|
556
|
+
body: {
|
|
557
|
+
type: linkType,
|
|
558
|
+
scope: linkScope,
|
|
559
|
+
},
|
|
560
|
+
json: true,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (Array.isArray(responseData)) {
|
|
565
|
+
returnData.push(...responseData.map((item) => ({ json: item })));
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
returnData.push({ json: responseData });
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
catch (error) {
|
|
572
|
+
if (this.continueOnFail()) {
|
|
573
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
574
|
+
returnData.push({ json: { error: errorMessage } });
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
throw error;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return [returnData];
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
exports.MicrosoftOneDriveBusiness = MicrosoftOneDriveBusiness;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IHookFunctions, IWebhookFunctions, INodeType, INodeTypeDescription, IWebhookResponseData } from 'n8n-workflow';
|
|
2
|
+
export declare class MicrosoftOneDriveBusinessTrigger implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
webhookMethods: {
|
|
5
|
+
default: {
|
|
6
|
+
checkExists(this: IHookFunctions): Promise<boolean>;
|
|
7
|
+
create(this: IHookFunctions): Promise<boolean>;
|
|
8
|
+
delete(this: IHookFunctions): Promise<boolean>;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MicrosoftOneDriveBusinessTrigger = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
class MicrosoftOneDriveBusinessTrigger {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.description = {
|
|
8
|
+
displayName: 'Microsoft OneDrive (Business) Trigger',
|
|
9
|
+
name: 'microsoftOneDriveBusinessTrigger',
|
|
10
|
+
icon: 'file:onedrive.svg',
|
|
11
|
+
group: ['trigger'],
|
|
12
|
+
version: 1,
|
|
13
|
+
subtitle: '={{$parameter["event"]}}',
|
|
14
|
+
description: 'Triggers when OneDrive for Business events occur',
|
|
15
|
+
defaults: {
|
|
16
|
+
name: 'OneDrive (Business) Trigger',
|
|
17
|
+
},
|
|
18
|
+
inputs: [],
|
|
19
|
+
outputs: ['main'],
|
|
20
|
+
credentials: [
|
|
21
|
+
{
|
|
22
|
+
name: 'microsoftOneDriveBusinessOAuth2Api',
|
|
23
|
+
required: true,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
webhooks: [
|
|
27
|
+
{
|
|
28
|
+
name: 'default',
|
|
29
|
+
httpMethod: 'POST',
|
|
30
|
+
responseMode: 'onReceived',
|
|
31
|
+
path: 'webhook',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
properties: [
|
|
35
|
+
{
|
|
36
|
+
displayName: 'Site ID',
|
|
37
|
+
name: 'siteId',
|
|
38
|
+
type: 'string',
|
|
39
|
+
default: '',
|
|
40
|
+
required: true,
|
|
41
|
+
description: 'The SharePoint site ID',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
displayName: 'Drive ID',
|
|
45
|
+
name: 'driveId',
|
|
46
|
+
type: 'string',
|
|
47
|
+
default: '',
|
|
48
|
+
description: 'The drive ID. If not specified, the default drive for the site will be used.',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
displayName: 'Event',
|
|
52
|
+
name: 'event',
|
|
53
|
+
type: 'options',
|
|
54
|
+
options: [
|
|
55
|
+
{
|
|
56
|
+
name: '⚡ On File Created',
|
|
57
|
+
value: 'fileCreated',
|
|
58
|
+
description: 'Trigger when a file is created',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: '⚡ On File Updated',
|
|
62
|
+
value: 'fileUpdated',
|
|
63
|
+
description: 'Trigger when a file is updated',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: '⚡ On Folder Created',
|
|
67
|
+
value: 'folderCreated',
|
|
68
|
+
description: 'Trigger when a folder is created',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: '⚡ On Folder Updated',
|
|
72
|
+
value: 'folderUpdated',
|
|
73
|
+
description: 'Trigger when a folder is updated',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
default: 'fileCreated',
|
|
77
|
+
description: 'The event to trigger on',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
displayName: 'Watch Folder ID',
|
|
81
|
+
name: 'watchFolderId',
|
|
82
|
+
type: 'string',
|
|
83
|
+
default: 'root',
|
|
84
|
+
description: 'The ID of the folder to watch. Use "root" to watch the entire drive.',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
displayName: 'Options',
|
|
88
|
+
name: 'options',
|
|
89
|
+
type: 'collection',
|
|
90
|
+
placeholder: 'Add Option',
|
|
91
|
+
default: {},
|
|
92
|
+
options: [
|
|
93
|
+
{
|
|
94
|
+
displayName: 'Poll Interval (minutes)',
|
|
95
|
+
name: 'pollInterval',
|
|
96
|
+
type: 'number',
|
|
97
|
+
default: 5,
|
|
98
|
+
description: 'How often to poll for changes (in minutes)',
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
this.webhookMethods = {
|
|
105
|
+
default: {
|
|
106
|
+
async checkExists() {
|
|
107
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
108
|
+
if (webhookData.subscriptionId === undefined) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const siteId = this.getNodeParameter('siteId');
|
|
112
|
+
const driveId = this.getNodeParameter('driveId', '');
|
|
113
|
+
// Get drive ID if not provided
|
|
114
|
+
let actualDriveId = driveId;
|
|
115
|
+
if (!actualDriveId) {
|
|
116
|
+
const driveResponse = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
117
|
+
method: 'GET',
|
|
118
|
+
url: `https://graph.microsoft.com/v1.0/sites/${siteId}/drive`,
|
|
119
|
+
json: true,
|
|
120
|
+
});
|
|
121
|
+
actualDriveId = driveResponse.id;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
125
|
+
method: 'GET',
|
|
126
|
+
url: `https://graph.microsoft.com/v1.0/subscriptions/${webhookData.subscriptionId}`,
|
|
127
|
+
json: true,
|
|
128
|
+
});
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
async create() {
|
|
136
|
+
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
137
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
138
|
+
const siteId = this.getNodeParameter('siteId');
|
|
139
|
+
const driveId = this.getNodeParameter('driveId', '');
|
|
140
|
+
const watchFolderId = this.getNodeParameter('watchFolderId');
|
|
141
|
+
// Get drive ID if not provided
|
|
142
|
+
let actualDriveId = driveId;
|
|
143
|
+
if (!actualDriveId) {
|
|
144
|
+
const driveResponse = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
145
|
+
method: 'GET',
|
|
146
|
+
url: `https://graph.microsoft.com/v1.0/sites/${siteId}/drive`,
|
|
147
|
+
json: true,
|
|
148
|
+
});
|
|
149
|
+
actualDriveId = driveResponse.id;
|
|
150
|
+
}
|
|
151
|
+
const watchPath = watchFolderId === 'root' ? 'root' : `items/${watchFolderId}`;
|
|
152
|
+
const resource = `/drives/${actualDriveId}/${watchPath}`;
|
|
153
|
+
// Create subscription
|
|
154
|
+
const expirationDateTime = new Date();
|
|
155
|
+
expirationDateTime.setHours(expirationDateTime.getHours() + 72); // 72 hours max
|
|
156
|
+
const body = {
|
|
157
|
+
changeType: 'updated',
|
|
158
|
+
notificationUrl: webhookUrl,
|
|
159
|
+
resource,
|
|
160
|
+
expirationDateTime: expirationDateTime.toISOString(),
|
|
161
|
+
clientState: 'n8n-secret-token',
|
|
162
|
+
};
|
|
163
|
+
try {
|
|
164
|
+
const responseData = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
165
|
+
method: 'POST',
|
|
166
|
+
url: 'https://graph.microsoft.com/v1.0/subscriptions',
|
|
167
|
+
body,
|
|
168
|
+
json: true,
|
|
169
|
+
});
|
|
170
|
+
webhookData.subscriptionId = responseData.id;
|
|
171
|
+
webhookData.driveId = actualDriveId;
|
|
172
|
+
webhookData.deltaLink = null;
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
176
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Microsoft Graph subscription creation failed: ${errorMessage}`);
|
|
177
|
+
}
|
|
178
|
+
return true;
|
|
179
|
+
},
|
|
180
|
+
async delete() {
|
|
181
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
182
|
+
if (webhookData.subscriptionId !== undefined) {
|
|
183
|
+
try {
|
|
184
|
+
await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
185
|
+
method: 'DELETE',
|
|
186
|
+
url: `https://graph.microsoft.com/v1.0/subscriptions/${webhookData.subscriptionId}`,
|
|
187
|
+
json: true,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
delete webhookData.subscriptionId;
|
|
194
|
+
delete webhookData.driveId;
|
|
195
|
+
delete webhookData.deltaLink;
|
|
196
|
+
}
|
|
197
|
+
return true;
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
async webhook() {
|
|
203
|
+
const bodyData = this.getBodyData();
|
|
204
|
+
const query = this.getQueryData();
|
|
205
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
206
|
+
// Handle validation request
|
|
207
|
+
if (query.validationToken) {
|
|
208
|
+
return {
|
|
209
|
+
webhookResponse: query.validationToken,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
// Verify client state
|
|
213
|
+
const notification = bodyData.value?.[0];
|
|
214
|
+
if (notification?.clientState !== 'n8n-secret-token') {
|
|
215
|
+
return {
|
|
216
|
+
webhookResponse: 'Invalid client state',
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const event = this.getNodeParameter('event');
|
|
220
|
+
const watchFolderId = this.getNodeParameter('watchFolderId');
|
|
221
|
+
const driveId = webhookData.driveId;
|
|
222
|
+
// Use delta query to get changes
|
|
223
|
+
let deltaUrl = webhookData.deltaLink;
|
|
224
|
+
if (!deltaUrl) {
|
|
225
|
+
const watchPath = watchFolderId === 'root' ? 'root' : `items/${watchFolderId}`;
|
|
226
|
+
deltaUrl = `https://graph.microsoft.com/v1.0/drives/${driveId}/${watchPath}/delta`;
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
const deltaResponse = await this.helpers.requestOAuth2.call(this, 'microsoftOneDriveBusinessOAuth2Api', {
|
|
230
|
+
method: 'GET',
|
|
231
|
+
url: deltaUrl,
|
|
232
|
+
json: true,
|
|
233
|
+
});
|
|
234
|
+
// Store the new delta link
|
|
235
|
+
webhookData.deltaLink = deltaResponse['@odata.deltaLink'];
|
|
236
|
+
const changes = deltaResponse.value;
|
|
237
|
+
const filteredChanges = changes.filter((change) => {
|
|
238
|
+
const isFile = change.file !== undefined;
|
|
239
|
+
const isFolder = change.folder !== undefined;
|
|
240
|
+
const isDeleted = change.deleted !== undefined;
|
|
241
|
+
if (isDeleted)
|
|
242
|
+
return false;
|
|
243
|
+
if (event === 'fileCreated' && isFile) {
|
|
244
|
+
return change.createdDateTime === change.lastModifiedDateTime;
|
|
245
|
+
}
|
|
246
|
+
else if (event === 'fileUpdated' && isFile) {
|
|
247
|
+
return change.createdDateTime !== change.lastModifiedDateTime;
|
|
248
|
+
}
|
|
249
|
+
else if (event === 'folderCreated' && isFolder) {
|
|
250
|
+
return change.createdDateTime === change.lastModifiedDateTime;
|
|
251
|
+
}
|
|
252
|
+
else if (event === 'folderUpdated' && isFolder) {
|
|
253
|
+
return change.createdDateTime !== change.lastModifiedDateTime;
|
|
254
|
+
}
|
|
255
|
+
return false;
|
|
256
|
+
});
|
|
257
|
+
if (filteredChanges.length === 0) {
|
|
258
|
+
return {
|
|
259
|
+
webhookResponse: 'No matching changes',
|
|
260
|
+
workflowData: [],
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
workflowData: [filteredChanges.map((change) => ({ json: change }))],
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
269
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to fetch delta changes: ${errorMessage}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
exports.MicrosoftOneDriveBusinessTrigger = MicrosoftOneDriveBusinessTrigger;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
|
|
2
|
+
<path fill="#0364B8" d="M154.4 90.93A66.31 66.31 0 0 0 92.38 56C64.25 56 41 78.55 40 106.64A63.67 63.67 0 0 0 0 167.68C0 198.16 24.73 223 55.21 223h98.11c36.51 0 66.16-29.65 66.16-66.16a66.37 66.37 0 0 0-65.08-65.91Z"/>
|
|
3
|
+
<path fill="#0078D4" d="M154.4 90.93A66.28 66.28 0 0 0 92.38 56a66.84 66.84 0 0 0-15.61 1.84a66.33 66.33 0 0 1 77.63 99.33a66.18 66.18 0 0 1 65.08 65.91c0 2.4-.13 4.77-.39 7.1A66.13 66.13 0 0 0 256 156.84a66.37 66.37 0 0 0-101.6-65.91Z"/>
|
|
4
|
+
<path fill="#1490DF" d="M154.4 90.93a66.54 66.54 0 0 0-3.65-1.52A66.36 66.36 0 0 0 92.38 56a66.84 66.84 0 0 0-15.61 1.84a67 67 0 0 1 9.09 1.16a66.32 66.32 0 0 1 53.48 83.45A63.67 63.67 0 0 0 99.85 120a63.87 63.87 0 0 0-59.85 40.71a63.87 63.87 0 0 1 15.21-54.07A63.67 63.67 0 0 1 95 81.24a66.36 66.36 0 0 1 59.4 9.69Z"/>
|
|
5
|
+
<path fill="#28A8EA" d="M154.4 90.93a63.67 63.67 0 0 1 44 66.63a66.18 66.18 0 0 1 21.08 65.91H153.32a66.16 66.16 0 0 0 66.16-66.63a66.36 66.36 0 0 0-65.08-65.91Z"/>
|
|
6
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-onedrive-business-sp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "n8n node for Microsoft OneDrive for Business (SharePoint)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n",
|
|
8
|
+
"onedrive",
|
|
9
|
+
"sharepoint",
|
|
10
|
+
"microsoft",
|
|
11
|
+
"graph",
|
|
12
|
+
"business"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "Your Name",
|
|
17
|
+
"email": "your.email@example.com"
|
|
18
|
+
},
|
|
19
|
+
"main": "dist/index.js",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc && node copy-icons.js",
|
|
22
|
+
"dev": "tsc --watch",
|
|
23
|
+
"format": "prettier nodes credentials --write",
|
|
24
|
+
"lint": "eslint \"nodes/**/*.ts\" \"credentials/**/*.ts\" package.json",
|
|
25
|
+
"lintfix": "eslint \"nodes/**/*.ts\" \"credentials/**/*.ts\" package.json --fix",
|
|
26
|
+
"prepublishOnly": "npm run build"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist"
|
|
30
|
+
],
|
|
31
|
+
"n8n": {
|
|
32
|
+
"n8nNodesApiVersion": 1,
|
|
33
|
+
"credentials": [
|
|
34
|
+
"dist/credentials/MicrosoftOneDriveBusinessOAuth2Api.credentials.js"
|
|
35
|
+
],
|
|
36
|
+
"nodes": [
|
|
37
|
+
"dist/nodes/MicrosoftOneDriveBusiness/MicrosoftOneDriveBusiness.node.js",
|
|
38
|
+
"dist/nodes/MicrosoftOneDriveBusiness/MicrosoftOneDriveBusinessTrigger.node.js"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^25.0.3",
|
|
43
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
44
|
+
"eslint": "^8.0.0",
|
|
45
|
+
"eslint-plugin-n8n-nodes-base": "^1.11.0",
|
|
46
|
+
"gulp": "^4.0.2",
|
|
47
|
+
"n8n-workflow": "*",
|
|
48
|
+
"prettier": "^3.0.0",
|
|
49
|
+
"typescript": "^5.3.3"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"n8n-workflow": "*"
|
|
53
|
+
}
|
|
54
|
+
}
|