fix(KoBoToolbox Node): Fix query and sort + use question name in attachments (#3017)

* Fix query,sort + use question name in attachments

* Change Menu structure

* kobo: Clearer webhook name

* [kobo]: fix when no json filter
This commit is contained in:
Yann Jouanique 2022-05-14 11:20:45 +02:00 committed by GitHub
parent a7d960c561
commit c885115768
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 165 additions and 33 deletions

View file

@ -173,10 +173,14 @@ export async function downloadAttachments(this: IExecuteFunctions | IWebhookFunc
for (const [index, attachment] of attachmentList.entries()) { for (const [index, attachment] of attachmentList.entries()) {
// look for the question name linked to this attachment // look for the question name linked to this attachment
const filename = attachment.filename; const filename = attachment.filename;
Object.keys(submission).forEach(question => { let relatedQuestion = null;
if (filename.endsWith('/' + _.toString(submission[question]).replace(/\s/g, '_'))) { if('question' === options.binaryNamingScheme) {
} Object.keys(submission).forEach(question => {
}); if (filename.endsWith('/' + _.toString(submission[question]).replace(/\s/g, '_'))) {
relatedQuestion = question;
}
});
}
// Download attachment // Download attachment
// NOTE: this needs to follow redirects (possibly across domains), while keeping Authorization headers // NOTE: this needs to follow redirects (possibly across domains), while keeping Authorization headers
@ -209,11 +213,18 @@ export async function downloadAttachments(this: IExecuteFunctions | IWebhookFunc
} }
} }
const dataPropertyAttachmentsPrefixName = options.dataPropertyAttachmentsPrefixName || 'attachment_';
const fileName = filename.split('/').pop();
if (response && response.body) { if (response && response.body) {
binaryItem.binary![`${dataPropertyAttachmentsPrefixName}${index}`] = await this.helpers.prepareBinaryData(response.body, fileName); // Use the provided prefix if any, otherwise try to use the original question name
let binaryName;
if('question' === options.binaryNamingScheme && relatedQuestion) {
binaryName = relatedQuestion;
}
else {
binaryName = `${options.dataPropertyAttachmentsPrefixName || 'attachment_'}${index}`;
}
const fileName = filename.split('/').pop();
binaryItem.binary![binaryName] = await this.helpers.prepareBinaryData(response.body, fileName);
} }
} }
} else { } else {

View file

@ -194,13 +194,14 @@ export class KoBoToolbox implements INodeType {
// ---------------------------------- // ----------------------------------
const submissionQueryOptions = this.getNodeParameter('options', i) as IDataObject; const submissionQueryOptions = this.getNodeParameter('options', i) as IDataObject;
const filterJson = this.getNodeParameter('filterJson', i, null) as string;
responseData = await koBoToolboxApiRequest.call(this, { responseData = await koBoToolboxApiRequest.call(this, {
url: `/api/v2/assets/${formId}/data/`, url: `/api/v2/assets/${formId}/data/`,
qs: { qs: {
limit: this.getNodeParameter('limit', i, 1000) as number, limit: this.getNodeParameter('limit', i, 1000) as number,
...(submissionQueryOptions.query && { query: submissionQueryOptions.query }), ...(filterJson && { query: filterJson }),
//...(submissionQueryOptions.sort && { sort: submissionQueryOptions.sort }), ...(submissionQueryOptions.sort && { sort: submissionQueryOptions.sort }),
...(submissionQueryOptions.fields && { fields: JSON.stringify(parseStringList(submissionQueryOptions.fields as string)) }), ...(submissionQueryOptions.fields && { fields: JSON.stringify(parseStringList(submissionQueryOptions.fields as string)) }),
}, },
scroll: this.getNodeParameter('returnAll', i) as boolean, scroll: this.getNodeParameter('returnAll', i) as boolean,

View file

@ -16,7 +16,7 @@ import {
} from './GenericFunctions'; } from './GenericFunctions';
import { import {
options, options,
} from './Options'; } from './Options';
export class KoBoToolboxTrigger implements INodeType { export class KoBoToolboxTrigger implements INodeType {
@ -98,13 +98,14 @@ export class KoBoToolboxTrigger implements INodeType {
async create(this: IHookFunctions): Promise<boolean> { async create(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node'); const webhookData = this.getWorkflowStaticData('node');
const webhookUrl = this.getNodeWebhookUrl('default'); const webhookUrl = this.getNodeWebhookUrl('default');
const workflow = this.getWorkflow();
const formId = this.getNodeParameter('formId') as string; //tslint:disable-line:variable-name const formId = this.getNodeParameter('formId') as string; //tslint:disable-line:variable-name
const response = await koBoToolboxApiRequest.call(this, { const response = await koBoToolboxApiRequest.call(this, {
method: 'POST', method: 'POST',
url: `/api/v2/assets/${formId}/hooks/`, url: `/api/v2/assets/${formId}/hooks/`,
body: { body: {
name: `n8n-webhook:${webhookUrl}`, name: `n8n webhook id ${workflow.id}: ${workflow.name}`,
endpoint: webhookUrl, endpoint: webhookUrl,
email_notification: true, email_notification: true,
}, },

View file

@ -9,6 +9,36 @@ export const options = {
type: 'collection', type: 'collection',
default: {}, default: {},
options: [ options: [
{
displayName: 'Download Attachments',
name: 'download',
type: 'boolean',
default: false,
description: 'Download submitted attachments',
},
{
displayName: 'Attachments Naming Scheme',
name: 'binaryNamingScheme',
type: 'options',
default: 'sequence',
displayOptions: {
show: {
download: [
true,
],
},
},
options: [
{
name: 'Sequence (e.g. attachment_N)',
value: 'sequence',
},
{
name: 'Use Original Form Question ID',
value: 'question',
},
],
},
{ {
displayName: 'Attachments Prefix', displayName: 'Attachments Prefix',
name: 'dataPropertyAttachmentsPrefixName', name: 'dataPropertyAttachmentsPrefixName',
@ -18,18 +48,14 @@ export const options = {
download: [ download: [
true, true,
], ],
binaryNamingScheme: [
'sequence',
],
}, },
}, },
default: 'attachment_', default: 'attachment_',
description: 'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"', description: 'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"',
}, },
{
displayName: 'Download Attachments',
name: 'download',
type: 'boolean',
default: false,
description: 'Download submitted attachments',
},
{ {
displayName: 'File Size', displayName: 'File Size',
name: 'version', name: 'version',

View file

@ -192,6 +192,73 @@ export const submissionFields: INodeProperties[] = [
default: 100, default: 100,
description: 'Max number of results to return', description: 'Max number of results to return',
}, },
{
displayName: 'Filter',
name: 'filterType',
type: 'options',
default: 'none',
displayOptions: {
show: {
resource: [
'submission',
],
operation: [
'getAll',
],
},
},
options: [
{
name: 'None',
value: 'none',
},
{
name: 'JSON',
value: 'json',
},
],
},
{
displayName: 'See <a href="https://github.com/SEL-Columbia/formhub/wiki/Formhub-Access-Points-(API)#api-parameters" target="_blank">Formhub API docs</a> to creating filters, using the MongoDB JSON format - e.g. {"_submission_time":{"$lt":"2021-10-01T01:02:03"}}',
name: 'jsonNotice',
type: 'notice',
displayOptions: {
show: {
resource: [
'submission',
],
operation: [
'getAll',
],
filterType: [
'json',
],
},
},
default: '',
},
{
displayName: 'Filters (JSON)',
name: 'filterJson',
type: 'string',
default: '',
typeOptions: {
// alwaysOpenEditWindow: true,
},
displayOptions: {
show: {
resource: [
'submission',
],
operation: [
'getAll',
],
filterType: [
'json',
],
},
},
},
{ {
displayName: 'Options', displayName: 'Options',
name: 'options', name: 'options',
@ -210,6 +277,36 @@ export const submissionFields: INodeProperties[] = [
default: {}, default: {},
placeholder: 'Add Option', placeholder: 'Add Option',
options: [ options: [
{
displayName: 'Download Attachments',
name: 'download',
type: 'boolean',
default: false,
description: 'Download submitted attachments',
},
{
displayName: 'Attachments Naming Scheme',
name: 'binaryNamingScheme',
type: 'options',
default: 'sequence',
displayOptions: {
show: {
download: [
true,
],
},
},
options: [
{
name: 'Sequence (e.g. attachment_N)',
value: 'sequence',
},
{
name: 'Use Original Form Question ID',
value: 'question',
},
],
},
{ {
displayName: 'Attachments Prefix', displayName: 'Attachments Prefix',
name: 'dataPropertyAttachmentsPrefixName', name: 'dataPropertyAttachmentsPrefixName',
@ -219,18 +316,14 @@ export const submissionFields: INodeProperties[] = [
download: [ download: [
true, true,
], ],
binaryNamingScheme: [
'sequence',
],
}, },
}, },
default: 'attachment_', default: 'attachment_',
description: 'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"', description: 'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"',
}, },
{
displayName: 'Download Attachments',
name: 'download',
type: 'boolean',
default: false,
description: 'Download submitted attachments',
},
{ {
displayName: 'Fields to Retrieve', displayName: 'Fields to Retrieve',
name: 'fields', name: 'fields',
@ -291,13 +384,13 @@ export const submissionFields: INodeProperties[] = [
default: false, default: false,
description: 'Apply some reformatting to the submission data, such as parsing GeoJSON coordinates', description: 'Apply some reformatting to the submission data, such as parsing GeoJSON coordinates',
}, },
// { {
// displayName: 'Sort', displayName: 'Sort',
// name: 'sort', name: 'sort',
// type: 'json', type: 'json',
// default: '', default: '',
// description: 'Sort predicates, in Mongo JSON format (e.g. {"_submission_time":1})', description: 'Sort predicates, in MongoDB JSON format (e.g. {"_submission_time":1})',
// }, },
], ],
}, },
]; ];