Skip to content

Commit

Permalink
Programming exercises: Add simple mode to create and edit view (#9283)
Browse files Browse the repository at this point in the history
  • Loading branch information
florian-glombik authored Oct 29, 2024
1 parent 7503f9c commit ac4c2c1
Show file tree
Hide file tree
Showing 75 changed files with 2,292 additions and 988 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package de.tum.cit.aet.artemis.core.dto;

import java.util.Set;

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record CourseExistingExerciseDetailsDTO(Set<String> exerciseTitles, Set<String> shortNames) {
}
34 changes: 34 additions & 0 deletions src/main/java/de/tum/cit/aet/artemis/core/web/CourseResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import de.tum.cit.aet.artemis.core.config.Constants;
import de.tum.cit.aet.artemis.core.domain.Course;
import de.tum.cit.aet.artemis.core.domain.User;
import de.tum.cit.aet.artemis.core.dto.CourseExistingExerciseDetailsDTO;
import de.tum.cit.aet.artemis.core.dto.CourseForArchiveDTO;
import de.tum.cit.aet.artemis.core.dto.CourseForDashboardDTO;
import de.tum.cit.aet.artemis.core.dto.CourseForImportDTO;
Expand All @@ -97,6 +98,7 @@
import de.tum.cit.aet.artemis.core.security.annotations.EnforceAtLeastInstructor;
import de.tum.cit.aet.artemis.core.security.annotations.EnforceAtLeastStudent;
import de.tum.cit.aet.artemis.core.security.annotations.EnforceAtLeastTutor;
import de.tum.cit.aet.artemis.core.security.annotations.enforceRoleInCourse.EnforceAtLeastEditorInCourse;
import de.tum.cit.aet.artemis.core.service.AuthorizationCheckService;
import de.tum.cit.aet.artemis.core.service.CourseService;
import de.tum.cit.aet.artemis.core.service.FilePathService;
Expand All @@ -107,6 +109,7 @@
import de.tum.cit.aet.artemis.exam.repository.ExamRepository;
import de.tum.cit.aet.artemis.exercise.domain.Exercise;
import de.tum.cit.aet.artemis.exercise.domain.ExerciseMode;
import de.tum.cit.aet.artemis.exercise.domain.ExerciseType;
import de.tum.cit.aet.artemis.exercise.domain.Submission;
import de.tum.cit.aet.artemis.exercise.domain.Team;
import de.tum.cit.aet.artemis.exercise.domain.participation.Participant;
Expand Down Expand Up @@ -1473,4 +1476,35 @@ public ResponseEntity<Long> getNumberOfAllowedComplaintsInCourse(@PathVariable L
long unacceptedComplaints = complaintService.countUnacceptedComplaintsByParticipantAndCourseId(participant, courseId);
return ResponseEntity.ok(Math.max(complaintService.getMaxComplaintsPerParticipant(course, participant) - unacceptedComplaints, 0));
}

/**
* GET courses/{courseId}/existing-exercise-details: Get the exercise names (and shortNames for {@link ExerciseType#PROGRAMMING} exercises)
* of all exercises with the given type in the given course.
*
* @param courseId of the course for which all exercise names should be fetched
* @param exerciseType for which the details should be fetched, as the name of an exercise only needs to be unique for each exercise type
* @return {@link CourseExistingExerciseDetailsDTO} with the exerciseNames (and already used shortNames if a {@link ExerciseType#PROGRAMMING} exercise is requested)
*/
@GetMapping("courses/{courseId}/existing-exercise-details")
@EnforceAtLeastEditorInCourse
public ResponseEntity<CourseExistingExerciseDetailsDTO> getExistingExerciseDetails(@PathVariable Long courseId, @RequestParam String exerciseType) {
log.debug("REST request to get details of existing exercises in course : {}", courseId);
Course course = courseRepository.findByIdWithEagerExercisesElseThrow(courseId);

Set<String> alreadyTakenExerciseNames = new HashSet<>();
Set<String> alreadyTakenShortNames = new HashSet<>();

boolean includeShortNames = exerciseType.equals(ExerciseType.PROGRAMMING.toString());

course.getExercises().forEach((exercise -> {
if (exercise.getType().equals(exerciseType)) {
alreadyTakenExerciseNames.add(exercise.getTitle());
if (includeShortNames && exercise.getShortName() != null) {
alreadyTakenShortNames.add(exercise.getShortName());
}
}
}));

return ResponseEntity.ok(new CourseExistingExerciseDetailsDTO(alreadyTakenExerciseNames, alreadyTakenShortNames));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ export class CourseDetailComponent implements OnInit, OnDestroy {
if (this.paramSub) {
this.paramSub.unsubscribe();
}
this.eventManager.destroy(this.eventSubscriber);
this.eventManager?.destroy(this.eventSubscriber);
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/main/webapp/app/exam/manage/exam-management.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ const ENTITY_STATES = [...examManagementState];
ArtemisMarkdownEditorModule,
NgxDatatableModule,
ArtemisDataTableModule,
ArtemisTextExerciseModule,
ArtemisFileUploadExerciseManagementModule,
ArtemisProgrammingExerciseManagementModule,
ArtemisQuizManagementModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
<div class="d-flex align-items-center">
@if (!isImport) {
<h4 jhiTranslate="artemisApp.examManagement.createExam"></h4>
}
@if (isImport) {
} @else {
<h4 jhiTranslate="artemisApp.examManagement.importExam"></h4>
}
<jhi-documentation-button [type]="documentationType" />
Expand Down
18 changes: 9 additions & 9 deletions src/main/webapp/app/exam/manage/exams/exam-update.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,27 @@ import { examWorkingTime, normalWorkingTime } from 'app/exam/participate/exam.ut
templateUrl: './exam-update.component.html',
})
export class ExamUpdateComponent implements OnInit, OnDestroy {
protected readonly faSave = faSave;
protected readonly faBan = faBan;
protected readonly faExclamationTriangle = faExclamationTriangle;
protected readonly documentationType: DocumentationType = 'Exams';

exam: Exam;
course: Course;
isSaving: boolean;
isImport = false;
isImportInSameCourse = false;
hideChannelNameInput = false;

hideChannelNameInput = false;
private originalStartDate?: dayjs.Dayjs;

private originalEndDate?: dayjs.Dayjs;

private componentActive = true;

// Link to the component enabling the selection of exercise groups and exercises for import
@ViewChild(ExamExerciseImportComponent) examExerciseImportComponent: ExamExerciseImportComponent;
@ViewChild('workingTimeConfirmationContent') public workingTimeConfirmationContent: TemplateRef<any>;

readonly documentationType: DocumentationType = 'Exams';

// Icons
faSave = faSave;
faBan = faBan;
faExclamationTriangle = faExclamationTriangle;
@ViewChild('workingTimeConfirmationContent') public workingTimeConfirmationContent: TemplateRef<any>;

constructor(
private route: ActivatedRoute,
Expand Down Expand Up @@ -471,6 +470,7 @@ export class ExamUpdateComponent implements OnInit, OnDestroy {
dayjs(this.exam.exampleSolutionPublicationDate).isBefore(this.exam.endDate || null)
);
}

/**
* Default exam start text, which can be edited by instructors in the text editor
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,14 @@ import { faPlus } from '@fortawesome/free-solid-svg-icons';
`,
})
export class AddAuxiliaryRepositoryButtonComponent {
ButtonType = ButtonType;
ButtonSize = ButtonSize;
protected readonly ButtonType = ButtonType;
protected readonly ButtonSize = ButtonSize;
protected readonly faPlus = faPlus;

@Input() programmingExercise: ProgrammingExercise;

@Output() onRefresh: EventEmitter<any> = new EventEmitter<any>();

// Icons
faPlus = faPlus;

/**
* Adds a new auxiliary repository, which is displayed as a new row, to the respective programming exercise and activates the angular change detection.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ <h2 id="jhi-programming-exercise-heading-import" jhiTranslate="artemisApp.progra
}
<jhi-documentation-button [type]="documentationType" />
</div>
<jhi-form-status-bar [formStatusSections]="formStatusSections" />
<jhi-form-status-bar [formStatusSections]="formStatusSections()" />
<form name="editForm" role="form" novalidate #editForm="ngForm" (keydown.enter)="isEventInsideTextArea($event)">
<div class="update-programming-exercise">
<jhi-programming-exercise-info
Expand All @@ -19,19 +19,33 @@ <h2 id="jhi-programming-exercise-heading-import" jhiTranslate="artemisApp.progra
[isImport]="isImportFromExistingExercise || isImportFromFile"
[isLocal]="isLocal"
[importOptions]="importOptions"
[isSimpleMode]="isSimpleMode()"
[isEditFieldDisplayedRecord]="isEditFieldDisplayedRecord()"
[courseId]="courseId"
[(isAuxiliaryRepositoryInputValid)]="isAuxiliaryRepositoryInputValid"
/>
<hr class="mb-5" />
<jhi-programming-exercise-difficulty
@if (!isSimpleMode()) {
<!-- The mode section would only contain the difficulty in the simple mode,
in the simple mode the difficulty will be part of the general section -->
<jhi-programming-exercise-mode
[programmingExercise]="programmingExercise"
[programmingExerciseCreationConfig]="getProgrammingExerciseCreationConfig()"
[isEditFieldDisplayedRecord]="isEditFieldDisplayedRecord()"
(triggerValidation)="calculateFormStatusSections()"
/>
<hr class="mb-5" />
}
<jhi-programming-exercise-language
[programmingExercise]="programmingExercise"
[programmingExerciseCreationConfig]="getProgrammingExerciseCreationConfig()"
(triggerValidation)="calculateFormStatusSections()"
[isEditFieldDisplayedRecord]="isEditFieldDisplayedRecord()"
/>
<hr class="mb-5" />
<jhi-programming-exercise-language [programmingExercise]="programmingExercise" [programmingExerciseCreationConfig]="getProgrammingExerciseCreationConfig()" />
<hr class="mb-5" />
<jhi-programming-exercise-problem
[(exercise)]="programmingExercise"
[programmingExerciseCreationConfig]="getProgrammingExerciseCreationConfig()"
[isEditFieldDisplayedRecord]="isEditFieldDisplayedRecord()"
(problemStatementChange)="calculateFormStatusSections()"
/>
<hr class="mb-5" />
Expand All @@ -40,18 +54,22 @@ <h2 id="jhi-programming-exercise-heading-import" jhiTranslate="artemisApp.progra
[programmingExercise]="programmingExercise"
[programmingExerciseCreationConfig]="getProgrammingExerciseCreationConfig()"
[importOptions]="importOptions"
[isEditFieldDisplayedRecord]="isEditFieldDisplayedRecord()"
/>
@if (!isExamMode) {
@if (isEditFieldDisplayedRecord().plagiarismControl && !isExamMode) {
<jhi-exercise-update-plagiarism [exercise]="programmingExercise" />
}
<jhi-form-footer
[isCreation]="!programmingExercise.id"
[isImport]="isImportFromExistingExercise || isImportFromFile"
[isSaving]="isSaving"
[(notificationText)]="notificationText"
[isSimpleMode]="isSimpleMode()"
[switchEditMode]="switchEditMode"
[areAuxiliaryRepositoriesValid]="isAuxiliaryRepositoryInputValid()"
[invalidReasons]="getInvalidReasons()"
(save)="save()"
(onCancel)="previousState()"
[(notificationText)]="notificationText"
/>
</div>
</form>
Expand Down
Loading

0 comments on commit ac4c2c1

Please sign in to comment.