Skip to content

Commit

Permalink
Merge pull request #75 from rajnishdargan/compass-sever-eval
Browse files Browse the repository at this point in the history
Issue #IQ-608 feat: server evaluable changes and resolve conflict
  • Loading branch information
sajeshkayyath authored Mar 7, 2024
2 parents 66516ef + 5a43168 commit 52dd6d4
Show file tree
Hide file tree
Showing 12 changed files with 706 additions and 565 deletions.
4 changes: 3 additions & 1 deletion projects/quml-demo-app/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DataService } from './services/data.service';
export class AppComponent implements OnInit {
contentId = 'do_2138622515299368961170';
playerConfig: any;
telemetryEvents: any = [];

constructor(private dataService: DataService) { }

Expand Down Expand Up @@ -46,6 +47,7 @@ export class AppComponent implements OnInit {
}

getTelemetryEvents(event) {
console.log('event is for telemetry', JSON.stringify(event));
this.telemetryEvents.push(JSON.parse(JSON.stringify(event)));
console.log('event is for telemetry', this.telemetryEvents);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@
<!-- Show player end page -->
<div class="endPage-container" *ngIf="endPageReached" [ngClass]="endPageReached ? 'endPage-container-height': ''">
<sb-player-end-page *ngIf="endPageReached && showEndPage" [contentName]="parentConfig.contentName"
[outcome]="outcomeLabel" [outcomeLabel]="'Score: '" [userName]="userName" [timeSpentLabel]="durationSpent"
[outcome]="!questionSetEvaluable? outcomeLabel : ''" [outcomeLabel]="!questionSetEvaluable? 'Score: ': ''" [userName]="userName" [timeSpentLabel]="durationSpent"
(replayContent)="replayContent()" (exitContent)="exitContent($event)"
[showExit]="parentConfig?.sideMenuConfig.showExit" [showReplay]="showReplay" [nextContent]="nextContent"
(playNextContent)="playNextContent($event)">

<span *ngIf="questionSetEvaluable" class="mt-8 font-weight-bold d-block">You've succesfully submitted the assessment and response sent for validation</span>

<span class="sb-color-primary mt-8 fnormal font-weight-bold d-block"
*ngIf="attempts?.max && attempts?.current && attempts.max !== attempts.current">Attempt no
{{attempts.current}}/{{attempts.max}}
Expand Down
37 changes: 30 additions & 7 deletions projects/quml-library/src/lib/main-player/main-player.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export class MainPlayerComponent implements OnInit, OnChanges {
nextContent: NextContent;
disabledHandle: any;
subscription: Subscription;
questionSetEvaluable: any;

constructor(
public viewerService: ViewerService,
Expand Down Expand Up @@ -214,7 +215,9 @@ export class MainPlayerComponent implements OnInit, OnChanges {
this.parentConfig.showFeedback = this.showFeedBack = this.playerConfig.metadata?.showFeedback;
this.parentConfig.sideMenuConfig = { ...this.parentConfig.sideMenuConfig, ...this.playerConfig.config.sideMenu };
this.parentConfig.warningTime = _.get(this.playerConfig,'config.warningTime', this.parentConfig.warningTime);
this.parentConfig.showWarningTimer = _.get(this.playerConfig,'config.showWarningTimer', this.parentConfig.showWarningTimer)
this.parentConfig.showWarningTimer = _.get(this.playerConfig,'config.showWarningTimer', this.parentConfig.showWarningTimer);
this.viewerService.serverValidationCheck(this.playerConfig.metadata?.evalMode);
this.questionSetEvaluable = this.viewerService.questionSetEvaluable;
if (this.playerConfig?.context?.userData) {
const firstName = this.playerConfig.context.userData?.firstName ?? '';
const lastName = this.playerConfig.context.userData?.lastName ?? '';
Expand Down Expand Up @@ -270,7 +273,9 @@ export class MainPlayerComponent implements OnInit, OnChanges {
/* istanbul ignore else */
if (this.parentConfig.isSectionsAvailable) {
const activeSectionIndex = this.getActiveSectionIndex();
this.updateSectionScore(activeSectionIndex);
if(!this.questionSetEvaluable) {
this.updateSectionScore(activeSectionIndex);
}
}
this.getSummaryObject();
this.loadScoreBoard = true;
Expand All @@ -284,7 +289,9 @@ export class MainPlayerComponent implements OnInit, OnChanges {

if (this.parentConfig.isSectionsAvailable) {
const activeSectionIndex = this.getActiveSectionIndex();
this.updateSectionScore(activeSectionIndex);
if(!this.questionSetEvaluable) {
this.updateSectionScore(activeSectionIndex);
}
this.setNextSection(event, activeSectionIndex);
} else {
this.prepareEnd(event);
Expand Down Expand Up @@ -353,7 +360,11 @@ export class MainPlayerComponent implements OnInit, OnChanges {

prepareEnd(event) {
this.viewerService.pauseVideo();
this.calculateScore();
if(!this.questionSetEvaluable) {
this.calculateScore();
} else {
this.finalScore = 0;
}
this.setDurationSpent();
this.getSummaryObject();
if (this.parentConfig.requiresSubmit && !this.isDurationExpired) {
Expand Down Expand Up @@ -440,7 +451,11 @@ export class MainPlayerComponent implements OnInit, OnChanges {
}

exitContent(event) {
this.calculateScore();
if(!this.questionSetEvaluable) {
this.calculateScore();
} else {
this.finalScore = 0;
}
/* istanbul ignore else */
if (event?.type === 'EXIT') {
this.viewerService.raiseHeartBeatEvent(eventName.endPageExitClicked, TelemetryType.interact, pageId.endPage);
Expand Down Expand Up @@ -476,7 +491,11 @@ export class MainPlayerComponent implements OnInit, OnChanges {

onScoreBoardLoaded(event) {
if (event?.scoreBoardLoaded) {
this.calculateScore();
if(!this.questionSetEvaluable) {
this.calculateScore();
} else {
this.finalScore = 0
}
}
}

Expand Down Expand Up @@ -571,7 +590,11 @@ export class MainPlayerComponent implements OnInit, OnChanges {

@HostListener('window:beforeunload')
ngOnDestroy() {
this.calculateScore();
if(!this.questionSetEvaluable) {
this.calculateScore();
} else {
this.finalScore = 0;
}
this.getSummaryObject();
/* istanbul ignore else */
if (this.isSummaryEventRaised === false) {
Expand Down
13 changes: 13 additions & 0 deletions projects/quml-library/src/lib/mcq/mcq.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'
import { DomSanitizer } from '@angular/platform-browser';

import { McqComponent } from './mcq.component';
import { ViewerService } from '../services/viewer-service/viewer-service';

describe('McqComponent', () => {
let component: McqComponent;
let viewerService;
let fixture: ComponentFixture<McqComponent>;
class ViewServiceMock {
questionSetEvaluable: boolean
}
const question = {
"copyright": "tn",
"subject": [
Expand Down Expand Up @@ -159,6 +164,9 @@ describe('McqComponent', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [McqComponent],
providers: [
{ provide: ViewerService, useClass: ViewServiceMock }
],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
Expand All @@ -167,6 +175,7 @@ describe('McqComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(McqComponent);
component = fixture.componentInstance;
viewerService = TestBed.inject(ViewerService);
component.question = question;
fixture.detectChanges();
});
Expand All @@ -177,21 +186,25 @@ describe('McqComponent', () => {

it('should set layout to IMAGEGRID', () => {
component.question.templateId = 'mcq-horizontal';
viewerService.questionSetEvaluable = false;
component.ngOnInit();
expect(component.layout).toBe('IMAGEGRID');
});
it('should set layout to IMAGEQAGRID', () => {
component.question.templateId = 'mcq-vertical-split';
viewerService.questionSetEvaluable = false;
component.ngOnInit();
expect(component.layout).toBe('IMAGEQAGRID');
});
it('should set layout to MULTIIMAGEGRID', () => {
component.question.templateId = 'mcq-grid-split';
viewerService.questionSetEvaluable = false;
component.ngOnInit();
expect(component.layout).toBe('MULTIIMAGEGRID');
});
it('should not set any layout', () => {
component.question.templateId = 'mcq';
viewerService.questionSetEvaluable = false;
component.ngOnInit();
expect(component.layout).toBeUndefined;
});
Expand Down
8 changes: 6 additions & 2 deletions projects/quml-library/src/lib/mcq/mcq.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Component, OnInit, Input, SecurityContext, Output, EventEmitter, AfterV
import { DomSanitizer } from '@angular/platform-browser';
import { katex } from 'katex';
import { UtilService } from '../util-service';
import { ViewerService } from '../services/viewer-service/viewer-service';
import * as _ from 'lodash-es';

declare const katex: any;
Expand Down Expand Up @@ -35,11 +36,14 @@ export class McqComponent implements OnInit, AfterViewInit {

constructor(
public domSanitizer: DomSanitizer,
public utilService: UtilService) {
public utilService: UtilService,
public viewerService: ViewerService) {
}

ngOnInit() {
this.numberOfCorrectOptions = _.castArray(this.question.responseDeclaration.response1.correctResponse.value).length;
if(!this.viewerService.questionSetEvaluable) {
this.numberOfCorrectOptions = _.castArray(this.question.responseDeclaration.response1.correctResponse.value).length;
}
if (this.question?.solutions) {
this.solutions = this.question.solutions;
}
Expand Down
4 changes: 2 additions & 2 deletions projects/quml-library/src/lib/quml-library.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class QumlLibraryService {

constructor(public utilService: UtilService) { }

async initializeTelemetry(config: QumlPlayerConfig, parentConfig: IParentConfig) {
initializeTelemetry(config: QumlPlayerConfig, parentConfig: IParentConfig) {
if (!_.has(config, 'context') || _.isEmpty(config, 'context')) {
return;
}
Expand Down Expand Up @@ -61,7 +61,7 @@ export class QumlLibraryService {
{ id: '2.0', type: 'PlayerVersion' }
])
};
await CsTelemetryModule.instance.init({});
CsTelemetryModule.instance.init({});
CsTelemetryModule.instance.telemetryService.initTelemetry(
{
config: telemetryConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<div class="current-slide" *ngIf="currentSlideIndex !== 0">
{{myCarousel.getCurrentSlideIndex()}}/{{noOfQuestions}}
</div>
<div *ngIf="currentSolutions && showUserSolution">
<div *ngIf="currentSolutions && showUserSolution && !questionSetEvaluable">
<quml-ans (click)="getSolutions()" (keydown)="onAnswerKeyDown($event)"></quml-ans>
</div>
</div>
Expand Down Expand Up @@ -67,7 +67,7 @@
attr.aria-label="question number {{question?.index}}"
(click)="goToSlideClicked($event, question?.index)" (keydown)="onEnter($event, question?.index)"
class="showFeedBack-progressBar"
[ngClass]="(j+1) === myCarousel.getCurrentSlideIndex() ? (question.class === 'skipped' ? 'progressBar-border' : 'progressBar-border ' + question.class) : question.class">
[ngClass]="(j+1) === myCarousel.getCurrentSlideIndex() ? (question.class === 'skipped' ? 'progressBar-border' : (questionSetEvaluable ? 'att-color progressBar-border': 'progressBar-border ' + question.class)) : (questionSetEvaluable ? (question.class === 'skipped'|| question.class === 'unattempted' ? question.class : 'att-color'): question.class)">
{{question?.index}}
</li>
</ul>
Expand All @@ -89,7 +89,7 @@
attr.aria-label="question number {{question?.index}}"
(click)="goToSlideClicked($event, question?.index)" (keydown)="onEnter($event, question?.index)"
class="showFeedBack-progressBar hover-effect"
[ngClass]="(j+1) === myCarousel.getCurrentSlideIndex() ? (question.class === 'skipped' ? 'progressBar-border' : 'progressBar-border ' + question.class) : question.class">
[ngClass]="(j+1) === myCarousel.getCurrentSlideIndex() ? (question.class === 'skipped' ? 'progressBar-border' : (questionSetEvaluable ? 'att-color progressBar-border': 'progressBar-border ' + question.class)) : (questionSetEvaluable ? (question.class === 'skipped'|| question.class === 'unattempted' ? question.class : 'att-color'): question.class)">
{{question?.index}}
</li>
</ul>
Expand Down Expand Up @@ -119,11 +119,11 @@
</div>
</div>

<quml-alert *ngIf="showAlert && showFeedBack" [alertType]="alertType" [isHintAvailable]="showHints"
<quml-alert *ngIf="showAlert && showFeedBack && !questionSetEvaluable" [alertType]="alertType" [isHintAvailable]="showHints"
[showSolutionButton]="showUserSolution && currentSolutions" (showSolution)="viewSolution()" (showHint)="viewHint()"
(closeAlert)="closeAlertBox($event)"></quml-alert>

<quml-mcq-solutions *ngIf="showSolution" [question]="currentQuestion" [options]="currentOptions"
<quml-mcq-solutions *ngIf="showSolution && !questionSetEvaluable" [question]="currentQuestion" [options]="currentOptions"
[solutions]="currentSolutions" [baseUrl]="parentConfig?.baseUrl" [media]="media" [identifier]="currentQuestionIndetifier" (close)="closeSolution()"></quml-mcq-solutions>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe('SectionPlayerComponent', () => {
qumlPlayerEvent = new EventEmitter<any>();
qumlQuestionEvent = new EventEmitter<any>();
pauseVideo() { }
serverValidationCheck() {}
}

class ElementRefMock {
Expand Down Expand Up @@ -665,6 +666,34 @@ describe('SectionPlayerComponent', () => {
expect(component.isAssessEventRaised).toBeTruthy();
});

it('store response if eval mode is server', () => {
component.questionSetEvaluable = true;
component.myCarousel = myCarousel;
const option = {
"name": "optionSelect",
"option": {
"label": "<p>Narendra Modi</p>",
"value": 1,
"selected": true
},
"cardinality": "single",
"solutions": []
}
component.optionSelectedObj = {
"name": "optionSelect",
"option": {
"label": "<p>Narendra Modi</p>",
"value": 1,
"selected": true
},
"cardinality": "single",
"solutions": []
}
component.questions = mockSectionQuestions;
component.parentConfig = mockParentConfig;
component.sectionConfig = mockSectionConfig;
component.validateSelectedOption(option, "next");
});

it('should hide the popup once the time is over', fakeAsync(() => {
component.infoPopupTimeOut();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export class SectionPlayerComponent implements OnChanges, AfterViewInit {
isShuffleQuestions = false;
shuffleOptions: boolean;
playerContentCompatibiltyLevel = COMPATABILITY_LEVEL;
questionSetEvaluable: any;

constructor(
public viewerService: ViewerService,
Expand Down Expand Up @@ -216,11 +217,15 @@ export class SectionPlayerComponent implements OnChanges, AfterViewInit {
this.showWarningTimer = this.parentConfig.showWarningTimer;
this.showTimer = this.sectionConfig.metadata?.showTimer;

//server-level-validation
this.questionSetEvaluable = this.viewerService.questionSetEvaluable;

if (this.sectionConfig.metadata?.showFeedback) {
this.showFeedBack = this.sectionConfig.metadata?.showFeedback; // prioritize the section level config
} else {
this.showFeedBack = this.parentConfig.showFeedback; // Fallback to parent config
}
this.showFeedBack = this.showFeedBack && !this.questionSetEvaluable; // showFeedBack should evaluate from questionSetEvaluable field

this.showUserSolution = this.sectionConfig.metadata?.showSolutions;
this.startPageInstruction = this.sectionConfig.metadata?.instructions || this.parentConfig.instructions;
Expand Down Expand Up @@ -307,7 +312,7 @@ export class SectionPlayerComponent implements OnChanges, AfterViewInit {
}

/* istanbul ignore else */
if (this.myCarousel.isLast(this.myCarousel.getCurrentSlideIndex()) || this.noOfQuestions === this.myCarousel.getCurrentSlideIndex()) {
if (this.myCarousel.isLast(this.myCarousel.getCurrentSlideIndex()) || this.noOfQuestions === this.myCarousel.getCurrentSlideIndex() && !this.questionSetEvaluable) {
this.calculateScore();
}

Expand Down Expand Up @@ -441,7 +446,7 @@ export class SectionPlayerComponent implements OnChanges, AfterViewInit {
updateScoreForShuffledQuestion() {
const currentIndex = this.myCarousel.getCurrentSlideIndex() - 1;

if (this.isShuffleQuestions) {
if (this.isShuffleQuestions && !this.questionSetEvaluable) {
this.updateScoreBoard(currentIndex, 'correct', undefined, DEFAULT_SCORE);
}
}
Expand Down Expand Up @@ -540,7 +545,11 @@ export class SectionPlayerComponent implements OnChanges, AfterViewInit {
} else {
this.optionSelectedObj = optionSelected;
this.isAssessEventRaised = false;
this.currentSolutions = !_.isEmpty(optionSelected.solutions) ? optionSelected.solutions : undefined;
if(!this.questionSetEvaluable) {
this.currentSolutions = !_.isEmpty(optionSelected.solutions) ? optionSelected.solutions : undefined;
} else {
this.currentSolutions = undefined;
}
}
this.currentQuestionIndetifier = this.questions[currentIndex].identifier;
this.media = _.get(this.questions[currentIndex], 'media', []);
Expand Down Expand Up @@ -666,7 +675,8 @@ export class SectionPlayerComponent implements OnChanges, AfterViewInit {
if (this.optionSelectedObj) {
this.currentQuestion = selectedQuestion.body;
this.currentOptions = selectedQuestion.interactions[key].options;


if (!this.questionSetEvaluable) {
if (option.cardinality === Cardinality.single) {
const correctOptionValue = Number(selectedQuestion.responseDeclaration[key].correctResponse.value);

Expand Down Expand Up @@ -717,6 +727,13 @@ export class SectionPlayerComponent implements OnChanges, AfterViewInit {
this.alertType = 'correct';
}
}
} else {
this.updateScoreBoard(currentIndex, 'correct', undefined, 0);
if (!this.isAssessEventRaised) {
this.isAssessEventRaised = true;
this.viewerService.raiseAssesEvent(edataItem, currentIndex + 1, '', 0, [option.option], this.slideDuration);
}
}
this.optionSelectedObj = undefined;
} else if ((isQuestionSkipAllowed) || isSubjectiveQuestion || onStartPage || isActive) {
if(!_.isUndefined(type)) {
Expand Down
Loading

0 comments on commit 52dd6d4

Please sign in to comment.