mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(KoboToolbox Node): Improve attachment matching logic and GeoJSON Polygon format (#3535)
* Fix query,sort + use question name in attachments * Change Menu structure * kobo: Clearer webhook name * [kobo]: fix when no json filter * Fix ambiguous attachment matching + GeoJSON Polygon format * Fix kobo function * Fix extra descriptions * Add credentials injection and testing * Fix credential injection and lint issues Co-authored-by: Yann Jouanique <yann.jouanique@oneacrefund.org> Co-authored-by: Yann Jouanique <yann.jouanique@gmail.com> Co-authored-by: Omar Ajoue <krynble@gmail.com> Co-authored-by: Jan Oberhauser <janober@users.noreply.github.com>
This commit is contained in:
parent
725d122da7
commit
637e81552f
|
@ -1,4 +1,6 @@
|
||||||
import {
|
import {
|
||||||
|
IAuthenticateGeneric,
|
||||||
|
ICredentialTestRequest,
|
||||||
ICredentialType,
|
ICredentialType,
|
||||||
NodePropertyTypes,
|
NodePropertyTypes,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
@ -23,4 +25,20 @@ export class KoBoToolboxApi implements ICredentialType {
|
||||||
hint: 'You can get your API token at https://[api-root]/token/?format=json (for a logged in user)',
|
hint: 'You can get your API token at https://[api-root]/token/?format=json (for a logged in user)',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
authenticate = {
|
||||||
|
type: 'generic',
|
||||||
|
properties: {
|
||||||
|
headers: {
|
||||||
|
Authorization: '=Token {{$credentials.token}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as IAuthenticateGeneric;
|
||||||
|
|
||||||
|
test: ICredentialTestRequest = {
|
||||||
|
request: {
|
||||||
|
baseURL: '={{$credentials.URL}}',
|
||||||
|
url: '/api/v2/assets/',
|
||||||
|
method: 'GET',
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ export async function koBoToolboxApiRequest(this: IExecuteFunctions | IWebhookFu
|
||||||
url: '',
|
url: '',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
'Authorization': `Token ${credentials.token}`,
|
|
||||||
},
|
},
|
||||||
json: true,
|
json: true,
|
||||||
};
|
};
|
||||||
|
@ -44,7 +43,7 @@ export async function koBoToolboxApiRequest(this: IExecuteFunctions | IWebhookFu
|
||||||
let results = null;
|
let results = null;
|
||||||
let keepLooking = true;
|
let keepLooking = true;
|
||||||
while (keepLooking) {
|
while (keepLooking) {
|
||||||
const response = await this.helpers.httpRequest(options);
|
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'koBoToolboxApi', options);
|
||||||
// Append or set results
|
// Append or set results
|
||||||
results = response.results ? _.concat(results || [], response.results) : response;
|
results = response.results ? _.concat(results || [], response.results) : response;
|
||||||
if (returnAll && response.next) {
|
if (returnAll && response.next) {
|
||||||
|
@ -106,7 +105,7 @@ const formatValue = (value: any, format: string): any => { //tslint:disable-line
|
||||||
return _.first(points) === _.last(points)
|
return _.first(points) === _.last(points)
|
||||||
? {
|
? {
|
||||||
type: 'Polygon',
|
type: 'Polygon',
|
||||||
coordinates: [coordinates]
|
coordinates: [coordinates],
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
type: 'LineString',
|
type: 'LineString',
|
||||||
|
@ -183,12 +182,12 @@ export async function downloadAttachments(this: IExecuteFunctions | IWebhookFunc
|
||||||
|
|
||||||
let relatedQuestion = null;
|
let relatedQuestion = null;
|
||||||
if('question' === options.binaryNamingScheme) {
|
if('question' === options.binaryNamingScheme) {
|
||||||
for(let question of Object.keys(submission)) {
|
for(const question of Object.keys(submission)) {
|
||||||
// The logic to map attachments to question is sometimes ambiguous:
|
// The logic to map attachments to question is sometimes ambiguous:
|
||||||
// - If the attachment is linked to a question, the question's value is the same as the attachment's filename (with spaces replaced by underscores)
|
// - If the attachment is linked to a question, the question's value is the same as the attachment's filename (with spaces replaced by underscores)
|
||||||
// - BUT sometimes the attachment's filename has an extra suffix, e.g. "My_Picture_0OdlaKJ.jpg", would map to the question "picture": "My Picture.jpg"
|
// - BUT sometimes the attachment's filename has an extra suffix, e.g. "My_Picture_0OdlaKJ.jpg", would map to the question "picture": "My Picture.jpg"
|
||||||
const sanitizedQuestionValue = _.toString(submission[question]).replace(/\s/g, '_'); // replace spaces with underscores
|
const sanitizedQuestionValue = _.toString(submission[question]).replace(/\s/g, '_'); // replace spaces with underscores
|
||||||
if (sanitizedFileName == sanitizedQuestionValue) {
|
if (sanitizedFileName === sanitizedQuestionValue) {
|
||||||
relatedQuestion = question;
|
relatedQuestion = question;
|
||||||
// Just use the first match...
|
// Just use the first match...
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -55,7 +55,6 @@ export class KoBoToolbox implements INodeType {
|
||||||
{
|
{
|
||||||
name: 'koBoToolboxApi',
|
name: 'koBoToolboxApi',
|
||||||
required: true,
|
required: true,
|
||||||
testedBy: 'koBoToolboxApiCredentialTest',
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
properties: [
|
properties: [
|
||||||
|
@ -91,41 +90,6 @@ export class KoBoToolbox implements INodeType {
|
||||||
};
|
};
|
||||||
|
|
||||||
methods = {
|
methods = {
|
||||||
credentialTest: {
|
|
||||||
async koBoToolboxApiCredentialTest(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise<INodeCredentialTestResult> {
|
|
||||||
const credentials = credential.data;
|
|
||||||
try {
|
|
||||||
const response = await this.helpers.request({
|
|
||||||
url: `${credentials!.URL}/api/v2/assets/hash`,
|
|
||||||
headers: {
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': `Token ${credentials!.token}`,
|
|
||||||
},
|
|
||||||
json: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.hash) {
|
|
||||||
return {
|
|
||||||
status: 'OK',
|
|
||||||
message: 'Connection successful!',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return {
|
|
||||||
status: 'Error',
|
|
||||||
message: `Credentials are not valid. Response: ${response.detail}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return {
|
|
||||||
status: 'Error',
|
|
||||||
message: `Credentials validation failed: ${(err as JsonObject).message}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
loadOptions: {
|
loadOptions: {
|
||||||
loadForms,
|
loadForms,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue