@openfn/language-asana 4.0.11 → 4.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/ast.json +64 -10
- package/configuration-schema.json +6 -3
- package/dist/index.cjs +91 -53
- package/dist/index.js +97 -55
- package/package.json +7 -7
- package/types/Adaptor.d.ts +27 -9
- package/types/util.d.ts +5 -0
- package/types/Utils.d.ts +0 -2
package/ast.json
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"title": "example",
|
|
20
|
-
"description": "getTask(\"1206933955023739\", {\n opt_fields: \"name,notes,assignee\",\n});"
|
|
20
|
+
"description": "getTask(\"1206933955023739\", {\n opt_fields: \"name,notes,assignee\",\n});",
|
|
21
|
+
"caption": "Get a task"
|
|
21
22
|
},
|
|
22
23
|
{
|
|
23
24
|
"title": "function",
|
|
@@ -42,6 +43,15 @@
|
|
|
42
43
|
},
|
|
43
44
|
"name": "params"
|
|
44
45
|
},
|
|
46
|
+
{
|
|
47
|
+
"title": "param",
|
|
48
|
+
"description": "The fields to return.",
|
|
49
|
+
"type": {
|
|
50
|
+
"type": "NameExpression",
|
|
51
|
+
"name": "string"
|
|
52
|
+
},
|
|
53
|
+
"name": "params.opt_fields"
|
|
54
|
+
},
|
|
45
55
|
{
|
|
46
56
|
"title": "param",
|
|
47
57
|
"description": "(Optional) callback function",
|
|
@@ -61,7 +71,7 @@
|
|
|
61
71
|
}
|
|
62
72
|
]
|
|
63
73
|
},
|
|
64
|
-
"valid":
|
|
74
|
+
"valid": false
|
|
65
75
|
},
|
|
66
76
|
{
|
|
67
77
|
"name": "getTasks",
|
|
@@ -80,7 +90,13 @@
|
|
|
80
90
|
},
|
|
81
91
|
{
|
|
82
92
|
"title": "example",
|
|
83
|
-
"description": "getTasks(\"1206933955023739\", {\n opt_fields: \"name,notes,assignee\",\n});"
|
|
93
|
+
"description": "getTasks(\"1206933955023739\", {\n opt_fields: \"name,notes,assignee\",\n});",
|
|
94
|
+
"caption": "Get all tasks"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"title": "example",
|
|
98
|
+
"description": "getTasks(\"1206933955023739\", {\n opt_fields: \"name,notes,assignee\",\n limit: 100,\n});",
|
|
99
|
+
"caption": "Limit the number of tasks returned"
|
|
84
100
|
},
|
|
85
101
|
{
|
|
86
102
|
"title": "function",
|
|
@@ -105,6 +121,24 @@
|
|
|
105
121
|
},
|
|
106
122
|
"name": "params"
|
|
107
123
|
},
|
|
124
|
+
{
|
|
125
|
+
"title": "param",
|
|
126
|
+
"description": "The maximum number of tasks to return.",
|
|
127
|
+
"type": {
|
|
128
|
+
"type": "NameExpression",
|
|
129
|
+
"name": "number"
|
|
130
|
+
},
|
|
131
|
+
"name": "params.limit"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"title": "param",
|
|
135
|
+
"description": "The fields to return.",
|
|
136
|
+
"type": {
|
|
137
|
+
"type": "NameExpression",
|
|
138
|
+
"name": "string"
|
|
139
|
+
},
|
|
140
|
+
"name": "params.opt_fields"
|
|
141
|
+
},
|
|
108
142
|
{
|
|
109
143
|
"title": "param",
|
|
110
144
|
"description": "(Optional) callback function",
|
|
@@ -124,13 +158,13 @@
|
|
|
124
158
|
}
|
|
125
159
|
]
|
|
126
160
|
},
|
|
127
|
-
"valid":
|
|
161
|
+
"valid": false
|
|
128
162
|
},
|
|
129
163
|
{
|
|
130
164
|
"name": "updateTask",
|
|
131
165
|
"params": [
|
|
132
166
|
"taskGid",
|
|
133
|
-
"
|
|
167
|
+
"data",
|
|
134
168
|
"callback"
|
|
135
169
|
],
|
|
136
170
|
"docs": {
|
|
@@ -143,7 +177,8 @@
|
|
|
143
177
|
},
|
|
144
178
|
{
|
|
145
179
|
"title": "example",
|
|
146
|
-
"description": "updateTask(\"1206933955023739\", {\n name: \"test\",\n approval_status: \"pending\",\n assignee: \"12345\",\n});"
|
|
180
|
+
"description": "updateTask(\"1206933955023739\", {\n name: \"test\",\n approval_status: \"pending\",\n assignee: \"12345\",\n});",
|
|
181
|
+
"caption": "Update a task"
|
|
147
182
|
},
|
|
148
183
|
{
|
|
149
184
|
"title": "function",
|
|
@@ -161,12 +196,12 @@
|
|
|
161
196
|
},
|
|
162
197
|
{
|
|
163
198
|
"title": "param",
|
|
164
|
-
"description": "Body
|
|
199
|
+
"description": "Body data to update the task with",
|
|
165
200
|
"type": {
|
|
166
201
|
"type": "NameExpression",
|
|
167
202
|
"name": "object"
|
|
168
203
|
},
|
|
169
|
-
"name": "
|
|
204
|
+
"name": "data"
|
|
170
205
|
},
|
|
171
206
|
{
|
|
172
207
|
"title": "param",
|
|
@@ -259,7 +294,8 @@
|
|
|
259
294
|
},
|
|
260
295
|
{
|
|
261
296
|
"title": "example",
|
|
262
|
-
"description": "upsertTask(\"1201382240880\", {\n externalId: \"name\",\n data: {\n name: \"test\",\n approval_status: \"pending\",\n projects: [\"1201382240880\"],\n assignee: \"12345\",\n },\n});"
|
|
297
|
+
"description": "upsertTask(\"1201382240880\", {\n externalId: \"name\",\n data: {\n name: \"test\",\n approval_status: \"pending\",\n projects: [\"1201382240880\"],\n assignee: \"12345\",\n },\n});",
|
|
298
|
+
"caption": "Upsert a task"
|
|
263
299
|
},
|
|
264
300
|
{
|
|
265
301
|
"title": "function",
|
|
@@ -284,6 +320,24 @@
|
|
|
284
320
|
},
|
|
285
321
|
"name": "params"
|
|
286
322
|
},
|
|
323
|
+
{
|
|
324
|
+
"title": "param",
|
|
325
|
+
"description": "The external id field name",
|
|
326
|
+
"type": {
|
|
327
|
+
"type": "NameExpression",
|
|
328
|
+
"name": "string"
|
|
329
|
+
},
|
|
330
|
+
"name": "params.externalId"
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
"title": "param",
|
|
334
|
+
"description": "The data to upsert.",
|
|
335
|
+
"type": {
|
|
336
|
+
"type": "NameExpression",
|
|
337
|
+
"name": "object"
|
|
338
|
+
},
|
|
339
|
+
"name": "params.data"
|
|
340
|
+
},
|
|
287
341
|
{
|
|
288
342
|
"title": "param",
|
|
289
343
|
"description": "(Optional) callback function",
|
|
@@ -303,7 +357,7 @@
|
|
|
303
357
|
}
|
|
304
358
|
]
|
|
305
359
|
},
|
|
306
|
-
"valid":
|
|
360
|
+
"valid": false
|
|
307
361
|
},
|
|
308
362
|
{
|
|
309
363
|
"name": "createTaskStory",
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
"description": "The API version",
|
|
8
8
|
"examples": [
|
|
9
9
|
"1.0"
|
|
10
|
-
]
|
|
10
|
+
],
|
|
11
|
+
"default": "1.0"
|
|
11
12
|
},
|
|
12
13
|
"token": {
|
|
13
14
|
"title": "Token",
|
|
@@ -20,5 +21,7 @@
|
|
|
20
21
|
},
|
|
21
22
|
"type": "object",
|
|
22
23
|
"additionalProperties": true,
|
|
23
|
-
"required": [
|
|
24
|
-
|
|
24
|
+
"required": [
|
|
25
|
+
"token"
|
|
26
|
+
]
|
|
27
|
+
}
|
package/dist/index.cjs
CHANGED
|
@@ -74,34 +74,33 @@ __export(Adaptor_exports, {
|
|
|
74
74
|
var import_language_common2 = require("@openfn/language-common");
|
|
75
75
|
var import_util2 = require("@openfn/language-common/util");
|
|
76
76
|
|
|
77
|
-
// src/
|
|
78
|
-
var import_language_common = require("@openfn/language-common");
|
|
77
|
+
// src/util.js
|
|
79
78
|
var import_util = require("@openfn/language-common/util");
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
var import_node_path = require("path");
|
|
80
|
+
var import_language_common = require("@openfn/language-common");
|
|
81
|
+
var baseUrl = "https://app.asana.com";
|
|
82
|
+
function addAuth(headers, token) {
|
|
82
83
|
if (token) {
|
|
83
84
|
Object.assign(headers, { Authorization: `Bearer ${token}` });
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
|
-
function request(state, path, params, callback = (s) => s) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
87
|
+
function request(state, path, params = {}, callback = (s) => s) {
|
|
88
|
+
(0, import_util.assertRelativeUrl)(path);
|
|
89
|
+
const { token, apiVersion = "1.0" } = state.configuration ?? {};
|
|
90
|
+
const currentPath = (0, import_node_path.join)("/api", apiVersion, path);
|
|
91
|
+
const {
|
|
92
|
+
method = "GET",
|
|
93
|
+
headers = { accept: "application/json" },
|
|
94
|
+
...rest
|
|
95
|
+
} = params;
|
|
96
|
+
addAuth(headers, token);
|
|
91
97
|
const options = {
|
|
92
98
|
...rest,
|
|
93
99
|
headers,
|
|
94
100
|
baseUrl,
|
|
95
|
-
|
|
101
|
+
parseAs: "json"
|
|
96
102
|
};
|
|
97
|
-
return (0, import_util.request)(method,
|
|
98
|
-
(0, import_util.logResponse)(response);
|
|
99
|
-
const { body: body2, ...responseWithoutBody } = response;
|
|
100
|
-
return {
|
|
101
|
-
...(0, import_language_common.composeNextState)(state, body2 == null ? void 0 : body2.data),
|
|
102
|
-
response: responseWithoutBody
|
|
103
|
-
};
|
|
104
|
-
}).then(callback).catch((err) => {
|
|
103
|
+
return (0, import_util.request)(method, currentPath, options).then(import_util.logResponse).then(callback).catch((err) => {
|
|
105
104
|
if (err.code !== "BASE_URL_MISMATCH") {
|
|
106
105
|
console.log("Asana says:");
|
|
107
106
|
(0, import_util.logResponse)(err);
|
|
@@ -109,6 +108,41 @@ function request(state, path, params, callback = (s) => s) {
|
|
|
109
108
|
throw err;
|
|
110
109
|
});
|
|
111
110
|
}
|
|
111
|
+
var DEFAULT_PAGE_LIMIT = 100;
|
|
112
|
+
async function requestWithPagination(state, path, params = {}) {
|
|
113
|
+
var _a, _b;
|
|
114
|
+
let { body, headers, query = {}, ...rest } = params;
|
|
115
|
+
const { limit, ...restQuery } = query;
|
|
116
|
+
const options = {
|
|
117
|
+
...rest,
|
|
118
|
+
headers,
|
|
119
|
+
body,
|
|
120
|
+
query: { limit: limit ?? DEFAULT_PAGE_LIMIT, ...restQuery }
|
|
121
|
+
};
|
|
122
|
+
const results = [];
|
|
123
|
+
const didUserPassLimit = Boolean(limit);
|
|
124
|
+
let shouldFetchNextPage = false;
|
|
125
|
+
let currentPath = path;
|
|
126
|
+
do {
|
|
127
|
+
const response = await request(state, currentPath, options);
|
|
128
|
+
results.push(...(_a = response == null ? void 0 : response.body) == null ? void 0 : _a.data);
|
|
129
|
+
const nextPage = (_b = response == null ? void 0 : response.body) == null ? void 0 : _b.next_page;
|
|
130
|
+
const hasNextPage = (nextPage == null ? void 0 : nextPage.path) && (nextPage == null ? void 0 : nextPage.offset) !== void 0;
|
|
131
|
+
shouldFetchNextPage = !didUserPassLimit && hasNextPage;
|
|
132
|
+
if (shouldFetchNextPage) {
|
|
133
|
+
currentPath = nextPage.path;
|
|
134
|
+
}
|
|
135
|
+
} while (shouldFetchNextPage);
|
|
136
|
+
return results;
|
|
137
|
+
}
|
|
138
|
+
function prepareNextState(state, response) {
|
|
139
|
+
const { body, ...responseWithoutBody } = response;
|
|
140
|
+
const { data, next_page } = body ?? {};
|
|
141
|
+
return {
|
|
142
|
+
...(0, import_language_common.composeNextState)(state, data),
|
|
143
|
+
response: { next_page, ...responseWithoutBody }
|
|
144
|
+
};
|
|
145
|
+
}
|
|
112
146
|
|
|
113
147
|
// src/Adaptor.js
|
|
114
148
|
var import_language_common3 = require("@openfn/language-common");
|
|
@@ -125,59 +159,64 @@ function execute(...operations) {
|
|
|
125
159
|
};
|
|
126
160
|
}
|
|
127
161
|
function getTask(taskGid, params, callback) {
|
|
128
|
-
return (state) => {
|
|
162
|
+
return async (state) => {
|
|
129
163
|
const [resolvedTaskGid, resolvedParams] = (0, import_util2.expandReferences)(
|
|
130
164
|
state,
|
|
131
165
|
taskGid,
|
|
132
166
|
params
|
|
133
167
|
);
|
|
134
|
-
|
|
168
|
+
const response = await request(
|
|
135
169
|
state,
|
|
136
170
|
`tasks/${resolvedTaskGid}`,
|
|
137
171
|
{ query: resolvedParams },
|
|
138
172
|
callback
|
|
139
173
|
);
|
|
174
|
+
return prepareNextState(state, response);
|
|
140
175
|
};
|
|
141
176
|
}
|
|
142
177
|
function getTasks(projectGid, params, callback) {
|
|
143
|
-
return (state) => {
|
|
178
|
+
return async (state) => {
|
|
144
179
|
const [resolvedProjectGid, resolvedParams] = (0, import_util2.expandReferences)(
|
|
145
180
|
state,
|
|
146
181
|
projectGid,
|
|
147
182
|
params
|
|
148
183
|
);
|
|
149
|
-
|
|
184
|
+
const results = await requestWithPagination(
|
|
150
185
|
state,
|
|
151
186
|
`projects/${resolvedProjectGid}/tasks`,
|
|
152
187
|
{ query: resolvedParams },
|
|
153
188
|
callback
|
|
154
189
|
);
|
|
190
|
+
console.log(`Fetched ${results.length} tasks`);
|
|
191
|
+
return (0, import_language_common2.composeNextState)(state, results);
|
|
155
192
|
};
|
|
156
193
|
}
|
|
157
|
-
function updateTask(taskGid,
|
|
158
|
-
return (state) => {
|
|
159
|
-
const [resolvedTaskGid,
|
|
194
|
+
function updateTask(taskGid, data, callback) {
|
|
195
|
+
return async (state) => {
|
|
196
|
+
const [resolvedTaskGid, resolvedData] = (0, import_util2.expandReferences)(
|
|
160
197
|
state,
|
|
161
198
|
taskGid,
|
|
162
|
-
|
|
199
|
+
data
|
|
163
200
|
);
|
|
164
|
-
|
|
201
|
+
const response = await request(
|
|
165
202
|
state,
|
|
166
203
|
`tasks/${resolvedTaskGid}`,
|
|
167
|
-
{ body: { data:
|
|
204
|
+
{ body: { data: resolvedData }, method: "PUT" },
|
|
168
205
|
callback
|
|
169
206
|
);
|
|
207
|
+
return prepareNextState(state, response);
|
|
170
208
|
};
|
|
171
209
|
}
|
|
172
210
|
function createTask(params, callback) {
|
|
173
|
-
return (state) => {
|
|
211
|
+
return async (state) => {
|
|
174
212
|
const [resolvedParams] = (0, import_util2.expandReferences)(state, params);
|
|
175
|
-
|
|
213
|
+
const response = await request(
|
|
176
214
|
state,
|
|
177
215
|
"tasks",
|
|
178
216
|
{ body: { data: resolvedParams }, method: "POST" },
|
|
179
217
|
callback
|
|
180
218
|
);
|
|
219
|
+
return prepareNextState(state, response);
|
|
181
220
|
};
|
|
182
221
|
}
|
|
183
222
|
function upsertTask(projectGid, params, callback) {
|
|
@@ -187,29 +226,26 @@ function upsertTask(projectGid, params, callback) {
|
|
|
187
226
|
projectGid,
|
|
188
227
|
params
|
|
189
228
|
);
|
|
190
|
-
return
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
console.log("No matching task found. Performing create.");
|
|
205
|
-
return createTask(data, callback)(state);
|
|
206
|
-
}
|
|
229
|
+
return requestWithPagination(state, `projects/${resolvedProjectGid}/tasks`, {
|
|
230
|
+
query: { opt_fields: `${externalId}` }
|
|
231
|
+
}).then((next) => {
|
|
232
|
+
const matchingTask = next.find(
|
|
233
|
+
(task) => task[externalId] === data[externalId]
|
|
234
|
+
);
|
|
235
|
+
if (matchingTask) {
|
|
236
|
+
console.log("Matching task found. Performing update.");
|
|
237
|
+
console.log("Data to update", data);
|
|
238
|
+
const { projects, workspace, ...remainingData } = data;
|
|
239
|
+
return updateTask(matchingTask.gid, remainingData, callback)(state);
|
|
240
|
+
} else {
|
|
241
|
+
console.log("No matching task found. Performing create.");
|
|
242
|
+
return createTask(data, callback)(state);
|
|
207
243
|
}
|
|
208
|
-
);
|
|
244
|
+
});
|
|
209
245
|
};
|
|
210
246
|
}
|
|
211
247
|
function createTaskStory(taskGid, params, callback) {
|
|
212
|
-
return (state) => {
|
|
248
|
+
return async (state) => {
|
|
213
249
|
const [
|
|
214
250
|
resolvedTaskGid,
|
|
215
251
|
{
|
|
@@ -222,7 +258,7 @@ function createTaskStory(taskGid, params, callback) {
|
|
|
222
258
|
}
|
|
223
259
|
] = (0, import_util2.expandReferences)(state, taskGid, params);
|
|
224
260
|
const story = { text, html_text, is_pinned, sticker_name };
|
|
225
|
-
|
|
261
|
+
const response = await request(
|
|
226
262
|
state,
|
|
227
263
|
`tasks/${resolvedTaskGid}/stories`,
|
|
228
264
|
{
|
|
@@ -232,22 +268,24 @@ function createTaskStory(taskGid, params, callback) {
|
|
|
232
268
|
},
|
|
233
269
|
callback
|
|
234
270
|
);
|
|
271
|
+
return prepareNextState(state, response);
|
|
235
272
|
};
|
|
236
273
|
}
|
|
237
274
|
function request2(path, params = {}, callback) {
|
|
238
|
-
return (state) => {
|
|
275
|
+
return async (state) => {
|
|
239
276
|
const [resolvedPath, resolvedParams] = (0, import_util2.expandReferences)(
|
|
240
277
|
state,
|
|
241
278
|
path,
|
|
242
279
|
params
|
|
243
280
|
);
|
|
244
|
-
const { body
|
|
245
|
-
|
|
281
|
+
const { body, query, method } = resolvedParams;
|
|
282
|
+
const response = await request(
|
|
246
283
|
state,
|
|
247
284
|
resolvedPath,
|
|
248
285
|
{ method, body, query },
|
|
249
286
|
callback
|
|
250
287
|
);
|
|
288
|
+
return prepareNextState(state, response);
|
|
251
289
|
};
|
|
252
290
|
}
|
|
253
291
|
|
package/dist/index.js
CHANGED
|
@@ -30,40 +30,43 @@ __export(Adaptor_exports, {
|
|
|
30
30
|
updateTask: () => updateTask,
|
|
31
31
|
upsertTask: () => upsertTask
|
|
32
32
|
});
|
|
33
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
execute as commonExecute,
|
|
35
|
+
composeNextState as composeNextState2
|
|
36
|
+
} from "@openfn/language-common";
|
|
34
37
|
import { expandReferences } from "@openfn/language-common/util";
|
|
35
38
|
|
|
36
|
-
// src/
|
|
37
|
-
import { composeNextState } from "@openfn/language-common";
|
|
39
|
+
// src/util.js
|
|
38
40
|
import {
|
|
39
41
|
request as commonRequest,
|
|
40
|
-
logResponse
|
|
42
|
+
logResponse,
|
|
43
|
+
assertRelativeUrl
|
|
41
44
|
} from "@openfn/language-common/util";
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
import { join } from "path";
|
|
46
|
+
import { composeNextState } from "@openfn/language-common";
|
|
47
|
+
var baseUrl = "https://app.asana.com";
|
|
48
|
+
function addAuth(headers, token) {
|
|
44
49
|
if (token) {
|
|
45
50
|
Object.assign(headers, { Authorization: `Bearer ${token}` });
|
|
46
51
|
}
|
|
47
52
|
}
|
|
48
|
-
function request(state, path, params, callback = (s) => s) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
+
function request(state, path, params = {}, callback = (s) => s) {
|
|
54
|
+
assertRelativeUrl(path);
|
|
55
|
+
const { token, apiVersion = "1.0" } = state.configuration ?? {};
|
|
56
|
+
const currentPath = join("/api", apiVersion, path);
|
|
57
|
+
const {
|
|
58
|
+
method = "GET",
|
|
59
|
+
headers = { accept: "application/json" },
|
|
60
|
+
...rest
|
|
61
|
+
} = params;
|
|
62
|
+
addAuth(headers, token);
|
|
53
63
|
const options = {
|
|
54
64
|
...rest,
|
|
55
65
|
headers,
|
|
56
66
|
baseUrl,
|
|
57
|
-
|
|
67
|
+
parseAs: "json"
|
|
58
68
|
};
|
|
59
|
-
return commonRequest(method,
|
|
60
|
-
logResponse(response);
|
|
61
|
-
const { body: body2, ...responseWithoutBody } = response;
|
|
62
|
-
return {
|
|
63
|
-
...composeNextState(state, body2 == null ? void 0 : body2.data),
|
|
64
|
-
response: responseWithoutBody
|
|
65
|
-
};
|
|
66
|
-
}).then(callback).catch((err) => {
|
|
69
|
+
return commonRequest(method, currentPath, options).then(logResponse).then(callback).catch((err) => {
|
|
67
70
|
if (err.code !== "BASE_URL_MISMATCH") {
|
|
68
71
|
console.log("Asana says:");
|
|
69
72
|
logResponse(err);
|
|
@@ -71,6 +74,41 @@ function request(state, path, params, callback = (s) => s) {
|
|
|
71
74
|
throw err;
|
|
72
75
|
});
|
|
73
76
|
}
|
|
77
|
+
var DEFAULT_PAGE_LIMIT = 100;
|
|
78
|
+
async function requestWithPagination(state, path, params = {}) {
|
|
79
|
+
var _a, _b;
|
|
80
|
+
let { body, headers, query = {}, ...rest } = params;
|
|
81
|
+
const { limit, ...restQuery } = query;
|
|
82
|
+
const options = {
|
|
83
|
+
...rest,
|
|
84
|
+
headers,
|
|
85
|
+
body,
|
|
86
|
+
query: { limit: limit ?? DEFAULT_PAGE_LIMIT, ...restQuery }
|
|
87
|
+
};
|
|
88
|
+
const results = [];
|
|
89
|
+
const didUserPassLimit = Boolean(limit);
|
|
90
|
+
let shouldFetchNextPage = false;
|
|
91
|
+
let currentPath = path;
|
|
92
|
+
do {
|
|
93
|
+
const response = await request(state, currentPath, options);
|
|
94
|
+
results.push(...(_a = response == null ? void 0 : response.body) == null ? void 0 : _a.data);
|
|
95
|
+
const nextPage = (_b = response == null ? void 0 : response.body) == null ? void 0 : _b.next_page;
|
|
96
|
+
const hasNextPage = (nextPage == null ? void 0 : nextPage.path) && (nextPage == null ? void 0 : nextPage.offset) !== void 0;
|
|
97
|
+
shouldFetchNextPage = !didUserPassLimit && hasNextPage;
|
|
98
|
+
if (shouldFetchNextPage) {
|
|
99
|
+
currentPath = nextPage.path;
|
|
100
|
+
}
|
|
101
|
+
} while (shouldFetchNextPage);
|
|
102
|
+
return results;
|
|
103
|
+
}
|
|
104
|
+
function prepareNextState(state, response) {
|
|
105
|
+
const { body, ...responseWithoutBody } = response;
|
|
106
|
+
const { data, next_page } = body ?? {};
|
|
107
|
+
return {
|
|
108
|
+
...composeNextState(state, data),
|
|
109
|
+
response: { next_page, ...responseWithoutBody }
|
|
110
|
+
};
|
|
111
|
+
}
|
|
74
112
|
|
|
75
113
|
// src/Adaptor.js
|
|
76
114
|
import {
|
|
@@ -102,59 +140,64 @@ function execute(...operations) {
|
|
|
102
140
|
};
|
|
103
141
|
}
|
|
104
142
|
function getTask(taskGid, params, callback) {
|
|
105
|
-
return (state) => {
|
|
143
|
+
return async (state) => {
|
|
106
144
|
const [resolvedTaskGid, resolvedParams] = expandReferences(
|
|
107
145
|
state,
|
|
108
146
|
taskGid,
|
|
109
147
|
params
|
|
110
148
|
);
|
|
111
|
-
|
|
149
|
+
const response = await request(
|
|
112
150
|
state,
|
|
113
151
|
`tasks/${resolvedTaskGid}`,
|
|
114
152
|
{ query: resolvedParams },
|
|
115
153
|
callback
|
|
116
154
|
);
|
|
155
|
+
return prepareNextState(state, response);
|
|
117
156
|
};
|
|
118
157
|
}
|
|
119
158
|
function getTasks(projectGid, params, callback) {
|
|
120
|
-
return (state) => {
|
|
159
|
+
return async (state) => {
|
|
121
160
|
const [resolvedProjectGid, resolvedParams] = expandReferences(
|
|
122
161
|
state,
|
|
123
162
|
projectGid,
|
|
124
163
|
params
|
|
125
164
|
);
|
|
126
|
-
|
|
165
|
+
const results = await requestWithPagination(
|
|
127
166
|
state,
|
|
128
167
|
`projects/${resolvedProjectGid}/tasks`,
|
|
129
168
|
{ query: resolvedParams },
|
|
130
169
|
callback
|
|
131
170
|
);
|
|
171
|
+
console.log(`Fetched ${results.length} tasks`);
|
|
172
|
+
return composeNextState2(state, results);
|
|
132
173
|
};
|
|
133
174
|
}
|
|
134
|
-
function updateTask(taskGid,
|
|
135
|
-
return (state) => {
|
|
136
|
-
const [resolvedTaskGid,
|
|
175
|
+
function updateTask(taskGid, data, callback) {
|
|
176
|
+
return async (state) => {
|
|
177
|
+
const [resolvedTaskGid, resolvedData] = expandReferences(
|
|
137
178
|
state,
|
|
138
179
|
taskGid,
|
|
139
|
-
|
|
180
|
+
data
|
|
140
181
|
);
|
|
141
|
-
|
|
182
|
+
const response = await request(
|
|
142
183
|
state,
|
|
143
184
|
`tasks/${resolvedTaskGid}`,
|
|
144
|
-
{ body: { data:
|
|
185
|
+
{ body: { data: resolvedData }, method: "PUT" },
|
|
145
186
|
callback
|
|
146
187
|
);
|
|
188
|
+
return prepareNextState(state, response);
|
|
147
189
|
};
|
|
148
190
|
}
|
|
149
191
|
function createTask(params, callback) {
|
|
150
|
-
return (state) => {
|
|
192
|
+
return async (state) => {
|
|
151
193
|
const [resolvedParams] = expandReferences(state, params);
|
|
152
|
-
|
|
194
|
+
const response = await request(
|
|
153
195
|
state,
|
|
154
196
|
"tasks",
|
|
155
197
|
{ body: { data: resolvedParams }, method: "POST" },
|
|
156
198
|
callback
|
|
157
199
|
);
|
|
200
|
+
return prepareNextState(state, response);
|
|
158
201
|
};
|
|
159
202
|
}
|
|
160
203
|
function upsertTask(projectGid, params, callback) {
|
|
@@ -164,29 +207,26 @@ function upsertTask(projectGid, params, callback) {
|
|
|
164
207
|
projectGid,
|
|
165
208
|
params
|
|
166
209
|
);
|
|
167
|
-
return
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
console.log("No matching task found. Performing create.");
|
|
182
|
-
return createTask(data, callback)(state);
|
|
183
|
-
}
|
|
210
|
+
return requestWithPagination(state, `projects/${resolvedProjectGid}/tasks`, {
|
|
211
|
+
query: { opt_fields: `${externalId}` }
|
|
212
|
+
}).then((next) => {
|
|
213
|
+
const matchingTask = next.find(
|
|
214
|
+
(task) => task[externalId] === data[externalId]
|
|
215
|
+
);
|
|
216
|
+
if (matchingTask) {
|
|
217
|
+
console.log("Matching task found. Performing update.");
|
|
218
|
+
console.log("Data to update", data);
|
|
219
|
+
const { projects, workspace, ...remainingData } = data;
|
|
220
|
+
return updateTask(matchingTask.gid, remainingData, callback)(state);
|
|
221
|
+
} else {
|
|
222
|
+
console.log("No matching task found. Performing create.");
|
|
223
|
+
return createTask(data, callback)(state);
|
|
184
224
|
}
|
|
185
|
-
);
|
|
225
|
+
});
|
|
186
226
|
};
|
|
187
227
|
}
|
|
188
228
|
function createTaskStory(taskGid, params, callback) {
|
|
189
|
-
return (state) => {
|
|
229
|
+
return async (state) => {
|
|
190
230
|
const [
|
|
191
231
|
resolvedTaskGid,
|
|
192
232
|
{
|
|
@@ -199,7 +239,7 @@ function createTaskStory(taskGid, params, callback) {
|
|
|
199
239
|
}
|
|
200
240
|
] = expandReferences(state, taskGid, params);
|
|
201
241
|
const story = { text, html_text, is_pinned, sticker_name };
|
|
202
|
-
|
|
242
|
+
const response = await request(
|
|
203
243
|
state,
|
|
204
244
|
`tasks/${resolvedTaskGid}/stories`,
|
|
205
245
|
{
|
|
@@ -209,22 +249,24 @@ function createTaskStory(taskGid, params, callback) {
|
|
|
209
249
|
},
|
|
210
250
|
callback
|
|
211
251
|
);
|
|
252
|
+
return prepareNextState(state, response);
|
|
212
253
|
};
|
|
213
254
|
}
|
|
214
255
|
function request2(path, params = {}, callback) {
|
|
215
|
-
return (state) => {
|
|
256
|
+
return async (state) => {
|
|
216
257
|
const [resolvedPath, resolvedParams] = expandReferences(
|
|
217
258
|
state,
|
|
218
259
|
path,
|
|
219
260
|
params
|
|
220
261
|
);
|
|
221
|
-
const { body
|
|
222
|
-
|
|
262
|
+
const { body, query, method } = resolvedParams;
|
|
263
|
+
const response = await request(
|
|
223
264
|
state,
|
|
224
265
|
resolvedPath,
|
|
225
266
|
{ method, body, query },
|
|
226
267
|
callback
|
|
227
268
|
);
|
|
269
|
+
return prepareNextState(state, response);
|
|
228
270
|
};
|
|
229
271
|
}
|
|
230
272
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfn/language-asana",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
|
+
"label": "Asana",
|
|
4
5
|
"description": "An adaptor to access objects in Asana",
|
|
5
6
|
"homepage": "https://docs.openfn.org",
|
|
6
7
|
"repository": {
|
|
@@ -24,14 +25,12 @@
|
|
|
24
25
|
"configuration-schema.json"
|
|
25
26
|
],
|
|
26
27
|
"dependencies": {
|
|
27
|
-
"@openfn/language-common": "2.
|
|
28
|
+
"@openfn/language-common": "2.4.0"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"assertion-error": "2.0.0",
|
|
31
|
-
"chai": "
|
|
32
|
+
"chai": "^5.2.0",
|
|
32
33
|
"deep-eql": "4.1.1",
|
|
33
|
-
"esno": "^0.16.3",
|
|
34
|
-
"nock": "13.2.9",
|
|
35
34
|
"rimraf": "3.0.2"
|
|
36
35
|
},
|
|
37
36
|
"type": "module",
|
|
@@ -39,8 +38,9 @@
|
|
|
39
38
|
"main": "dist/index.cjs",
|
|
40
39
|
"scripts": {
|
|
41
40
|
"build": "pnpm clean && build-adaptor asana",
|
|
42
|
-
"test": "mocha --experimental-specifier-resolution=node --no-warnings",
|
|
43
|
-
"test:watch": "mocha -w --experimental-specifier-resolution=node --no-warnings",
|
|
41
|
+
"test": "mocha --experimental-specifier-resolution=node --no-warnings --exclude test/integration.js --recursive",
|
|
42
|
+
"test:watch": "mocha -w --experimental-specifier-resolution=node --no-warnings --exclude test/integration.js --recursive",
|
|
43
|
+
"test:integration": "mocha --experimental-specifier-resolution=node --no-warnings test/integration.js",
|
|
44
44
|
"clean": "rimraf dist types docs",
|
|
45
45
|
"pack": "pnpm pack --pack-destination ../../dist",
|
|
46
46
|
"lint": "eslint src"
|
package/types/Adaptor.d.ts
CHANGED
|
@@ -14,35 +14,48 @@ export function execute(...operations: Operations): Operation;
|
|
|
14
14
|
/**
|
|
15
15
|
* Get a single task of a given project.
|
|
16
16
|
* @public
|
|
17
|
-
* @example
|
|
17
|
+
* @example <caption>Get a task</caption>
|
|
18
18
|
* getTask("1206933955023739", {
|
|
19
19
|
* opt_fields: "name,notes,assignee",
|
|
20
20
|
* });
|
|
21
21
|
* @function
|
|
22
22
|
* @param {string} taskGid - Globally unique identifier for the task
|
|
23
23
|
* @param {object} params - Query params to include.
|
|
24
|
+
* @param {string} params.opt_fields - The fields to return.
|
|
24
25
|
* @param {function} callback - (Optional) callback function
|
|
25
26
|
* @returns {Operation}
|
|
26
27
|
*/
|
|
27
|
-
export function getTask(taskGid: string, params:
|
|
28
|
+
export function getTask(taskGid: string, params: {
|
|
29
|
+
opt_fields: string;
|
|
30
|
+
}, callback: Function): Operation;
|
|
28
31
|
/**
|
|
29
32
|
* Get the list of tasks for a given project.
|
|
30
33
|
* @public
|
|
31
|
-
* @example
|
|
34
|
+
* @example <caption>Get all tasks</caption>
|
|
35
|
+
* getTasks("1206933955023739", {
|
|
36
|
+
* opt_fields: "name,notes,assignee",
|
|
37
|
+
* });
|
|
38
|
+
* @example <caption>Limit the number of tasks returned</caption>
|
|
32
39
|
* getTasks("1206933955023739", {
|
|
33
40
|
* opt_fields: "name,notes,assignee",
|
|
41
|
+
* limit: 100,
|
|
34
42
|
* });
|
|
35
43
|
* @function
|
|
36
44
|
* @param {string} projectGid - Globally unique identifier for the project
|
|
37
45
|
* @param {object} params - Query params to include.
|
|
46
|
+
* @param {number} params.limit - The maximum number of tasks to return.
|
|
47
|
+
* @param {string} params.opt_fields - The fields to return.
|
|
38
48
|
* @param {function} callback - (Optional) callback function
|
|
39
49
|
* @returns {Operation}
|
|
40
50
|
*/
|
|
41
|
-
export function getTasks(projectGid: string, params:
|
|
51
|
+
export function getTasks(projectGid: string, params: {
|
|
52
|
+
limit: number;
|
|
53
|
+
opt_fields: string;
|
|
54
|
+
}, callback: Function): Operation;
|
|
42
55
|
/**
|
|
43
56
|
* Update a specific task.
|
|
44
57
|
* @public
|
|
45
|
-
* @example
|
|
58
|
+
* @example <caption>Update a task</caption>
|
|
46
59
|
* updateTask("1206933955023739", {
|
|
47
60
|
* name: "test",
|
|
48
61
|
* approval_status: "pending",
|
|
@@ -50,11 +63,11 @@ export function getTasks(projectGid: string, params: object, callback: Function)
|
|
|
50
63
|
* });
|
|
51
64
|
* @function
|
|
52
65
|
* @param {string} taskGid - Globally unique identifier for the task
|
|
53
|
-
* @param {object}
|
|
66
|
+
* @param {object} data - Body data to update the task with
|
|
54
67
|
* @param {function} callback - (Optional) callback function
|
|
55
68
|
* @returns {Operation}
|
|
56
69
|
*/
|
|
57
|
-
export function updateTask(taskGid: string,
|
|
70
|
+
export function updateTask(taskGid: string, data: object, callback: Function): Operation;
|
|
58
71
|
/**
|
|
59
72
|
* Create a task.
|
|
60
73
|
* @public
|
|
@@ -74,7 +87,7 @@ export function createTask(params: object, callback: Function): Operation;
|
|
|
74
87
|
/**
|
|
75
88
|
* Update or create a task.
|
|
76
89
|
* @public
|
|
77
|
-
* @example
|
|
90
|
+
* @example <caption>Upsert a task</caption>
|
|
78
91
|
* upsertTask("1201382240880", {
|
|
79
92
|
* externalId: "name",
|
|
80
93
|
* data: {
|
|
@@ -87,10 +100,15 @@ export function createTask(params: object, callback: Function): Operation;
|
|
|
87
100
|
* @function
|
|
88
101
|
* @param {string} projectGid - Globally unique identifier for the project
|
|
89
102
|
* @param {object} params - an object with an externalId and some task data.
|
|
103
|
+
* @param {string} params.externalId - The external id field name
|
|
104
|
+
* @param {object} params.data - The data to upsert.
|
|
90
105
|
* @param {function} callback - (Optional) callback function
|
|
91
106
|
* @returns {Operation}
|
|
92
107
|
*/
|
|
93
|
-
export function upsertTask(projectGid: string, params:
|
|
108
|
+
export function upsertTask(projectGid: string, params: {
|
|
109
|
+
externalId: string;
|
|
110
|
+
data: object;
|
|
111
|
+
}, callback: Function): Operation;
|
|
94
112
|
/**
|
|
95
113
|
* Options provided to the createTaskStory request
|
|
96
114
|
* @typedef {Object} StoryOptions
|
package/types/util.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export function addAuth(headers: any, token: any): void;
|
|
2
|
+
export function request(state: any, path: any, params?: {}, callback?: (s: any) => any): any;
|
|
3
|
+
export function requestWithPagination(state: any, path: any, params?: {}): Promise<any[]>;
|
|
4
|
+
export function prepareNextState(state: any, response: any): any;
|
|
5
|
+
export const DEFAULT_PAGE_LIMIT: 100;
|
package/types/Utils.d.ts
DELETED