Skip to content

Commit

Permalink
Support server-side export of all dataset including media.
Browse files Browse the repository at this point in the history
  • Loading branch information
yghokim committed Jul 15, 2020
1 parent 4cc3bf6 commit 217249f
Show file tree
Hide file tree
Showing 9 changed files with 349 additions and 61 deletions.
8 changes: 8 additions & 0 deletions client/app/experiment-data/experiment-data.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,14 @@ export class ExperimentDataComponent implements OnInit, OnDestroy {

onExportClicked() {
this.notificationService.pushSnackBarMessage({ message: "Start packing captured items.." })

this._internalSubscriptions.add(
this.api.selectedExperimentService.pipe(flatMap(service => service.downloadExperimentData())).subscribe(data => {
FileSaver.saveAs(data, this.api.getSelectedExperimentId() + "_experiment-tracking-data.zip")
})
)

return
this._internalSubscriptions.add(
this.api.selectedExperimentService.pipe(
flatMap(service => service.getTrackingPlans().pipe(
Expand Down
6 changes: 6 additions & 0 deletions client/app/services/experiment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -627,4 +627,10 @@ export class ExperimentService {
sendTestPingOfTrigger(triggerId: string): Observable<boolean> {
return this.http.post<boolean>('/api/research/experiments/' + this.experimentId + '/test/trigger_ping', { triggerId: triggerId }, this.researchApi.authorizedOptions)
}


//---------
downloadExperimentData(): Observable<Blob>{
return this.http.get<Blob>('/api/research/experiments/' + this.experimentId + '/export', this.researchApi.makeAuthorizedRequestOptions(null, 'blob'))
}
}
62 changes: 34 additions & 28 deletions omnitrack/core/fields/audiorecord.field.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,41 @@ import FieldIconTypes from "./field-icon-types";
import { ServerFile } from "../datatypes/field_datatypes";
import { EPropertyType } from "../properties/property.types";

export class AudioRecordFieldHelper extends FieldHelper{
typeName: string = "Audio Record";
typeNameForSerialization: string = TypedStringSerializer.TYPENAME_SERVERFILE;
propertyKeys: string[] = []

constructor(){
super(fieldTypes.ATTR_TYPE_AUDIO)
export class AudioRecordFieldHelper extends FieldHelper {
typeName = "Audio Record";
typeNameForSerialization: string = TypedStringSerializer.TYPENAME_SERVERFILE;
propertyKeys: string[] = []

constructor() {
super(fieldTypes.ATTR_TYPE_AUDIO)
}

getPropertyHelper<T>(propertyKey: string): PropertyHelper<T> {
return null
}

getPropertyType(propertyKey: string): EPropertyType {
return null
}

getSmallIconType(field: IFieldDbEntity): string {
return FieldIconTypes.ATTR_ICON_SMALL_AUDIO
}

formatFieldValue(attr: IFieldDbEntity, value: any): string {
const imageFile = value as ServerFile
let injectionId: string
if (attr.flags) {
injectionId = attr.flags.injectionId
}
if (injectionId != null) {
return injectionId
} else { return attr.localId }
}

getPropertyHelper<T>(propertyKey: string): PropertyHelper<T> {
return null
}

getPropertyType(propertyKey: string): EPropertyType {
return null
}

getSmallIconType(field: IFieldDbEntity): string {
return FieldIconTypes.ATTR_ICON_SMALL_AUDIO
}

formatFieldValue(attr: IFieldDbEntity, value: any): string {
const imageFile = value as ServerFile
return imageFile.mimeType
}

getPropertyName(propertyKey: string): string{
return "property"
}
getPropertyName(propertyKey: string): string {
return "property"
}


}
}
26 changes: 26 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
"string-format": "^2.0.0",
"tether": "1.4.7",
"tree-kill": "^1.2.1",
"tmp-promise": "^3.0.2",
"ttest": "^2.1.0",
"underscore.string": "^3.3.5",
"uuid": "^3.3.3",
Expand Down
56 changes: 28 additions & 28 deletions server/controllers/research/ot_experiment_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { userCtrl } from '../ot_user_controller';
import C from '../../server_consts';
import { IUserDbEntity } from '../../../omnitrack/core/db-entity-types';
import { generateNewPackageKey } from '../../models/ot_experiment';
import { IExperimentGroupDbEntity, IExperimentDbEntity } from '../../../omnitrack/core/research/db-entity-types';
import { IExperimentGroupDbEntity, IExperimentDbEntity, IExperimentTrackingPlanDbEntity } from '../../../omnitrack/core/research/db-entity-types';

export default class OTExperimentCtrl {

Expand Down Expand Up @@ -423,13 +423,13 @@ export default class OTExperimentCtrl {
_id: req.params.experimentId,
manager: req.researcher.uid
}, {
finishDate: req.body.date
}, { new: true })).lean().then(experiment => {
res.status(200).send(experiment)
}).catch(err => {
console.error(err)
res.status(500).send(err)
})
finishDate: req.body.date
}, { new: true })).lean().then(experiment => {
res.status(200).send(experiment)
}).catch(err => {
console.error(err)
res.status(500).send(err)
})
}

getInvitations = (req, res) => {
Expand Down Expand Up @@ -535,10 +535,10 @@ export default class OTExperimentCtrl {

OTExperiment.findOneAndUpdate(query, update, { new: true }).lean<any>().then(doc => {
if (doc) {
res.status(200).send({success: true, packageKey: packageKey})
res.status(200).send({ success: true, packageKey: packageKey })
app.socketModule().sendUpdateNotificationToExperimentSubscribers(experimentId, { model: SocketConstants.MODEL_EXPERIMENT, event: SocketConstants.EVENT_EDITED })
} else {
res.status(200).send({success: false, packageKey: null})
res.status(200).send({ success: false, packageKey: null })
}
}).catch(err => {
console.log(err)
Expand Down Expand Up @@ -585,18 +585,18 @@ export default class OTExperimentCtrl {
})
}

async findGroupsWithPlan(experimentId: string, planKey: string): Promise<Array<IExperimentGroupDbEntity>>{
async findGroupsWithPlan(experimentId: string, planKey: string): Promise<Array<IExperimentGroupDbEntity>> {
const experiment = await OTExperiment.findById(experimentId).lean<any>() as IExperimentDbEntity
if(experiment){
if (experiment) {
return experiment.groups.filter(g => g.trackingPlanKey === planKey)
}else throw {error : C.ERROR_CODE_ILLEGAL_ARGUMENTS}
} else throw { error: C.ERROR_CODE_ILLEGAL_ARGUMENTS }
}

async findParticipantsWithPlan(experimentId: string, planKey: string): Promise<Array<IUserDbEntity>>{
async findParticipantsWithPlan(experimentId: string, planKey: string): Promise<Array<IUserDbEntity>> {
const groupsWithPlan = await this.findGroupsWithPlan(experimentId, planKey)
if(groupsWithPlan.length > 0){
return OTUser.find({experiment: experimentId, group: {$in: groupsWithPlan}}, USER_PROJECTION_EXCLUDE_CREDENTIAL).lean<any>()
}else{
if (groupsWithPlan.length > 0) {
return OTUser.find({ experiment: experimentId, group: { $in: groupsWithPlan } }, USER_PROJECTION_EXCLUDE_CREDENTIAL).lean<any>()
} else {
return []
}
}
Expand Down Expand Up @@ -788,18 +788,18 @@ export default class OTExperimentCtrl {
OTExperiment.findOne({
_id: experimentId
}, {
consent: 1,
receiveConsentInApp: 1,
demographicFormSchema: 1
}).lean<any>().then(
exp => {
if (exp) {
res.status(200).send(exp)
} else {
res.status(404).send("No such experiment.")
}
consent: 1,
receiveConsentInApp: 1,
demographicFormSchema: 1
}).lean<any>().then(
exp => {
if (exp) {
res.status(200).send(exp)
} else {
res.status(404).send("No such experiment.")
}
)
}
)
}

sendNotificationMessageToUser = (req, res) => {
Expand Down
Loading

0 comments on commit 217249f

Please sign in to comment.