Skip to content

Commit

Permalink
Merge branch 'develop' into feature/text-exercises/immediate-prelimin…
Browse files Browse the repository at this point in the history
…ary-feedback
  • Loading branch information
FelixTJDietrich authored Sep 10, 2024
2 parents 20d3811 + 8b80d61 commit 9618c23
Show file tree
Hide file tree
Showing 20 changed files with 121 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,18 @@ public class BuildLogEntryService {

private final ProgrammingSubmissionRepository programmingSubmissionRepository;

private final ProfileService profileService;

@Value("${artemis.continuous-integration.build-log.file-expiry-days:30}")
private int expiryDays;

@Value("${artemis.build-logs-path:./build-logs}")
private Path buildLogsPath;

public BuildLogEntryService(BuildLogEntryRepository buildLogEntryRepository, ProgrammingSubmissionRepository programmingSubmissionRepository) {
public BuildLogEntryService(BuildLogEntryRepository buildLogEntryRepository, ProgrammingSubmissionRepository programmingSubmissionRepository, ProfileService profileService) {
this.buildLogEntryRepository = buildLogEntryRepository;
this.programmingSubmissionRepository = programmingSubmissionRepository;
this.profileService = profileService;
}

/**
Expand Down Expand Up @@ -331,10 +334,30 @@ public FileSystemResource retrieveBuildLogsFromFileForBuildJob(String buildJobId
}

/**
* Deletes all build log files that are older than {@link #expiryDays} days on a schedule
* Scheduled task that deletes old build log files from the continuous integration system.
* <p>
* This method runs based on the cron schedule defined in the application properties, with
* a default value of 3:00 AM every day if no custom schedule is provided.
* The task will only execute if scheduling is active, which is checked via the {@code profileService}.
* </p>
* <p>
* The method iterates through the files in the configured build logs directory and deletes
* files that were last modified before the configured expiry period (in days). The expiration
* period is specified by the {@code expiryDays} variable, and files older than this period are deleted.
* </p>
* <p>
* In case of an error during file deletion, it logs the error and continues processing.
* </p>
*
* @throws IOException if an I/O error occurs while accessing the build log files directory or
* deleting files.
*/
@Scheduled(cron = "${artemis.continuous-integration.build-log.cleanup-schedule:0 0 3 1 * ?}")
@Scheduled(cron = "${artemis.continuous-integration.build-log.cleanup-schedule:0 0 3 * * ?}")
public void deleteOldBuildLogsFiles() {
// only execute this if scheduling is active
if (!profileService.isSchedulingActive()) {
return;
}
log.info("Deleting old build log files");
ZonedDateTime now = ZonedDateTime.now();

Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/config/application-artemis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ artemis:
notification-plugin: "ls1tum/artemis-notification-plugin:1.0.0" # Docker image for the generic notification plugin. This value is set in an CI variable in GitLab CI.
build-log:
file-expiry-days: 30 # The amount of days until build log files can be deleted
cleanup-schedule: 0 0 3 1 * ? # Cron expression for schedule to delete old build log files
cleanup-schedule: 0 0 3 * * ? # Cron expression for schedule to delete old build log files
git:
name: Artemis
email: [email protected]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ export class CourseManagementService {
this.entityTitleService.setTitle(EntityType.COURSE, [course?.id], course?.title);

course?.exercises?.forEach((exercise) => {
this.entityTitleService.setTitle(EntityType.EXERCISE, [exercise.id], exercise.title);
this.entityTitleService.setExerciseTitle(exercise);
});
course?.lectures?.forEach((lecture) => this.entityTitleService.setTitle(EntityType.LECTURE, [lecture.id], lecture.title));
course?.exams?.forEach((exam) => this.entityTitleService.setTitle(EntityType.EXAM, [exam.id], exam.title));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,19 @@
@if (displayEditorModus) {
<div>
<div class="d-flex justify-content-between">
<span jhiTranslate="'artemisApp.programmingExercise.offlineIde'">: {{ programmingExercise.allowOfflineIde || false }}</span>
<span class="colon-suffix" [jhiTranslate]="'artemisApp.programmingExercise.offlineIde'"></span>
<span [jhiTranslate]="programmingExercise.allowOfflineIde ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
</div>
<div class="d-flex justify-content-between">
<span jhiTranslate="'artemisApp.programmingExercise.onlineEditor'">: {{ programmingExercise.allowOnlineEditor || false }}</span>
</div>
<div class="d-flex justify-content-between">
<span jhiTranslate="'artemisApp.programmingExercise.onlineIde'">: {{ programmingExercise.allowOnlineIde || false }}</span>
<span class="colon-suffix" [jhiTranslate]="'artemisApp.programmingExercise.onlineEditor'"></span>
<span [jhiTranslate]="programmingExercise.allowOnlineEditor ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
</div>
@if (onlineIdeEnabled) {
<div class="d-flex justify-content-between">
<span class="colon-suffix" [jhiTranslate]="'artemisApp.programmingExercise.onlineIde'"></span>
<span [jhiTranslate]="programmingExercise.allowOnlineIde ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
</div>
}
</div>
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ProgrammingExerciseInstructorRepositoryType, ProgrammingExerciseService
import { downloadZipFileFromResponse } from 'app/shared/util/download.util';
import { AlertService } from 'app/core/util/alert.service';
import { faDownload } from '@fortawesome/free-solid-svg-icons';
import { PROFILE_LOCALVC } from 'app/app.constants';
import { PROFILE_LOCALVC, PROFILE_THEIA } from 'app/app.constants';

@Component({
selector: 'jhi-programming-exercise-group-cell',
Expand All @@ -22,6 +22,7 @@ export class ProgrammingExerciseGroupCellComponent implements OnInit {
programmingExercise: ProgrammingExercise;

localVCEnabled = false;
onlineIdeEnabled = false;

@Input()
displayShortName = false;
Expand All @@ -48,6 +49,7 @@ export class ProgrammingExerciseGroupCellComponent implements OnInit {
ngOnInit(): void {
this.profileService.getProfileInfo().subscribe((profileInfo) => {
this.localVCEnabled = profileInfo.activeProfiles.includes(PROFILE_LOCALVC);
this.onlineIdeEnabled = profileInfo.activeProfiles.includes(PROFILE_THEIA);
if (this.programmingExercise.projectKey) {
if (this.programmingExercise.solutionParticipation?.buildPlanId) {
this.programmingExercise.solutionParticipation!.buildPlanUrl = createBuildPlanUrl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<th jhiSortBy="maxPoints"><span jhiTranslate="artemisApp.exercise.points"></span>&nbsp;<fa-icon [icon]="faSort" /></th>
<th jhiSortBy="bonusPoints"><span jhiTranslate="artemisApp.exercise.bonus"></span>&nbsp;<fa-icon [icon]="faSort" /></th>
<th jhiSortBy="includedInOverallScore"><span jhiTranslate="artemisApp.exercise.includedCompletely"></span>&nbsp;<fa-icon [icon]="faSort" /></th>
@if (course.presentationScore !== 0) {
@if (course.presentationScore) {
<th jhiSortBy="presentationScoreEnabled">
<span jhiTranslate="artemisApp.exercise.presentationScoreEnabled.title"></span>&nbsp;<fa-icon [icon]="faSort" />
</th>
Expand Down Expand Up @@ -58,7 +58,7 @@
<td>{{ fileUploadExercise.maxPoints }}</td>
<td>{{ fileUploadExercise.bonusPoints }}</td>
<td>{{ exerciseService.isIncludedInScore(fileUploadExercise) }}</td>
@if (course.presentationScore !== 0) {
@if (course.presentationScore) {
<td>{{ fileUploadExercise.presentationScoreEnabled }}</td>
}
<td>{{ fileUploadExercise.filePattern }}</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<th jhiSortBy="maxPoints"><span jhiTranslate="artemisApp.exercise.points"></span>&nbsp;<fa-icon [icon]="faSort" /></th>
<th jhiSortBy="bonusPoints"><span jhiTranslate="artemisApp.exercise.bonus"></span>&nbsp;<fa-icon [icon]="faSort" /></th>
<th jhiSortBy="includedInOverallScore"><span jhiTranslate="artemisApp.exercise.includedCompletely"></span>&nbsp;<fa-icon [icon]="faSort" /></th>
@if (course.presentationScore !== 0) {
@if (course.presentationScore) {
<th jhiSortBy="presentationScoreEnabled">
<span jhiTranslate="artemisApp.exercise.presentationScoreEnabled.title"></span>&nbsp;<fa-icon [icon]="faSort" />
</th>
Expand Down Expand Up @@ -58,7 +58,7 @@
<td id="modeling-exercise-{{ modelingExercise.id }}-maxPoints">{{ modelingExercise.maxPoints }}</td>
<td id="modeling-exercise-{{ modelingExercise.id }}-bonusPoints">{{ modelingExercise.bonusPoints }}</td>
<td id="modeling-exercise-{{ modelingExercise.id }}-included">{{ exerciseService.isIncludedInScore(modelingExercise) }}</td>
@if (course.presentationScore !== 0) {
@if (course.presentationScore) {
<td>{{ modelingExercise.presentationScoreEnabled }}</td>
}
<td jhiTranslate="{{ 'artemisApp.DiagramType.' + modelingExercise.diagramType }}">{{ modelingExercise.diagramType }}</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<th class="d-md-table-cell">
<span jhiTranslate="artemisApp.exercise.mode"></span>
</th>
@if (course.presentationScore !== 0) {
@if (course.presentationScore) {
<th class="d-md-table-cell" jhiSortBy="presentationScoreEnabled">
<span jhiTranslate="artemisApp.exercise.presentationScoreEnabled.title"></span>&nbsp;<fa-icon [icon]="faSort" />
</th>
Expand Down Expand Up @@ -139,19 +139,21 @@
}
<td class="d-md-table-cell">
<div class="d-flex justify-content-between">
<span [jhiTranslate]="'artemisApp.programmingExercise.offlineIde'"></span>:
<span class="colon-suffix" [jhiTranslate]="'artemisApp.programmingExercise.offlineIde'"></span>
<span [jhiTranslate]="programmingExercise.allowOfflineIde ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
</div>
<div class="d-flex justify-content-between">
<span [jhiTranslate]="'artemisApp.programmingExercise.onlineEditor'"></span>:
<span class="colon-suffix" [jhiTranslate]="'artemisApp.programmingExercise.onlineEditor'"></span>
<span [jhiTranslate]="programmingExercise.allowOnlineEditor ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
</div>
<div class="d-flex justify-content-between">
<span [jhiTranslate]="'artemisApp.programmingExercise.onlineIde'"></span>:
<span [jhiTranslate]="programmingExercise.allowOnlineIde ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
</div>
@if (onlineIdeEnabled) {
<div class="d-flex justify-content-between">
<span class="colon-suffix" [jhiTranslate]="'artemisApp.programmingExercise.onlineIde'"></span>
<span [jhiTranslate]="programmingExercise.allowOnlineIde ? 'artemisApp.exercise.yes' : 'artemisApp.exercise.no'"></span>
</div>
}
</td>
@if (course.presentationScore !== 0) {
@if (course.presentationScore) {
<td class="d-md-table-cell">{{ programmingExercise.presentationScoreEnabled }}</td>
}
<td class="d-md-table-cell">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import {
} from '@fortawesome/free-solid-svg-icons';
import { CourseExerciseService } from 'app/exercises/shared/course-exercises/course-exercise.service';
import { downloadZipFileFromResponse } from 'app/shared/util/download.util';
import { PROFILE_LOCALCI, PROFILE_LOCALVC } from 'app/app.constants';
import { PROFILE_LOCALCI, PROFILE_LOCALVC, PROFILE_THEIA } from 'app/app.constants';

@Component({
selector: 'jhi-programming-exercise',
Expand All @@ -55,6 +55,7 @@ export class ProgrammingExerciseComponent extends ExerciseComponent implements O
// Used to make the repository links download the repositories instead of linking to GitLab.
localVCEnabled = false;
localCIEnabled = false;
onlineIdeEnabled = false;

// extension points, see shared/extension-point
@ContentChild('overrideRepositoryAndBuildPlan') overrideRepositoryAndBuildPlan: TemplateRef<any>;
Expand Down Expand Up @@ -111,6 +112,7 @@ export class ProgrammingExerciseComponent extends ExerciseComponent implements O
this.buildPlanLinkTemplate = profileInfo.buildPlanURLTemplate;
this.localVCEnabled = profileInfo.activeProfiles.includes(PROFILE_LOCALVC);
this.localCIEnabled = profileInfo.activeProfiles.includes(PROFILE_LOCALCI);
this.onlineIdeEnabled = profileInfo.activeProfiles.includes(PROFILE_THEIA);
});
// reconnect exercise with course
this.programmingExercises.forEach((exercise) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { Injectable } from '@angular/core';
import { AccountService } from 'app/core/auth/account.service';
import { Participation } from 'app/entities/participation/participation.model';
import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model';
import { CommitInfo } from 'app/entities/programming/programming-submission.model';
import { Result } from 'app/entities/result.model';
import { EntityTitleService, EntityType } from 'app/shared/layouts/navbar/entity-title.service';
import { createRequestOption } from 'app/shared/util/request.util';
import { Observable, map, tap } from 'rxjs';
import { CommitInfo } from 'app/entities/programming/programming-submission.model';

export interface IProgrammingExerciseParticipationService {
getLatestResultWithFeedback: (participationId: number, withSubmission: boolean) => Observable<Result | undefined>;
Expand Down Expand Up @@ -81,7 +81,7 @@ export class ProgrammingExerciseParticipationService implements IProgrammingExer
sendTitlesToEntityTitleService(participation: Participation | undefined) {
if (participation?.exercise) {
const exercise = participation.exercise;
this.entityTitleService.setTitle(EntityType.EXERCISE, [exercise.id], exercise.title);
this.entityTitleService.setExerciseTitle(exercise);

if (exercise.course) {
const course = exercise.course;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,14 +348,14 @@ export class ProgrammingExerciseInstructionComponent implements OnChanges, OnDes
// Insert anchor divs into the text so that injectable elements can be inserted into them.
// Without class="d-flex" the injected components height would be 0.
// Added zero-width space as content so the div actually consumes a line to prevent a <ol> display bug in Safari
acc.replace(new RegExp(escapeStringForUseInRegex(task), 'g'), `<div class="pe-task-${id.toString()} d-flex">&#8203;</div>`),
acc.replace(new RegExp(escapeStringForUseInRegex(task), 'g'), `<div class="pe-${this.exercise.id}-task-${id.toString()} d-flex">&#8203;</div>`),
problemStatementHtml,
);
}

private injectTasksIntoDocument = () => {
this.tasks.forEach(({ id, taskName, testIds }) => {
const taskHtmlContainers = document.getElementsByClassName(`pe-task-${id}`);
const taskHtmlContainers = document.getElementsByClassName(`pe-${this.exercise.id}-task-${id}`);

for (let i = 0; i < taskHtmlContainers.length; i++) {
const taskHtmlContainer = taskHtmlContainers[i];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -488,12 +488,8 @@ export class ExerciseService {
}

public sendExerciseTitleToTitleService(exercise?: Exercise) {
// we only want to show the exercise group name as exercise name to the student for exam exercises.
// for tutors and more privileged users, we want to show the exercise title
if (exercise?.exerciseGroup && !exercise?.isAtLeastTutor) {
this.entityTitleService.setTitle(EntityType.EXERCISE, [exercise?.id], exercise?.exerciseGroup.title);
} else {
this.entityTitleService.setTitle(EntityType.EXERCISE, [exercise?.id], exercise?.title);
if (exercise) {
this.entityTitleService.setExerciseTitle(exercise);
}
if (exercise?.course) {
this.entityTitleService.setTitle(EntityType.COURSE, [exercise.course.id], exercise.course.title);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class PresentationScoreComponent implements DoCheck, OnDestroy {
}

private isBasicPresentation(): boolean {
return !!(this.exercise.course && this.exercise.course.presentationScore !== 0);
return !!this.exercise.course?.presentationScore;
}

private isGradedPresentation(): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<th jhiSortBy="maxPoints"><span jhiTranslate="artemisApp.exercise.points"></span>&nbsp;<fa-icon [icon]="faSort" /></th>
<th jhiSortBy="bonusPoints"><span jhiTranslate="artemisApp.exercise.bonus"></span>&nbsp;<fa-icon [icon]="faSort" /></th>
<th jhiSortBy="includedInOverallScore"><span jhiTranslate="artemisApp.exercise.includedCompletely"></span>&nbsp;<fa-icon [icon]="faSort" /></th>
@if (course.presentationScore !== 0) {
@if (course.presentationScore) {
<th jhiSortBy="presentationScoreEnabled">
<span jhiTranslate="artemisApp.exercise.presentationScoreEnabled.title"></span>&nbsp;<fa-icon [icon]="faSort" />
</th>
Expand Down Expand Up @@ -53,7 +53,7 @@
<td>{{ textExercise.maxPoints }}</td>
<td>{{ textExercise.bonusPoints }}</td>
<td>{{ exerciseService.isIncludedInScore(textExercise) }}</td>
@if (course.presentationScore !== 0) {
@if (course.presentationScore) {
<td>{{ textExercise.presentationScoreEnabled }}</td>
}
<td class="d-md-table-cell"><jhi-exercise-categories [exercise]="textExercise" /></td>
Expand Down
Loading

0 comments on commit 9618c23

Please sign in to comment.