MOBILE-2272 quiz: Fix error when calculating new state in offline

main
Dani Palou 2020-09-30 16:33:23 +02:00
parent d2f4c85af2
commit f144a29fee
2 changed files with 113 additions and 104 deletions

View File

@ -83,71 +83,76 @@ export class AddonQbehaviourDeferredFeedbackHandler implements CoreQuestionBehav
* @param isSameFn Function to override the default isSameResponse check. * @param isSameFn Function to override the default isSameResponse check.
* @return Promise resolved with state. * @return Promise resolved with state.
*/ */
determineNewStateDeferred(component: string, attemptId: number, question: any, componentId: string | number, siteId?: string, async determineNewStateDeferred(component: string, attemptId: number, question: any, componentId: string | number,
isCompleteFn?: isCompleteResponseFunction, isSameFn?: isSameResponseFunction): Promise<CoreQuestionState> { siteId?: string, isCompleteFn?: isCompleteResponseFunction, isSameFn?: isSameResponseFunction)
: Promise<CoreQuestionState> {
// Check if we have local data for the question. // Check if we have local data for the question.
return this.questionProvider.getQuestion(component, attemptId, question.slot, siteId).catch(() => { let dbQuestion;
try {
dbQuestion = await this.questionProvider.getQuestion(component, attemptId, question.slot, siteId);
} catch (error) {
// No entry found, use the original data. // No entry found, use the original data.
return question; dbQuestion = question;
}).then((dbQuestion) => { }
const state = this.questionProvider.getState(dbQuestion.state);
if (state.finished || !state.active) { const state = this.questionProvider.getState(dbQuestion.state);
// Question is finished, it cannot change.
return state; if (state.finished || !state.active) {
// Question is finished, it cannot change.
return state;
}
const newBasicAnswers = this.questionProvider.getBasicAnswers(question.answers);
if (dbQuestion.state) {
// Question already has a state stored. Check if answer has changed.
let prevAnswers = await this.questionProvider.getQuestionAnswers(component, attemptId, question.slot, false, siteId);
prevAnswers = this.questionProvider.convertAnswersArrayToObject(prevAnswers, true);
const prevBasicAnswers = this.questionProvider.getBasicAnswers(prevAnswers);
// If answers haven't changed the state is the same.
if (isSameFn) {
if (isSameFn(question, prevAnswers, prevBasicAnswers, question.answers, newBasicAnswers,
component, componentId)) {
return state;
}
} else {
if (this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers, component, componentId)) {
return state;
}
} }
}
// We need to check if the answers have changed. Retrieve current stored answers. // Answers have changed. Now check if the response is complete and calculate the new state.
return this.questionProvider.getQuestionAnswers(component, attemptId, question.slot, false, siteId) let complete: number;
.then((prevAnswers) => { let newState: string;
const newBasicAnswers = this.questionProvider.getBasicAnswers(question.answers); if (isCompleteFn) {
// Pass all the answers since some behaviours might need the extra data.
complete = isCompleteFn(question, question.answers, component, componentId);
} else {
// Only pass the basic answers since questions should be independent of extra data.
complete = this.questionDelegate.isCompleteResponse(question, newBasicAnswers, component, componentId);
}
prevAnswers = this.questionProvider.convertAnswersArrayToObject(prevAnswers, true); if (complete < 0) {
const prevBasicAnswers = this.questionProvider.getBasicAnswers(prevAnswers); newState = 'cannotdeterminestatus';
} else if (complete > 0) {
newState = 'complete';
} else {
const gradable = this.questionDelegate.isGradableResponse(question, newBasicAnswers);
if (gradable < 0) {
newState = 'cannotdeterminestatus';
} else if (gradable > 0) {
newState = 'invalid';
} else {
newState = 'todo';
}
}
// If answers haven't changed the state is the same. return this.questionProvider.getState(newState);
if (isSameFn) {
if (isSameFn(question, prevAnswers, prevBasicAnswers, question.answers, newBasicAnswers,
component, componentId)) {
return state;
}
} else {
if (this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers, component, componentId)) {
return state;
}
}
// Answers have changed. Now check if the response is complete and calculate the new state.
let complete: number,
newState: string;
if (isCompleteFn) {
// Pass all the answers since some behaviours might need the extra data.
complete = isCompleteFn(question, question.answers, component, componentId);
} else {
// Only pass the basic answers since questions should be independent of extra data.
complete = this.questionDelegate.isCompleteResponse(question, newBasicAnswers, component, componentId);
}
if (complete < 0) {
newState = 'cannotdeterminestatus';
} else if (complete > 0) {
newState = 'complete';
} else {
const gradable = this.questionDelegate.isGradableResponse(question, newBasicAnswers);
if (gradable < 0) {
newState = 'cannotdeterminestatus';
} else if (gradable > 0) {
newState = 'invalid';
} else {
newState = 'todo';
}
}
return this.questionProvider.getState(newState);
});
});
} }
/** /**

View File

@ -83,65 +83,69 @@ export class AddonQbehaviourManualGradedHandler implements CoreQuestionBehaviour
* @param isSameFn Function to override the default isSameResponse check. * @param isSameFn Function to override the default isSameResponse check.
* @return Promise resolved with state. * @return Promise resolved with state.
*/ */
determineNewStateManualGraded(component: string, attemptId: number, question: any, componentId: string | number, async determineNewStateManualGraded(component: string, attemptId: number, question: any, componentId: string | number,
siteId?: string, isCompleteFn?: isCompleteResponseFunction, isSameFn?: isSameResponseFunction) siteId?: string, isCompleteFn?: isCompleteResponseFunction, isSameFn?: isSameResponseFunction)
: Promise<CoreQuestionState> { : Promise<CoreQuestionState> {
// Check if we have local data for the question. // Check if we have local data for the question.
return this.questionProvider.getQuestion(component, attemptId, question.slot, siteId).catch(() => { let dbQuestion;
try {
dbQuestion = await this.questionProvider.getQuestion(component, attemptId, question.slot, siteId);
} catch (error) {
// No entry found, use the original data. // No entry found, use the original data.
return question; dbQuestion = question;
}).then((dbQuestion) => { }
const state = this.questionProvider.getState(dbQuestion.state);
if (state.finished || !state.active) { const state = this.questionProvider.getState(dbQuestion.state);
// Question is finished, it cannot change.
return state; if (state.finished || !state.active) {
// Question is finished, it cannot change.
return state;
}
const newBasicAnswers = this.questionProvider.getBasicAnswers(question.answers);
if (dbQuestion.state) {
// Question already has a state stored. Check if answer has changed.
let prevAnswers = await this.questionProvider.getQuestionAnswers(component, attemptId, question.slot, false, siteId);
prevAnswers = this.questionProvider.convertAnswersArrayToObject(prevAnswers, true);
const prevBasicAnswers = this.questionProvider.getBasicAnswers(prevAnswers);
// If answers haven't changed the state is the same.
if (isSameFn) {
if (isSameFn(question, prevAnswers, prevBasicAnswers, question.answers, newBasicAnswers,
component, componentId)) {
return state;
}
} else {
if (this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers, component, componentId)) {
return state;
}
} }
}
// We need to check if the answers have changed. Retrieve current stored answers. // Check if the response is complete and calculate the new state.
return this.questionProvider.getQuestionAnswers(component, attemptId, question.slot, false, siteId) let complete: number;
.then((prevAnswers) => { let newState: string;
const newBasicAnswers = this.questionProvider.getBasicAnswers(question.answers); if (isCompleteFn) {
// Pass all the answers since some behaviours might need the extra data.
complete = isCompleteFn(question, question.answers, component, componentId);
} else {
// Only pass the basic answers since questions should be independent of extra data.
complete = this.questionDelegate.isCompleteResponse(question, newBasicAnswers, component, componentId);
}
prevAnswers = this.questionProvider.convertAnswersArrayToObject(prevAnswers, true); if (complete < 0) {
const prevBasicAnswers = this.questionProvider.getBasicAnswers(prevAnswers); newState = 'cannotdeterminestatus';
} else if (complete > 0) {
newState = 'complete';
} else {
newState = 'todo';
}
// If answers haven't changed the state is the same. return this.questionProvider.getState(newState);
if (isSameFn) {
if (isSameFn(question, prevAnswers, prevBasicAnswers, question.answers, newBasicAnswers,
component, componentId)) {
return state;
}
} else {
if (this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers, component, componentId)) {
return state;
}
}
// Answers have changed. Now check if the response is complete and calculate the new state.
let complete: number,
newState: string;
if (isCompleteFn) {
// Pass all the answers since some behaviours might need the extra data.
complete = isCompleteFn(question, question.answers, component, componentId);
} else {
// Only pass the basic answers since questions should be independent of extra data.
complete = this.questionDelegate.isCompleteResponse(question, newBasicAnswers, component, componentId);
}
if (complete < 0) {
newState = 'cannotdeterminestatus';
} else if (complete > 0) {
newState = 'complete';
} else {
newState = 'todo';
}
return this.questionProvider.getState(newState);
});
});
} }
/** /**