Skip to content

Commit

Permalink
CSCEXAM-1214
Browse files Browse the repository at this point in the history
  • Loading branch information
VirmasaloA authored and Matti Lupari committed Nov 29, 2023
1 parent 68fd1f9 commit 828551f
Show file tree
Hide file tree
Showing 17 changed files with 178 additions and 28 deletions.
1 change: 1 addition & 0 deletions ui/src/app/examination/examination.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ import { ExaminationSectionComponent } from './section/examination-section.compo
DynamicClozeTestComponent,
],
providers: [ExaminationService, ExaminationStatusService],
exports: [ExaminationQuestionComponent],
})
export class ExaminationModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
{{ sq.derivedMaxScore }} {{ 'sitnet_unit_points' | translate }}
</span>
</div>
<div *ngIf="exam.implementation !== 'CLIENT_AUTH' && sq.essayAnswer?.attachment?.fileName" class="col-md-9 mt-2">
<div *ngIf="exam?.implementation !== 'CLIENT_AUTH' && sq.essayAnswer?.attachment?.fileName" class="col-md-9 mt-2">
<span class="float-end">
<span class="pe-2 filename-text">{{ sq.essayAnswer?.attachment?.fileName | uppercase }}</span>
<button class="pointer green_button" (click)="removeQuestionAnswerAttachment()">
Expand All @@ -56,7 +56,7 @@
{{ 'sitnet_save' | translate }}
</button>
</div>
<div class="col-md-6" *ngIf="exam.implementation !== 'CLIENT_AUTH' && sq.essayAnswer">
<div class="col-md-6" *ngIf="exam?.implementation !== 'CLIENT_AUTH' && sq.essayAnswer">
<div class="float-end mart10">
<div class="filename-text" *ngIf="!sq.essayAnswer.attachment?.fileName">
{{ 'sitnet_no_attachment' | translate }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { ExaminationService } from '../examination.service';
})
export class ExaminationEssayQuestionComponent implements OnInit {
@Input() sq!: Omit<ExaminationQuestion, 'essayAnswer'> & { essayAnswer: EssayAnswer };
@Input() exam!: Examination;
@Input() exam?: Examination;
@Input() isPreview = false;

questionTitle!: string;
Expand All @@ -48,22 +48,23 @@ export class ExaminationEssayQuestionComponent implements OnInit {
const decodedString = doc.documentElement.innerText;
this.questionTitle = decodedString;
}
saveAnswer = () => this.Examination.saveTextualAnswer$(this.sq, this.exam.hash, false, false).subscribe();
saveAnswer = () => this.Examination.saveTextualAnswer$(this.sq, this.exam?.hash || '', false, false).subscribe();

removeQuestionAnswerAttachment = () => {
const answeredQuestion = this.sq as AnsweredQuestion; // TODO: no casting
if (this.exam.external) {
if (this.exam?.external) {
this.Attachment.removeExternalQuestionAnswerAttachment(answeredQuestion, this.exam.hash);
return;
}
this.Attachment.removeQuestionAnswerAttachment(answeredQuestion);
};

selectFile = () => {
if (this.isPreview) {
if (this.isPreview || !this.exam) {
return;
}
this.Attachment.selectFile(false).then((data) => {
if (this.exam.external) {
if (this.exam?.external) {
this.Files.uploadAnswerAttachment(
'/app/iop/attachment/question/answer',
data.$value.attachmentFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
</div>
</div>
</div>
<!-- Expand button -->
<div class="col-auto">
<div
tabindex="0"
Expand Down Expand Up @@ -85,24 +86,24 @@
<xm-examination-cloze-test
*ngSwitchCase="'ClozeTestQuestion'"
[sq]="sq"
[examHash]="exam.hash"
[examHash]="exam?.hash || ''"
[isPreview]="isPreview"
>
</xm-examination-cloze-test>

<xm-examination-multi-choice-question
*ngSwitchCase="'MultipleChoiceQuestion'"
[sq]="sq"
[examHash]="exam.hash"
[examHash]="exam?.hash || ''"
[isPreview]="isPreview"
[orderOptions]="!exam.external"
[orderOptions]="!exam?.external"
>
</xm-examination-multi-choice-question>

<xm-examination-multi-choice-question
*ngSwitchCase="'ClaimChoiceQuestion'"
[sq]="sq"
[examHash]="exam.hash"
[examHash]="exam?.hash || ''"
[isPreview]="isPreview"
[orderOptions]="true"
>
Expand All @@ -111,9 +112,9 @@
<xm-examination-weighted-multi-choice-question
*ngSwitchCase="'WeightedMultipleChoiceQuestion'"
[sq]="sq"
[examHash]="exam.hash"
[examHash]="exam?.hash || ''"
[isPreview]="isPreview"
[orderOptions]="!exam.external"
[orderOptions]="!exam?.external"
>
</xm-examination-weighted-multi-choice-question>
</div>
Expand Down
17 changes: 10 additions & 7 deletions ui/src/app/examination/question/examination-question.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type ClozeTestAnswer = { [key: string]: string };
templateUrl: './examination-question.component.html',
})
export class ExaminationQuestionComponent implements OnInit, AfterViewInit {
@Input() exam!: Examination;
@Input() exam?: Examination;
@Input() question!: ExaminationQuestion;
@Input() isPreview = false;
@Input() isCollaborative = false;
Expand Down Expand Up @@ -67,12 +67,15 @@ export class ExaminationQuestionComponent implements OnInit, AfterViewInit {
};

downloadQuestionAttachment = () => {
if (this.exam.external) {
this.Attachment.downloadExternalQuestionAttachment(this.exam, this.sq);
} else if (this.isCollaborative) {
this.Attachment.downloadCollaborativeQuestionAttachment(this.exam.id, this.sq);
} else {
this.Attachment.downloadQuestionAttachment(this.sq.question);
if (this.exam) {
if (this.exam.external) {
this.Attachment.downloadExternalQuestionAttachment(this.exam, this.sq);
} else if (this.isCollaborative) {
this.Attachment.downloadCollaborativeQuestionAttachment(this.exam.id, this.sq);
} else {
this.Attachment.downloadQuestionAttachment(this.sq.question);
}
console.error('Cannot retrieve attachment without exam.');
}
};

Expand Down
4 changes: 2 additions & 2 deletions ui/src/app/question/basequestion/question-body.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class QuestionBodyComponent implements OnInit {
@Input() currentOwners: User[] = [];
@Input() lotteryOn = false;
@Input() examId = 0;
@Input() sectionQuestion!: ExamSectionQuestion;
@Input() sectionQuestion?: ExamSectionQuestion;
@Input() collaborative = false;

isInPublishedExam = false;
Expand Down Expand Up @@ -128,7 +128,7 @@ export class QuestionBodyComponent implements OnInit {
});

downloadQuestionAttachment = () => {
if (this.question.attachment && this.question.attachment.externalId) {
if (this.question.attachment && this.question.attachment.externalId && this.sectionQuestion) {
this.Attachment.downloadCollaborativeQuestionAttachment(this.examId, this.sectionQuestion);
return;
}
Expand Down
16 changes: 16 additions & 0 deletions ui/src/app/question/basequestion/question.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@
</form>
<!-- buttons -->
<div class="mart20">
<div class="question-cancel marl20">
<button
(click)="openPreview()"
type="submit"
class="btn btn-success float-end bigbutton"
[disabled]="
!question ||
!question.type ||
hasNoCorrectOption() ||
hasInvalidClaimChoiceOptions() ||
questionForm.invalid
"
>
{{ 'sitnet_button_preview' | translate }}
</button>
</div>
<div class="question-cancel">
<button
[disabled]="
Expand Down
22 changes: 20 additions & 2 deletions ui/src/app/question/basequestion/question.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ToastrService } from 'ngx-toastr';
import { from } from 'rxjs';
import type { ExamSectionQuestion, Question, ReverseQuestion } from '../../exam/exam.model';
import type { User } from '../../session/session.service';
import { CanComponentDeactivate } from '../has-unsaved-changes.quard';
import { QuestionPreviewDialogComponent } from '../previewquestion/preview-question';
import type { QuestionDraft } from '../question.service';
import { QuestionService } from '../question.service';

Expand All @@ -33,7 +36,7 @@ export class QuestionComponent implements OnInit, OnDestroy, CanComponentDeactiv
@Input() lotteryOn = false;
@Input() collaborative = false;
@Input() examId = 0;
@Input() sectionQuestion!: ExamSectionQuestion;
@Input() sectionQuestion?: ExamSectionQuestion;

@Output() saved = new EventEmitter<Question | QuestionDraft>();
@Output() cancelled = new EventEmitter<void>();
Expand All @@ -42,7 +45,6 @@ export class QuestionComponent implements OnInit, OnDestroy, CanComponentDeactiv

currentOwners: User[] = [];
question!: ReverseQuestion | QuestionDraft;
transitionWatcher?: unknown;
cancelClicked = false;
nextState = '';

Expand All @@ -51,6 +53,7 @@ export class QuestionComponent implements OnInit, OnDestroy, CanComponentDeactiv
private route: ActivatedRoute,
private toast: ToastrService,
private Question: QuestionService,
private modal: NgbModal,
) {}

ngOnInit() {
Expand Down Expand Up @@ -95,6 +98,21 @@ export class QuestionComponent implements OnInit, OnDestroy, CanComponentDeactiv
this.question.type === 'ClaimChoiceQuestion' &&
this.Question.getInvalidClaimOptionTypes(this.question.options).length > 0;

openPreview = () => {
const modal = this.modal.open(QuestionPreviewDialogComponent, {
backdrop: 'static',
keyboard: true,
size: 'lg',
});
modal.componentInstance.question =
this.sectionQuestion || ({ question: this.question as Question } as ExamSectionQuestion);
from(modal.result).subscribe({
next: () => {
this.saveQuestion();
},
});
};

saveQuestion = () => {
this.question.questionOwners = this.currentOwners;
const fn = (q: Question | QuestionDraft) => {
Expand Down
10 changes: 10 additions & 0 deletions ui/src/app/question/examquestion/exam-question.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,16 @@
</div>
<div class="row padl40 padr40">
<div class="col-md-12 mart20">
<div class="question-cancel marl20">
<button
(click)="openPreview()"
type="submit"
class="btn btn-success float-end bigbutton"
[disabled]="questionForm.invalid || hasInvalidClaimChoiceOptions()"
>
{{ 'sitnet_button_preview' | translate }}
</button>
</div>
<div class="question-cancel">
<button
[disabled]="questionForm.invalid || hasInvalidClaimChoiceOptions()"
Expand Down
18 changes: 18 additions & 0 deletions ui/src/app/question/examquestion/exam-question.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
import { HttpClient } from '@angular/common/http';
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import { ToastrService } from 'ngx-toastr';
import { from } from 'rxjs';
import type {
ExamSectionQuestion,
ExamSectionQuestionOption,
Expand All @@ -25,6 +27,7 @@ import type {
ReverseQuestion,
} from '../../exam/exam.model';
import { AttachmentService } from '../../shared/attachment/attachment.service';
import { QuestionPreviewDialogComponent } from '../previewquestion/preview-question';
import { QuestionService } from '../question.service';

// This component depicts a distributed exam question
Expand All @@ -51,6 +54,7 @@ export class ExamQuestionComponent implements OnInit, OnDestroy {
private toast: ToastrService,
private Question: QuestionService,
private Attachment: AttachmentService,
private modal: NgbModal,
) {}

ngOnInit() {
Expand All @@ -69,6 +73,20 @@ export class ExamQuestionComponent implements OnInit, OnDestroy {

cancel = () => this.cancelled.emit({ dirty: this.questionForm?.dirty || false });

openPreview = () => {
const modal = this.modal.open(QuestionPreviewDialogComponent, {
backdrop: 'static',
keyboard: true,
size: 'lg',
});
modal.componentInstance.question = this.examQuestion;
from(modal.result).subscribe({
next: () => {
this.save();
},
});
};

showWarning = () => this.examNames && this.examNames.length > 1;
estimateCharacters = () => (this.examQuestion.expectedWordCount || 0) * 8;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
</th>
<th>{{ 'sitnet_remove' | translate }}</th>
<th>{{ 'sitnet_copy' | translate }}</th>
<th>{{ 'sitnet_used_in_exams' | translate }}</th>
</tr>
</thead>
<tbody>
Expand Down Expand Up @@ -180,6 +181,9 @@
></i>
</a>
</td>
<td>
{{ examSectionQuestionsLength(question) }}
</td>
</tr>
<!--Fill if page not full-->
<tr *ngFor="let r of [] | pageFill : questions.length : currentPage : pageSize">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export class LibraryResultsComponent implements OnInit, OnChanges {
this.selected.emit(selections);
};

examSectionQuestionsLength = (question: LibraryQuestion): number => question.examSectionQuestions.length;

deleteQuestion = (question: SelectableQuestion) =>
this.Confirmation.open$(
this.translate.instant('sitnet_confirm'),
Expand Down
58 changes: 58 additions & 0 deletions ui/src/app/question/previewquestion/preview-question.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2018 Exam Consortium
*
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is distributed
* on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and limitations under the Licence.
*
*/
import { Component, Input } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { ExaminationQuestion } from '../../examination/examination.model';

@Component({
selector: 'xm-publication-delete-dialog',
template: `<div id="sitnet-dialog" role="dialog" aria-modal="true">
<div class="student-message-dialog-wrapper-padding" *ngIf="runme()">
<div class="student-enroll-dialog-wrap">
<div class="student-enroll-title">{{ 'sitnet_preview_question' | translate }}</div>
</div>
<xm-examination-question
*ngIf="question"
[question]="question"
[isPreview]="true"
[isCollaborative]="false"
></xm-examination-question>
<div class="modal-footer">
<div class="student-message-dialog-button-save float-end">
<button class="btn btn-sm btn-primary" (click)="activeModal.close()" autofocus>
{{ 'sitnet_save' | translate }}
</button>
</div>
<div class="student-message-dialog-button-cancel">
<button class="btn btn-sm btn-danger" (click)="activeModal.dismiss()">
{{ 'sitnet_go_back' | translate }}
</button>
</div>
</div>
</div>
</div> `,
})
export class QuestionPreviewDialogComponent {
@Input() question?: ExaminationQuestion;

constructor(public activeModal: NgbActiveModal) {}
runme = () => {
console.log('test question:');
console.log(this.question); //TODO DELETEME
console.log(this.question?.question.question);
return true;
};
}
Loading

0 comments on commit 828551f

Please sign in to comment.