-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #259 from adhocteam/dcloud/TTAHUB-35-download-ar-a…
…s-csv [TTAHUB 35]: Download Activity Reports as csv files
- Loading branch information
Showing
11 changed files
with
698 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
get: | ||
tags: | ||
- activity-reports | ||
summary: Download activity reports, in various formats. | ||
description: >- | ||
Multiple report ids can be selected by repeat use of the `report` parameter. | ||
parameters: | ||
- name: report | ||
in: query | ||
description: Ids of reports to include in download | ||
required: true | ||
style: form | ||
schema: | ||
type: array | ||
minItems: 1 | ||
items: | ||
type: integer | ||
- name: format | ||
in: query | ||
description: Format to download report in | ||
required: false | ||
style: form | ||
schema: | ||
type: string | ||
enum: | ||
- json | ||
- csv | ||
default: json | ||
|
||
responses: | ||
200: | ||
description: Successfully retrieved activity reports | ||
content: | ||
text/csv; charset=utf-8: | ||
schema: | ||
type: string | ||
application/json: | ||
schema: | ||
type: object | ||
$ref: '../../index.yaml#/components/schemas/activityReport' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
/** | ||
* @param {string} field name to be retrieved | ||
* @returns {function} Function that will return a simple value wrapped in a Promise | ||
*/ | ||
function transformSimpleValue(instance, field) { | ||
let value = instance[field]; | ||
if (value && Array.isArray(value)) { | ||
value = value.join('\n'); | ||
} | ||
const obj = {}; | ||
Object.defineProperty(obj, field, { | ||
value, | ||
enumerable: true, | ||
}); | ||
return Promise.resolve(obj); | ||
} | ||
|
||
/* | ||
* Generates a function that can transform values of a related model | ||
* @param {string} field The field of the related model | ||
* @param {string} key The key on the related model to transform | ||
* @returns {function} A function that will perform the transformation | ||
*/ | ||
function transformRelatedModel(field, prop) { | ||
async function transformer(instance) { | ||
const obj = {}; | ||
let records = await instance[field]; | ||
if (records) { | ||
if (!Array.isArray(records)) { | ||
records = [records]; | ||
} | ||
const value = records.map((r) => (r[prop] || '')).join('\n'); | ||
Object.defineProperty(obj, field, { | ||
value, | ||
enumerable: true, | ||
}); | ||
} | ||
return Promise.resolve(obj); | ||
} | ||
return transformer; | ||
} | ||
|
||
/* | ||
* Helper function for transformGoalsAndObjectives | ||
*/ | ||
function sortObjectives(a, b) { | ||
if (b.goal.id < a.goal.id) { | ||
return 1; | ||
} | ||
if (b.id < a.id) { | ||
return 1; | ||
} | ||
return -1; | ||
} | ||
|
||
/* | ||
* Create an object with goals and objectives. Used by transformGoalsAndObjectives | ||
* @param {Array<Objectives>} objectiveRecords | ||
*/ | ||
function makeGoalsAndObjectivesObject(objectiveRecords) { | ||
objectiveRecords.sort(sortObjectives); | ||
let objectiveNum = 1; | ||
let goalNum = 0; | ||
|
||
return objectiveRecords.reduce((accum, objective) => { | ||
const { | ||
goal, title, status, ttaProvided, | ||
} = objective; | ||
const goalName = goal.name || null; | ||
const newGoal = goalName && !Object.values(accum).includes(goalName); | ||
|
||
if (newGoal) { | ||
goalNum += 1; | ||
Object.defineProperty(accum, `goal-${goalNum}`, { | ||
value: goalName, | ||
enumerable: true, | ||
}); | ||
Object.defineProperty(accum, `goal-${goalNum}-status`, { | ||
value: goal.status, | ||
enumerable: true, | ||
}); | ||
objectiveNum = 1; | ||
} | ||
|
||
const objectiveId = `${goalNum}.${objectiveNum}`; | ||
|
||
Object.defineProperty(accum, `objective-${objectiveId}`, { | ||
value: title, | ||
enumerable: true, | ||
}); | ||
Object.defineProperty(accum, `objective-${objectiveId}-status`, { | ||
value: status, | ||
enumerable: true, | ||
}); | ||
Object.defineProperty(accum, `objective-${objectiveId}-ttaProvided`, { | ||
value: ttaProvided, | ||
enumerable: true, | ||
}); | ||
objectiveNum += 1; | ||
|
||
return accum; | ||
}, {}); | ||
} | ||
|
||
/* | ||
* Transform goals and objectives into a format suitable for a CSV | ||
* @param {ActivityReport} ActivityReport instance | ||
* @returns {Promise<object>} Object with key-values for goals and objectives | ||
*/ | ||
async function transformGoalsAndObjectives(report) { | ||
let obj = {}; | ||
const objectiveRecords = await report.objectives; | ||
if (objectiveRecords) { | ||
obj = makeGoalsAndObjectivesObject(objectiveRecords); | ||
} | ||
return obj; | ||
} | ||
|
||
const arTransformers = [ | ||
'displayId', | ||
transformRelatedModel('author', 'name'), | ||
transformRelatedModel('approvingManager', 'name'), | ||
transformRelatedModel('lastUpdatedBy', 'name'), | ||
'requester', | ||
transformRelatedModel('collaborators', 'name'), | ||
'programTypes', | ||
'targetPopulations', | ||
'virtualDeliveryType', | ||
'reason', | ||
'participants', | ||
'topics', | ||
'status', | ||
'ttaType', | ||
'numberOfParticipants', | ||
'deliveryMethod', | ||
'duration', | ||
'endDate', | ||
'startDate', | ||
transformRelatedModel('activityRecipients', 'name'), | ||
'activityRecipientType', | ||
'ECLKCResourcesUsed', | ||
'nonECLKCResourcesUsed', | ||
transformRelatedModel('attachments', 'originalFileName'), | ||
transformGoalsAndObjectives, | ||
transformRelatedModel('granteeNextSteps', 'note'), | ||
transformRelatedModel('specialistNextSteps', 'note'), | ||
'context', | ||
'managerNotes', | ||
'additionalNotes', | ||
'lastSaved', | ||
]; | ||
|
||
async function activityReportToCsvRecord(report, transformers = arTransformers) { | ||
const callFunctionOrValueGetter = (x) => { | ||
if (typeof x === 'function') { | ||
return x(report); | ||
} | ||
if (typeof x === 'string') { | ||
return transformSimpleValue(report, x); | ||
} | ||
return {}; | ||
}; | ||
const recordObjects = await Promise.all(transformers.map(callFunctionOrValueGetter)); | ||
const record = recordObjects.reduce((obj, value) => Object.assign(obj, value), {}); | ||
return record; | ||
} | ||
|
||
export { | ||
activityReportToCsvRecord, | ||
arTransformers, | ||
makeGoalsAndObjectivesObject, | ||
}; |
Oops, something went wrong.