Skip to content

Commit

Permalink
Merge branch 'dev' into CSCEXAM-1339
Browse files Browse the repository at this point in the history
  • Loading branch information
lupari authored Aug 12, 2024
2 parents 55d6557 + 5d9f8e7 commit b147833
Show file tree
Hide file tree
Showing 14 changed files with 400 additions and 363 deletions.
33 changes: 18 additions & 15 deletions app/util/datetime/DateTimeHandlerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import org.joda.time.DateTimeZone;
import org.joda.time.Interval;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import util.config.ConfigReader;

public class DateTimeHandlerImpl implements DateTimeHandler {
Expand Down Expand Up @@ -115,13 +114,25 @@ public List<Interval> getExceptionEvents(
DateTime end = new DateTime(ewh.getEndDate()).plusMillis(ewh.getEndDateTimezoneOffset());
Interval exception = new Interval(start, end);
Interval wholeDay = date.toInterval();
// exception covers this day fully
if (exception.contains(wholeDay) || exception.equals(wholeDay)) {
exceptions.clear();
exceptions.add(wholeDay);
break;
}
if (exception.overlaps(wholeDay)) {
exceptions.add(new Interval(exception.getStart(), exception.getEnd()));
} else if (exception.overlaps(wholeDay)) {
// exception starts this day but ends on a later day
if (start.toLocalDate().equals(date) && end.toLocalDate().isAfter(date)) {
exceptions.add(new Interval(exception.getStart(), wholeDay.getEnd()));
}
// exception ends this day but starts on an earlier day
else if (start.toLocalDate().isBefore(date) && end.toLocalDate().equals(date)) {
exceptions.add(new Interval(wholeDay.getStart(), exception.getEnd()));
}
// exception starts and ends this day
else {
exceptions.add(
new Interval(exception.getStart().withDate(date), exception.getEnd().withDate(date))
);
}
}
}
}
Expand Down Expand Up @@ -275,17 +286,9 @@ public List<OpeningHours> getWorkingHoursForDate(LocalDate date, ExamRoom room)
List<Interval> unifiedIntervals = mergeSlots(
Stream.concat(workingHours.stream().map(OpeningHours::getHours), extensionEvents.stream()).toList()
);
int tzOffset;
if (workingHours.isEmpty()) {
LocalTime lt = LocalTime.now().withHourOfDay(java.time.LocalTime.NOON.getHour());
tzOffset = DateTimeZone.forID(room.getLocalTimezone()).getOffset(date.toDateTime(lt));
} else {
tzOffset = workingHours.getFirst().getTimezoneOffset();
}
int offset = DateTimeZone.forID(room.getLocalTimezone()).getOffset(DateTime.now().withDayOfYear(1));
workingHours.clear();
workingHours.addAll(
unifiedIntervals.stream().map(interval -> new OpeningHours(interval, tzOffset)).toList()
);
workingHours.addAll(unifiedIntervals.stream().map(interval -> new OpeningHours(interval, offset)).toList());
}
if (!restrictionEvents.isEmpty()) {
for (OpeningHours hours : workingHours) {
Expand Down
241 changes: 131 additions & 110 deletions ui/src/app/exam/editor/sections/section-question.component.html
Original file line number Diff line number Diff line change
@@ -1,44 +1,55 @@
<div class="xm-study-item-container review-view mb-2">
<div class="row align-items-center">
<span class="col-md-6">
<strong class="me-3">#{{ sectionQuestion.question.id }}</strong>
<!-- question points -->
@if (
sectionQuestion.evaluationType === 'Points' ||
sectionQuestion.question.type === 'ClozeTestQuestion' ||
sectionQuestion.question.type === 'MultipleChoiceQuestion'
) {
<span> 0 / {{ sectionQuestion.maxScore }} {{ 'i18n_unit_points' | translate }} </span>
}
@if (sectionQuestion.evaluationType === 'Selection') {
<span>
{{ 'i18n_evaluation_select' | translate }}
</span>
}
@if (sectionQuestion.question.type === 'WeightedMultipleChoiceQuestion') {
<span> 0 / {{ calculateWeightedMaxPoints() }} {{ 'i18n_unit_points' | translate }} </span>
}
@if (sectionQuestion.question.type === 'ClaimChoiceQuestion') {
<span>
{{ getMinimumOptionScore() }} / {{ getCorrectClaimChoiceOptionScore() }}
{{ 'i18n_unit_points' | translate }}
</span>
}
@if (sectionQuestion.question.attachment?.id || sectionQuestion.question.attachment?.externalId) {
<span class="ms-3">
<a
class="pointer text-dark"
ngbPopover="{{ sectionQuestion.question.attachment?.fileName }}"
popoverTitle="{{ 'i18n_instructions' | translate }}"
triggers="mouseenter:mouseleave"
(click)="downloadQuestionAttachment()"
>
<i class="bi-paperclip"></i>
</a>
</span>
}
<span cdkDragHandle class="me-3">
<i
class="bi bi-arrows-vertical"
ngbPopover="{{ 'i18n_move_question' | translate }}"
popoverTitle="{{ 'i18n_instructions' | translate }}"
placement="top-left"
triggers="mouseenter:mouseleave"
></i>
</span>
<span (mousedown)="$event.stopPropagation()">
<strong class="me-3">#{{ sectionQuestion.question.id }}</strong>
<!-- question points -->
@if (
sectionQuestion.evaluationType === 'Points' ||
sectionQuestion.question.type === 'ClozeTestQuestion' ||
sectionQuestion.question.type === 'MultipleChoiceQuestion'
) {
<span> 0 / {{ sectionQuestion.maxScore }} {{ 'i18n_unit_points' | translate }} </span>
}
@if (sectionQuestion.evaluationType === 'Selection') {
<span>
{{ 'i18n_evaluation_select' | translate }}
</span>
}
@if (sectionQuestion.question.type === 'WeightedMultipleChoiceQuestion') {
<span> 0 / {{ calculateWeightedMaxPoints() }} {{ 'i18n_unit_points' | translate }} </span>
}
@if (sectionQuestion.question.type === 'ClaimChoiceQuestion') {
<span>
{{ getMinimumOptionScore() }} / {{ getCorrectClaimChoiceOptionScore() }}
{{ 'i18n_unit_points' | translate }}
</span>
}
@if (sectionQuestion.question.attachment?.id || sectionQuestion.question.attachment?.externalId) {
<span class="ms-3">
<a
class="pointer text-dark"
ngbPopover="{{ sectionQuestion.question.attachment?.fileName }}"
popoverTitle="{{ 'i18n_instructions' | translate }}"
triggers="mouseenter:mouseleave"
(click)="downloadQuestionAttachment()"
>
<i class="bi-paperclip"></i>
</a>
</span>
}
</span>
</span>
<div class="col" ngbDropdown>
<div class="col" (mousedown)="$event.stopPropagation()" ngbDropdown>
<button class="btn btn-outline-dark float-end" ngbDropdownToggle>
{{ 'i18n_settings' | translate }}
</button>
Expand All @@ -49,89 +60,99 @@
</div>
</div>
</div>
<div class="row mt-3">
<!-- Question -->
<div class="col-md-12">
<div class="make-inline" [xmMathJax]="sectionQuestion.question.question"></div>
<div (mousedown)="$event.stopPropagation()">
<div class="row mt-3">
<!-- Question -->
<div class="col-md-12">
<div class="make-inline" [xmMathJax]="sectionQuestion.question.question"></div>
</div>
</div>
</div>
<div class="row mt-2">
<div class="col-md-12">
@if (sectionQuestion.answerInstructions || sectionQuestion.options.length > 0) {
<button
(click)="sectionQuestion.expanded = !sectionQuestion.expanded"
class="btn btn-outline-dark"
[attr.aria-expanded]="sectionQuestion.expanded"
>
<span [hidden]="sectionQuestion.expanded">{{ 'i18n_show_more' | translate }}</span>
<span [hidden]="!sectionQuestion.expanded">{{ 'i18n_hide' | translate }}</span>
<i [hidden]="sectionQuestion.expanded" class="bi bi-chevron-right ms-2" alt="hide evaluation"></i>
<i [hidden]="!sectionQuestion.expanded" class="bi bi-chevron-down ms-2" alt="show evaluation"></i>
</button>
}
<div class="row mt-2">
<div class="col-md-12">
@if (sectionQuestion.answerInstructions || sectionQuestion.options.length > 0) {
<button
(click)="sectionQuestion.expanded = !sectionQuestion.expanded"
class="btn btn-outline-dark"
[attr.aria-expanded]="sectionQuestion.expanded"
>
<span [hidden]="sectionQuestion.expanded">{{ 'i18n_show_more' | translate }}</span>
<span [hidden]="!sectionQuestion.expanded">{{ 'i18n_hide' | translate }}</span>
<i
[hidden]="sectionQuestion.expanded"
class="bi bi-chevron-right ms-2"
alt="hide evaluation"
></i>
<i
[hidden]="!sectionQuestion.expanded"
class="bi bi-chevron-down ms-2"
alt="show evaluation"
></i>
</button>
}
</div>
</div>
</div>
<div class="row mt-1" [ngbCollapse]="!sectionQuestion.expanded">
<div class="col-md-12">
@if (sectionQuestion.answerInstructions && sectionQuestion.answerInstructions.length > 0) {
<div class="row my-4 ms-2">
<div class="col-md-12" role="note">
<img src="/assets/images/icon_info.png" alt="" />
{{ sectionQuestion.answerInstructions }}
<div class="row mt-1" [ngbCollapse]="!sectionQuestion.expanded">
<div class="col-md-12">
@if (sectionQuestion.answerInstructions && sectionQuestion.answerInstructions.length > 0) {
<div class="row my-4 ms-2">
<div class="col-md-12" role="note">
<img src="/assets/images/icon_info.png" alt="" />
{{ sectionQuestion.answerInstructions }}
</div>
</div>
</div>
}
@switch (sectionQuestion.question.type) {
@case ('MultipleChoiceQuestion') {
@for (option of sectionQuestion.options; track option) {
<div class="row ms-2 mt-2">
<div class="col-md-12">
@if (option.option.correctOption) {
<img src="/assets/images/icon_correct_answer.png" alt="" />
} @else {
<img src="/assets/images/icon_wrong_answer.png" alt="" />
}
{{ option.option.option }}
}
@switch (sectionQuestion.question.type) {
@case ('MultipleChoiceQuestion') {
@for (option of sectionQuestion.options; track option) {
<div class="row ms-2 mt-2">
<div class="col-md-12">
@if (option.option.correctOption) {
<img src="/assets/images/icon_correct_answer.png" alt="" />
} @else {
<img src="/assets/images/icon_wrong_answer.png" alt="" />
}
{{ option.option.option }}
</div>
</div>
</div>
}
}
}
@case ('WeightedMultipleChoiceQuestion') {
@for (option of sectionQuestion.options; track option) {
<div class="row ms-2 mt-2">
<div class="col-md-12">
@if (option.score >= 0) {
<img src="/assets/images/icon_correct_answer_checkbox.png" alt="" />
}
@if (option.score < 0) {
<img src="/assets/images/icon_wrong_answer_checkbox.png" alt="" />
}
<span class="ps-2">{{ option.option.option }}</span>
<span class="ps-2">{{ option.score }} {{ 'i18n_unit_points' | translate }}</span>
@case ('WeightedMultipleChoiceQuestion') {
@for (option of sectionQuestion.options; track option) {
<div class="row ms-2 mt-2">
<div class="col-md-12">
@if (option.score >= 0) {
<img src="/assets/images/icon_correct_answer_checkbox.png" alt="" />
}
@if (option.score < 0) {
<img src="/assets/images/icon_wrong_answer_checkbox.png" alt="" />
}
<span class="ps-2">{{ option.option.option }}</span>
<span class="ps-2">{{ option.score }} {{ 'i18n_unit_points' | translate }}</span>
</div>
</div>
</div>
}
}
}
@case ('ClaimChoiceQuestion') {
@for (option of sectionQuestion.options | orderBy: 'option.id'; track option) {
<div class="row ms-2 mt-2">
<div class="col-md-12">
@if (determineClaimOptionType(option) === 'CorrectOption') {
<img src="/assets/images/icon_correct_answer_radio.png" alt="" />
}
@if (determineClaimOptionType(option) === 'IncorrectOption') {
<img src="/assets/images/icon_wrong_answer_radio.png" alt="" />
}
@if (determineClaimOptionType(option) === 'SkipOption') {
<img src="/assets/images/icon_wrong_answer.png" alt="" />
}
<span class="ps-2">{{ option.option.option }}</span>
<span class="ps-2">{{ option.score }} {{ 'i18n_unit_points' | translate }}</span>
@case ('ClaimChoiceQuestion') {
@for (option of sectionQuestion.options | orderBy: 'option.id'; track option) {
<div class="row ms-2 mt-2">
<div class="col-md-12">
@if (determineClaimOptionType(option) === 'CorrectOption') {
<img src="/assets/images/icon_correct_answer_radio.png" alt="" />
}
@if (determineClaimOptionType(option) === 'IncorrectOption') {
<img src="/assets/images/icon_wrong_answer_radio.png" alt="" />
}
@if (determineClaimOptionType(option) === 'SkipOption') {
<img src="/assets/images/icon_wrong_answer.png" alt="" />
}
<span class="ps-2">{{ option.option.option }}</span>
<span class="ps-2">{{ option.score }} {{ 'i18n_unit_points' | translate }}</span>
</div>
</div>
</div>
}
}
}
}
</div>
</div>
</div>
</div>
2 changes: 2 additions & 0 deletions ui/src/app/exam/editor/sections/section-question.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* See the Licence for the specific language governing permissions and limitations under the Licence.
*/

import { CdkDragHandle } from '@angular/cdk/drag-drop';
import { HttpClient } from '@angular/common/http';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import {
Expand Down Expand Up @@ -44,6 +45,7 @@ import { OrderByPipe } from 'src/app/shared/sorting/order-by.pipe';
templateUrl: './section-question.component.html',
standalone: true,
imports: [
CdkDragHandle,
NgbPopover,
NgbDropdown,
NgbDropdownToggle,
Expand Down
Loading

0 comments on commit b147833

Please sign in to comment.