Skip to content

Commit

Permalink
fix(#8589): don't check form expression on edit for 4.3 (#8600)
Browse files Browse the repository at this point in the history
  • Loading branch information
dianabarsan authored Oct 2, 2023
1 parent 7fb0ab3 commit 984d8ec
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 146 deletions.
8 changes: 8 additions & 0 deletions tests/e2e/default/enketo/death-report.wdio-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ describe('Submit a death report', () => {
expect(deathCardInfo.deathPlace).to.equal('Health facility');
});

it('should edit the report', async () => {
await commonPage.goToReports();
const reportId = await reportsPage.getLastSubmittedReportId();
await reportsPage.editReport(reportId);
await genericForm.nextPage();
await reportsPage.submitForm();
});

it('Should verify that the report related to the death was created', async () => {
await commonPage.goToReports();
const firstReport = await reportsPage.getListReportInfo(await reportsPage.firstReport());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const formDoc = {
content_type: 'application/octet-stream',
data: Buffer.from(oneTextForm).toString('base64'),
}
},
context: {
expression: 'summary.alive',
}
};
const reportDoc ={
Expand Down Expand Up @@ -71,7 +74,6 @@ describe('Edit report with attachmnet', () => {
await commonElements.goToReports();

await reportsPage.editReport(reportDoc._id);
// await browser.debug();
await reportsPage.submitForm();

const editedReport = await utils.getDoc(reportDoc._id);
Expand Down
13 changes: 9 additions & 4 deletions webapp/src/ts/modals/training-cards/training-cards.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { GeolocationService } from '@mm-services/geolocation.service';
import { TranslateService } from '@mm-services/translate.service';
import { TelemetryService } from '@mm-services/telemetry.service';
import { FeedbackService } from '@mm-services/feedback.service';
import { EnketoFormContext } from '@mm-services/enketo.service';

@Component({
selector: 'training-cards-modal',
Expand Down Expand Up @@ -93,11 +94,15 @@ export class TrainingCardsComponent extends MmModalAbstract implements OnInit, O
}
}

private async renderForm(form) {
private async renderForm(formDoc) {
try {
const selector = `#${this.formWrapperId}`;
this.form = await this.enketoService.render(selector, form, null, null, this.resetFormError.bind(this), true);
this.formNoTitle = !form?.title;
const formObj = new EnketoFormContext(`#${this.formWrapperId}`, 'training-card', formDoc);
formObj.isFormInModal = true;
formObj.valuechangeListener = this.resetFormError.bind(this);

this.form = await this.enketoService.render(formObj);
this.formNoTitle = !formDoc?.title;

this.loadingContent = false;
this.recordTelemetryPostRender();
} catch(error) {
Expand Down
13 changes: 4 additions & 9 deletions webapp/src/ts/modules/contacts/contacts-edit.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,15 +245,10 @@ export class ContactsEditComponent implements OnInit, OnDestroy, AfterViewInit {
const instanceData = this.getFormInstanceData();
const markFormEdited = this.markFormEdited.bind(this);
const resetFormError = this.resetFormError.bind(this);
const formContext: EnketoFormContext = {
selector: '#contact-form',
formDoc,
instanceData,
editedListener: markFormEdited,
valuechangeListener: resetFormError,
titleKey,
};

const formContext = new EnketoFormContext('#contact-form', 'contact', formDoc, instanceData);
formContext.editedListener = markFormEdited;
formContext.valuechangeListener = resetFormError;
formContext.titleKey = titleKey;
this.globalActions.setEnketoEditedStatus(false);

return this.enketoService.renderContactForm(formContext);
Expand Down
23 changes: 8 additions & 15 deletions webapp/src/ts/modules/contacts/contacts-report.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { isEqual as _isEqual } from 'lodash-es';

import { ContactViewModelGeneratorService } from '@mm-services/contact-view-model-generator.service';
import { EnketoService } from '@mm-services/enketo.service';
import { EnketoService, EnketoFormContext } from '@mm-services/enketo.service';
import { GeolocationService } from '@mm-services/geolocation.service';
import { GlobalActions } from '@mm-actions/global';
import { Selectors } from '@mm-selectors/index';
Expand Down Expand Up @@ -129,20 +129,13 @@ export class ContactsReportComponent implements OnInit, OnDestroy, AfterViewInit
this.globalActions.setTitle(this.translateFromService.get(form.title));
this.setCancelCallback();

const instanceData = {
source: 'contact',
contact,
};
const markFormEdited = this.markFormEdited.bind(this);
const resetFormError = this.resetFormError.bind(this);

return this.enketoService.render(
'#contact-report',
form,
instanceData,
markFormEdited,
resetFormError
);
const instanceData = { source: 'contact', contact, };

const formContext = new EnketoFormContext('#contact-report', 'report', form, instanceData);
formContext.editedListener = this.markFormEdited.bind(this);
formContext.valuechangeListener = this.resetFormError.bind(this);

return this.enketoService.render(formContext);
})
.then((formInstance) => {
this.form = formInstance;
Expand Down
15 changes: 7 additions & 8 deletions webapp/src/ts/modules/reports/reports-add.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Selectors } from '@mm-selectors/index';
import { GeolocationService } from '@mm-services/geolocation.service';
import { GlobalActions } from '@mm-actions/global';
import { ReportsActions } from '@mm-actions/reports';
import { EnketoService } from '@mm-services/enketo.service';
import { EnketoService, EnketoFormContext } from '@mm-services/enketo.service';
import { TelemetryService } from '@mm-services/telemetry.service';
import { TranslateService } from '@mm-services/translate.service';

Expand Down Expand Up @@ -194,14 +194,13 @@ export class ReportsAddComponent implements OnInit, OnDestroy, AfterViewInit {
}

private renderForm(form, reportContent, model) {
const formContext = new EnketoFormContext('#report-form', 'report', form, reportContent);
formContext.editedListener = this.markFormEdited.bind(this);
formContext.valuechangeListener = this.resetFormError.bind(this);
formContext.editing = !!reportContent;

return this.enketoService
.render(
'#report-form',
form,
reportContent,
this.markFormEdited.bind(this),
this.resetFormError.bind(this),
)
.render(formContext)
.then((form) => {
this.form = form;
this.globalActions.setLoadingContent(false);
Expand Down
11 changes: 7 additions & 4 deletions webapp/src/ts/modules/tasks/tasks-content.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Store } from '@ngrx/store';
import { combineLatest, Subject, Subscription } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';

import { EnketoService } from '@mm-services/enketo.service';
import { EnketoService, EnketoFormContext } from '@mm-services/enketo.service';
import { TelemetryService } from '@mm-services/telemetry.service';
import { TranslateFromService } from '@mm-services/translate-from.service';
import { XmlFormsService } from '@mm-services/xml-forms.service';
Expand Down Expand Up @@ -214,11 +214,14 @@ export class TasksContentComponent implements OnInit, OnDestroy {

private renderForm(action, formDoc) {
this.globalActions.setEnketoEditedStatus(false);
const markFormEdited = this.markFormEdited.bind(this);
const resetFormError = this.resetFormError.bind(this);

const formContext = new EnketoFormContext('#task-report', 'task', formDoc, action.content);
formContext.editedListener = this.markFormEdited.bind(this);
formContext.valuechangeListener = this.resetFormError.bind(this);


return this.enketoService
.render('#task-report', formDoc, action.content, markFormEdited, resetFormError)
.render(formContext)
.then((formInstance) => {
this.form = formInstance;
this.loadingForm = false;
Expand Down
87 changes: 47 additions & 40 deletions webapp/src/ts/services/enketo.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,11 +434,15 @@ export class EnketoService {
});
}

private canAccessForm(formDoc, user, instanceData, contactSummary) {
private canAccessForm(formContext: EnketoFormContext) {
return this.xmlFormsService.canAccessForm(
formDoc,
user,
{ doc: instanceData?.contact, contactSummary: contactSummary?.context },
formContext.formDoc,
formContext.userContact,
{
doc: typeof formContext.instanceData !== 'string' && formContext.instanceData?.contact,
contactSummary: formContext.contactSummary?.context,
shouldEvaluateExpression: formContext.shouldEvaluateExpression(),
},
);
}

Expand All @@ -451,72 +455,53 @@ export class EnketoService {
}

private async renderForm(formContext: EnketoFormContext) {
const {
formDoc,
instanceData,
selector,
titleKey,
isFormInModal,
userContact,
} = formContext;

try {
this.unload(this.currentForm);
const doc = await this.transformXml(formDoc);
const contactSummary = await this.getContactSummary(doc, instanceData);
const doc = await this.transformXml(formContext.formDoc);
formContext.contactSummary = await this.getContactSummary(doc, formContext.instanceData);

if (!await this.canAccessForm(formDoc, userContact, instanceData, contactSummary)) {
if (!await this.canAccessForm(formContext)) {
throw { translationKey: 'error.loading.form.no_authorized' };
}

this.replaceJavarosaMediaWithLoaders(doc.html);
const xmlFormContext: XmlFormContext = {
doc,
wrapper: $(selector),
instanceData,
titleKey,
isFormInModal,
contactSummary,
wrapper: $(formContext.selector),
instanceData: formContext.instanceData,
titleKey: formContext.titleKey,
isFormInModal: formContext.isFormInModal,
contactSummary: formContext.contactSummary,
};
const form = await this.renderFromXmls(xmlFormContext);
const formContainer = xmlFormContext.wrapper.find('.container').first();
this.replaceMediaLoaders(formContainer, formDoc);
this.replaceMediaLoaders(formContainer, formContext.formDoc);
this.registerEnketoListeners(xmlFormContext.wrapper, form, formContext);
window.CHTCore.debugFormModel = () => form.model.getStr();
return form;
} catch (error) {
if (error.translationKey) {
throw error;
}
const errorMessage = `Failed during the form "${formDoc.internalId}" rendering : `;
const errorMessage = `Failed during the form "${formContext.formDoc?.internalId}" rendering : `;
console.error(errorMessage, error.message);
this.feedbackService.submit(errorMessage + error.message, false);
throw new Error(errorMessage + error.message);
}
}

render(selector, form, instanceData, editedListener, valuechangeListener, isFormInModal = false) {
return this.ngZone.runOutsideAngular(() => {
return this._render(selector, form, instanceData, editedListener, valuechangeListener, isFormInModal);
});
render(formContext:EnketoFormContext) {
return this.ngZone.runOutsideAngular(() => this._render(formContext));
}

private _render(selector, form, instanceData, editedListener, valuechangeListener, isFormInModal) {
private _render(formContext) {
return Promise
.all([
this.inited,
this.getUserContact(),
])
.then(([ , userContact]) => {
const formContext: EnketoFormContext = {
selector,
formDoc: form,
instanceData,
editedListener,
valuechangeListener,
isFormInModal,
userContact,
};
formContext.userContact = userContact;
return this.renderForm(formContext);
});
}
Expand Down Expand Up @@ -901,16 +886,38 @@ interface XmlFormContext {
instanceData: null|string|Record<string, any>; // String for report forms, Record<> for contact forms.
titleKey?: string;
isFormInModal?: boolean;
contactSummary: Record<string, any>;
contactSummary?: Record<string, any>;
}

export interface EnketoFormContext {
export class EnketoFormContext {
selector: string;
formDoc: Record<string, any>;
instanceData: null|string|Record<string, any>; // String for report forms, Record<> for contact forms.
type: 'contact'|'report'|'task'|'training-card';
editing: boolean;
instanceData: null|string|Record<string, any>;
editedListener: () => void;
valuechangeListener: () => void;
titleKey?: string;
isFormInModal?: boolean;
userContact?: Record<string, any>;
contactSummary? :Record<string, any>;

constructor(selector?, type?, formDoc?, data?) {
this.selector = selector;
this.type = type;
this.formDoc = formDoc;
this.instanceData = data;
}

shouldEvaluateExpression() {
if (this.type === 'report' && this.editing) {
return false;
}
return true;
}

requiresContact() {
// Users can access contact forms even when they don't have a contact associated.
return this.type !== 'contact';
}
}
4 changes: 4 additions & 0 deletions webapp/src/ts/services/xml-forms.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,10 @@ export class XmlFormsService {
return false;
}

if (options?.shouldEvaluateExpression === false) {
return true;
}

return await this.checkFormExpression(form, options?.doc, userContact, options?.contactSummary);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ describe('TrainingCardsComponent', () => {
expect(xmlFormsService.get.calledOnce).to.be.true;
expect(xmlFormsService.get.args[0]).to.deep.equal([ 'training:a_form_id' ]);
expect(enketoService.render.calledOnce).to.be.true;
expect(enketoService.render.args[0][1]).to.deep.equal(xmlForm);
expect(enketoService.render.args[0][2]).to.equal(null);
expect(enketoService.render.args[0][0].formDoc).to.deep.equal(xmlForm);
expect(component.form).to.equal(renderedForm);
expect(consoleErrorMock.notCalled).to.be.true;
expect(feedbackService.submit.notCalled).to.be.true;
Expand Down Expand Up @@ -298,15 +297,14 @@ describe('TrainingCardsComponent', () => {
expect(xmlFormsService.get.calledOnce).to.be.true;
expect(xmlFormsService.get.args[0]).to.deep.equal([ 'training:a_form_id' ]);
expect(enketoService.render.calledOnce).to.be.true;
expect(enketoService.render.args[0][1]).to.deep.equal(xmlForm);
expect(enketoService.render.args[0][2]).to.equal(null);
expect(enketoService.render.args[0][0].formDoc).to.deep.equal(xmlForm);
expect(component.form).to.equal(renderedForm);
expect(consoleErrorMock.notCalled).to.be.true;
expect(feedbackService.submit.notCalled).to.be.true;
expect(telemetryService.record.calledOnce).to.be.true;
expect(telemetryService.record.args[0][0]).to.equal('enketo:training:a_form_id:add:render');

const resetFormError = enketoService.render.args[0][4];
const resetFormError = enketoService.render.args[0][0].valuechangeListener;
resetFormError();
expect(globalActions.setEnketoError.notCalled).to.be.true; // No error so no call
component.enketoError = 'some error';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,17 +160,17 @@ describe('contacts report component', () => {
flush();

expect(enketoService.render.callCount).to.equal(1);
expect(enketoService.render.args[0][0]).to.equal('#contact-report');
expect(enketoService.render.args[0][1]).to.deep.equal({ title: 'formTitle' });
expect(enketoService.render.args[0][2]).to.deep.equal(
{
expect(enketoService.render.args[0][0]).to.deep.include({
selector: '#contact-report',
formDoc: { title: 'formTitle' },
instanceData: {
source: 'contact',
contact: {
_id: 'test_id',
contact_type: 'test_type'
}
}
);
});
}));

it('should unsubscribe and unload form on destroy', async () => {
Expand Down
Loading

0 comments on commit 984d8ec

Please sign in to comment.