@blickwerk/n8n-nodes-microsoft-planner 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -11
- package/dist/nodes/MicrosoftPlanner/GenericFunctions.d.ts +3 -0
- package/dist/nodes/MicrosoftPlanner/GenericFunctions.js +33 -0
- package/dist/nodes/MicrosoftPlanner/MicrosoftPlanner.node.js +52 -8
- package/dist/nodes/MicrosoftPlanner/TaskDescription.js +56 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes
|
|
|
14
14
|
|
|
15
15
|
1. Go to **Settings > Community Nodes** in your n8n instance
|
|
16
16
|
2. Select **Install**
|
|
17
|
-
3. Enter
|
|
17
|
+
3. Enter `@blickwerk/n8n-nodes-microsoft-planner` in **Enter npm package name**
|
|
18
18
|
4. Agree to the [risks](https://docs.n8n.io/integrations/community-nodes/risks/) of using community nodes
|
|
19
19
|
5. Select **Install**
|
|
20
20
|
|
|
@@ -22,10 +22,10 @@ After installing the node, you can use it like any other node in your workflows.
|
|
|
22
22
|
|
|
23
23
|
### Manual Installation
|
|
24
24
|
|
|
25
|
-
To install manually
|
|
25
|
+
To install manually:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
npm install n8n-nodes-microsoft-planner
|
|
28
|
+
npm install @blickwerk/n8n-nodes-microsoft-planner
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
## Prerequisites
|
|
@@ -36,6 +36,7 @@ You need to have:
|
|
|
36
36
|
- Azure AD App Registration with the following API permissions:
|
|
37
37
|
- `Tasks.ReadWrite` - Read and write tasks
|
|
38
38
|
- `Group.ReadWrite.All` - Read and write all groups (required for Planner)
|
|
39
|
+
- `User.Read.All` - Read all users (required for user assignment by email)
|
|
39
40
|
|
|
40
41
|
## Setting up Azure AD App
|
|
41
42
|
|
|
@@ -54,10 +55,13 @@ You need to have:
|
|
|
54
55
|
3. Select **Microsoft Graph**
|
|
55
56
|
4. Select **Delegated permissions**
|
|
56
57
|
5. Add the following permissions:
|
|
57
|
-
- `Tasks.ReadWrite`
|
|
58
|
-
- `Group.ReadWrite.All`
|
|
58
|
+
- `Tasks.ReadWrite` - Read and write tasks
|
|
59
|
+
- `Group.ReadWrite.All` - Read and write all groups (required for Planner)
|
|
60
|
+
- `User.Read.All` - Read all users' basic profiles (required for user assignment)
|
|
59
61
|
6. Click **Grant admin consent**
|
|
60
62
|
|
|
63
|
+
**Note**: The `User.Read.All` permission is required if you want to assign tasks to users by email address.
|
|
64
|
+
|
|
61
65
|
### Create Client Secret
|
|
62
66
|
|
|
63
67
|
1. Go to **Certificates & secrets**
|
|
@@ -100,11 +104,16 @@ To create a task, you need:
|
|
|
100
104
|
- **Title**: The task title
|
|
101
105
|
|
|
102
106
|
Optional fields:
|
|
103
|
-
- Description
|
|
104
|
-
- Priority
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
107
|
+
- **Description**: Detailed task description
|
|
108
|
+
- **Priority**: Select from dropdown
|
|
109
|
+
- Urgent (highest priority)
|
|
110
|
+
- Important
|
|
111
|
+
- Medium (default)
|
|
112
|
+
- Low
|
|
113
|
+
- **Assigned To**: Comma-separated list of user emails (e.g., `user1@domain.com, user2@domain.com`)
|
|
114
|
+
- **Due Date Time**: When the task should be completed
|
|
115
|
+
- **Start Date Time**: When work on the task should begin
|
|
116
|
+
- **Percent Complete**: Task completion percentage (0-100)
|
|
108
117
|
|
|
109
118
|
### Getting Tasks
|
|
110
119
|
|
|
@@ -115,7 +124,15 @@ You can retrieve tasks by:
|
|
|
115
124
|
|
|
116
125
|
### Updating a Task
|
|
117
126
|
|
|
118
|
-
To update a task, provide the Task ID and the fields you want to update.
|
|
127
|
+
To update a task, provide the Task ID and the fields you want to update. You can update:
|
|
128
|
+
- Title
|
|
129
|
+
- Description
|
|
130
|
+
- Priority (via dropdown)
|
|
131
|
+
- Assigned users (via email list)
|
|
132
|
+
- Due Date Time
|
|
133
|
+
- Start Date Time
|
|
134
|
+
- Percent Complete
|
|
135
|
+
- Move to different bucket
|
|
119
136
|
|
|
120
137
|
### Finding Plan and Bucket IDs
|
|
121
138
|
|
|
@@ -139,10 +156,20 @@ Tested with n8n version 1.0.0 and above.
|
|
|
139
156
|
|
|
140
157
|
## Version History
|
|
141
158
|
|
|
159
|
+
### 1.1.0
|
|
160
|
+
- Added priority dropdown (Urgent, Important, Medium, Low) instead of number input
|
|
161
|
+
- Added user assignment functionality (assign tasks by email)
|
|
162
|
+
- Improved user experience with better field descriptions
|
|
163
|
+
|
|
164
|
+
### 1.0.1
|
|
165
|
+
- Fixed DateTime format handling (automatic conversion to ISO 8601)
|
|
166
|
+
- Improved error handling for invalid date formats
|
|
167
|
+
|
|
142
168
|
### 1.0.0
|
|
143
169
|
- Initial release
|
|
144
170
|
- Support for creating and retrieving Planner tasks
|
|
145
171
|
- OAuth2 authentication
|
|
172
|
+
- CRUD operations (Create, Read, Update, Delete)
|
|
146
173
|
|
|
147
174
|
## License
|
|
148
175
|
|
|
@@ -3,3 +3,6 @@ export declare function microsoftApiRequest(this: IHookFunctions | IExecuteFunct
|
|
|
3
3
|
export declare function microsoftApiRequestAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: IHttpRequestMethods, endpoint: string, body?: IDataObject, query?: IDataObject): Promise<any>;
|
|
4
4
|
export declare function cleanETag(eTag: string): string;
|
|
5
5
|
export declare function formatDateTime(dateTime: string | undefined): string | undefined;
|
|
6
|
+
export declare function getUserIdByEmail(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, email: string): Promise<string | null>;
|
|
7
|
+
export declare function parseAssignments(assignmentsString: string): string[];
|
|
8
|
+
export declare function createAssignmentsObject(userIds: string[]): IDataObject;
|
|
@@ -4,6 +4,9 @@ exports.microsoftApiRequest = microsoftApiRequest;
|
|
|
4
4
|
exports.microsoftApiRequestAllItems = microsoftApiRequestAllItems;
|
|
5
5
|
exports.cleanETag = cleanETag;
|
|
6
6
|
exports.formatDateTime = formatDateTime;
|
|
7
|
+
exports.getUserIdByEmail = getUserIdByEmail;
|
|
8
|
+
exports.parseAssignments = parseAssignments;
|
|
9
|
+
exports.createAssignmentsObject = createAssignmentsObject;
|
|
7
10
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
8
11
|
async function microsoftApiRequest(method, resource, body = {}, qs = {}, uri, headers = {}) {
|
|
9
12
|
const options = {
|
|
@@ -61,3 +64,33 @@ function formatDateTime(dateTime) {
|
|
|
61
64
|
}
|
|
62
65
|
return date.toISOString();
|
|
63
66
|
}
|
|
67
|
+
async function getUserIdByEmail(email) {
|
|
68
|
+
try {
|
|
69
|
+
const response = await microsoftApiRequest.call(this, 'GET', `/users/${encodeURIComponent(email)}`);
|
|
70
|
+
return response.id;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
// Log error for debugging
|
|
74
|
+
console.error(`Failed to get user ID for email ${email}:`, error.message || error);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function parseAssignments(assignmentsString) {
|
|
79
|
+
if (!assignmentsString || assignmentsString.trim() === '') {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
return assignmentsString
|
|
83
|
+
.split(',')
|
|
84
|
+
.map((email) => email.trim())
|
|
85
|
+
.filter((email) => email.length > 0);
|
|
86
|
+
}
|
|
87
|
+
function createAssignmentsObject(userIds) {
|
|
88
|
+
const assignments = {};
|
|
89
|
+
for (const userId of userIds) {
|
|
90
|
+
assignments[userId] = {
|
|
91
|
+
'@odata.type': '#microsoft.graph.plannerAssignment',
|
|
92
|
+
orderHint: ' !',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return assignments;
|
|
96
|
+
}
|
|
@@ -68,15 +68,37 @@ class MicrosoftPlanner {
|
|
|
68
68
|
if (additionalFields.priority !== undefined) {
|
|
69
69
|
body.priority = additionalFields.priority;
|
|
70
70
|
}
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
const formattedDueDateTime = (0, GenericFunctions_1.formatDateTime)(additionalFields.dueDateTime);
|
|
72
|
+
if (formattedDueDateTime) {
|
|
73
|
+
body.dueDateTime = formattedDueDateTime;
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
const formattedStartDateTime = (0, GenericFunctions_1.formatDateTime)(additionalFields.startDateTime);
|
|
76
|
+
if (formattedStartDateTime) {
|
|
77
|
+
body.startDateTime = formattedStartDateTime;
|
|
76
78
|
}
|
|
77
79
|
if (additionalFields.percentComplete !== undefined) {
|
|
78
80
|
body.percentComplete = additionalFields.percentComplete;
|
|
79
81
|
}
|
|
82
|
+
// Handle assignments
|
|
83
|
+
if (additionalFields.assignments) {
|
|
84
|
+
const emails = (0, GenericFunctions_1.parseAssignments)(additionalFields.assignments);
|
|
85
|
+
const userIds = [];
|
|
86
|
+
for (const email of emails) {
|
|
87
|
+
const userId = await GenericFunctions_1.getUserIdByEmail.call(this, email);
|
|
88
|
+
if (userId) {
|
|
89
|
+
userIds.push(userId);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.warn(`Could not find user ID for email: ${email}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (userIds.length > 0) {
|
|
96
|
+
body.assignments = (0, GenericFunctions_1.createAssignmentsObject)(userIds);
|
|
97
|
+
}
|
|
98
|
+
else if (emails.length > 0) {
|
|
99
|
+
console.warn('No valid user IDs found for assignment. Check if User.Read.All permission is granted.');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
80
102
|
const responseData = await GenericFunctions_1.microsoftApiRequest.call(this, 'POST', '/planner/tasks', body);
|
|
81
103
|
// Add description if provided
|
|
82
104
|
if (additionalFields.description) {
|
|
@@ -148,11 +170,13 @@ class MicrosoftPlanner {
|
|
|
148
170
|
if (updateFields.priority !== undefined) {
|
|
149
171
|
body.priority = updateFields.priority;
|
|
150
172
|
}
|
|
151
|
-
|
|
152
|
-
|
|
173
|
+
const formattedDueDateTime = (0, GenericFunctions_1.formatDateTime)(updateFields.dueDateTime);
|
|
174
|
+
if (formattedDueDateTime) {
|
|
175
|
+
body.dueDateTime = formattedDueDateTime;
|
|
153
176
|
}
|
|
154
|
-
|
|
155
|
-
|
|
177
|
+
const formattedStartDateTime = (0, GenericFunctions_1.formatDateTime)(updateFields.startDateTime);
|
|
178
|
+
if (formattedStartDateTime) {
|
|
179
|
+
body.startDateTime = formattedStartDateTime;
|
|
156
180
|
}
|
|
157
181
|
if (updateFields.percentComplete !== undefined) {
|
|
158
182
|
body.percentComplete = updateFields.percentComplete;
|
|
@@ -160,6 +184,26 @@ class MicrosoftPlanner {
|
|
|
160
184
|
if (updateFields.bucketId) {
|
|
161
185
|
body.bucketId = updateFields.bucketId;
|
|
162
186
|
}
|
|
187
|
+
// Handle assignments
|
|
188
|
+
if (updateFields.assignments) {
|
|
189
|
+
const emails = (0, GenericFunctions_1.parseAssignments)(updateFields.assignments);
|
|
190
|
+
const userIds = [];
|
|
191
|
+
for (const email of emails) {
|
|
192
|
+
const userId = await GenericFunctions_1.getUserIdByEmail.call(this, email);
|
|
193
|
+
if (userId) {
|
|
194
|
+
userIds.push(userId);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
console.warn(`Could not find user ID for email: ${email}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (userIds.length > 0) {
|
|
201
|
+
body.assignments = (0, GenericFunctions_1.createAssignmentsObject)(userIds);
|
|
202
|
+
}
|
|
203
|
+
else if (emails.length > 0) {
|
|
204
|
+
console.warn('No valid user IDs found for assignment. Check if User.Read.All permission is granted.');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
163
207
|
const responseData = await GenericFunctions_1.microsoftApiRequest.call(this, 'PATCH', `/planner/tasks/${taskId}`, body, {}, undefined, {
|
|
164
208
|
'If-Match': eTag,
|
|
165
209
|
});
|
|
@@ -119,9 +119,35 @@ exports.taskFields = [
|
|
|
119
119
|
{
|
|
120
120
|
displayName: 'Priority',
|
|
121
121
|
name: 'priority',
|
|
122
|
-
type: '
|
|
122
|
+
type: 'options',
|
|
123
|
+
options: [
|
|
124
|
+
{
|
|
125
|
+
name: 'Urgent',
|
|
126
|
+
value: 0,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: 'Important',
|
|
130
|
+
value: 1,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'Medium',
|
|
134
|
+
value: 5,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'Low',
|
|
138
|
+
value: 9,
|
|
139
|
+
},
|
|
140
|
+
],
|
|
123
141
|
default: 5,
|
|
124
|
-
description: 'Priority of the task
|
|
142
|
+
description: 'Priority of the task',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
displayName: 'Assigned To (User IDs)',
|
|
146
|
+
name: 'assignments',
|
|
147
|
+
type: 'string',
|
|
148
|
+
default: '',
|
|
149
|
+
placeholder: 'user1@domain.com, user2@domain.com',
|
|
150
|
+
description: 'Comma-separated list of user emails or IDs to assign the task to',
|
|
125
151
|
},
|
|
126
152
|
{
|
|
127
153
|
displayName: 'Due Date Time',
|
|
@@ -284,9 +310,35 @@ exports.taskFields = [
|
|
|
284
310
|
{
|
|
285
311
|
displayName: 'Priority',
|
|
286
312
|
name: 'priority',
|
|
287
|
-
type: '
|
|
313
|
+
type: 'options',
|
|
314
|
+
options: [
|
|
315
|
+
{
|
|
316
|
+
name: 'Urgent',
|
|
317
|
+
value: 0,
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
name: 'Important',
|
|
321
|
+
value: 1,
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
name: 'Medium',
|
|
325
|
+
value: 5,
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: 'Low',
|
|
329
|
+
value: 9,
|
|
330
|
+
},
|
|
331
|
+
],
|
|
288
332
|
default: 5,
|
|
289
|
-
description: 'Priority of the task
|
|
333
|
+
description: 'Priority of the task',
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
displayName: 'Assigned To (User IDs)',
|
|
337
|
+
name: 'assignments',
|
|
338
|
+
type: 'string',
|
|
339
|
+
default: '',
|
|
340
|
+
placeholder: 'user1@domain.com, user2@domain.com',
|
|
341
|
+
description: 'Comma-separated list of user emails or IDs to assign the task to',
|
|
290
342
|
},
|
|
291
343
|
{
|
|
292
344
|
displayName: 'Due Date Time',
|