Skip to content

Commit

Permalink
Merge branch 'develop' into feature/exams/quiz-pool-configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
rriyaldhi authored Jul 15, 2023
2 parents b61ec95 + 0190a74 commit 61771e1
Show file tree
Hide file tree
Showing 43 changed files with 374 additions and 76 deletions.
27 changes: 25 additions & 2 deletions src/main/java/de/tum/in/www1/artemis/domain/Lecture.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public class Lecture extends DomainObject {
@Column(name = "end_date")
private ZonedDateTime endDate;

@Column(name = "visible_date")
private ZonedDateTime visibleDate;

@OneToMany(mappedBy = "lecture", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.EAGER)
@JsonIgnoreProperties(value = "lecture", allowSetters = true)
private Set<Attachment> attachments = new HashSet<>();
Expand Down Expand Up @@ -93,6 +96,14 @@ public void setEndDate(ZonedDateTime endDate) {
this.endDate = endDate;
}

public ZonedDateTime getVisibleDate() {
return visibleDate;
}

public void setVisibleDate(ZonedDateTime visibleDate) {
this.visibleDate = visibleDate;
}

public Set<Attachment> getAttachments() {
return attachments;
}
Expand Down Expand Up @@ -137,8 +148,8 @@ public void setCourse(Course course) {

@Override
public String toString() {
return "Lecture{" + "id=" + getId() + ", title='" + getTitle() + "'" + ", description='" + getDescription() + "'" + ", startDate='" + getStartDate() + "'" + ", endDate='"
+ getEndDate() + "'" + "}";
return "Lecture{" + "id=" + getId() + ", title='" + getTitle() + "'" + ", description='" + getDescription() + "'" + ", visibleDate='" + getVisibleDate() + "'"
+ ", startDate='" + getStartDate() + "'" + ", endDate='" + getEndDate() + "'" + "}";
}

public enum LectureSearchColumn {
Expand All @@ -163,4 +174,16 @@ public String getChannelName() {
public void setChannelName(String channelNameTransient) {
this.channelNameTransient = channelNameTransient;
}

/**
* check if students are allowed to see this lecture
*
* @return true, if students are allowed to see this lecture, otherwise false
*/
public boolean isVisibleToStudents() {
if (visibleDate == null) { // no visible date means the lecture is visible to students
return true;
}
return visibleDate.isBefore(ZonedDateTime.now());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,25 @@ public boolean isAllowedToSeeExercise(@NotNull Exercise exercise, @Nullable User
return isAtLeastTeachingAssistantInCourse(course, user) || (isStudentInCourse(course, user) && exercise.isVisibleToStudents());
}

/**
* checks if the passed user is allowed to see the given lecture
*
* @param lecture the lecture that needs to be checked
* @param user the user whose permissions should be checked
*/
public void checkIsAllowedToSeeLectureElseThrow(@NotNull Lecture lecture, @Nullable User user) {
user = loadUserIfNeeded(user);
if (isAdmin(user)) {
return;
}
Course course = lecture.getCourse();
if (isAtLeastTeachingAssistantInCourse(course, user) || (isStudentInCourse(course, user) && lecture.isVisibleToStudents())) {
return;
}

throw new AccessForbiddenException();
}

/**
* Determines if a user is allowed to see a lecture unit
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public Course findOneWithExercisesAndLecturesAndExamsAndCompetenciesAndTutorialG
course.setExercises(exerciseService.filterExercisesForCourse(course, user));
exerciseService.loadExerciseDetailsIfNecessary(course, user);
course.setExams(examRepository.findByCourseIdsForUser(Set.of(course.getId()), user.getId(), user.getGroups(), ZonedDateTime.now()));
course.setLectures(lectureService.filterActiveAttachments(course.getLectures(), user));
course.setLectures(lectureService.filterVisibleLecturesWithActiveAttachments(course, course.getLectures(), user));
course.setCompetencies(competencyService.findAllForCourse(course, user, refresh));
course.setPrerequisites(competencyService.findAllPrerequisitesForCourse(course, user));
course.setTutorialGroups(tutorialGroupService.findAllForCourse(course, user));
Expand Down Expand Up @@ -307,7 +307,7 @@ public List<Course> findAllActiveWithExercisesAndLecturesAndExamsForUser(User us
course.setExercises(exerciseService.filterExercisesForCourse(course, user));
exerciseService.loadExerciseDetailsIfNecessary(course, user);
course.setExams(allExams.stream().filter(ex -> ex.getCourse().getId().equals(course.getId())).collect(Collectors.toSet()));
course.setLectures(lectureService.filterActiveAttachments(course.getLectures(), user));
course.setLectures(lectureService.filterVisibleLecturesWithActiveAttachments(course, course.getLectures(), user));
}).toList();

if (log.isDebugEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public Lecture importLecture(final Lecture importedLecture, final Course course)
lecture.setDescription(importedLecture.getDescription());
lecture.setStartDate(importedLecture.getStartDate());
lecture.setEndDate(importedLecture.getEndDate());
lecture.setVisibleDate(importedLecture.getVisibleDate());

lecture = lectureRepository.save(lecture);
course.addLectures(lecture);
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/de/tum/in/www1/artemis/service/LectureService.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,23 @@ public void filterActiveAttachmentUnits(Lecture lectureWithAttachmentUnits) {
}

/**
* Filter active attachments for a set of lectures.
* Filter active attachments for a set of lectures. All lectures must be from the same course.
*
* @param course course all the lectures are from
* @param lecturesWithAttachments lectures that have attachments
* @param user the user for which this call should filter
* @return lectures with filtered attachments
*/
public Set<Lecture> filterActiveAttachments(Set<Lecture> lecturesWithAttachments, User user) {
public Set<Lecture> filterVisibleLecturesWithActiveAttachments(Course course, Set<Lecture> lecturesWithAttachments, User user) {
if (authCheckService.isAtLeastTeachingAssistantInCourse(course, user)) {
return lecturesWithAttachments;
}

Set<Lecture> lecturesWithFilteredAttachments = new HashSet<>();
for (Lecture lecture : lecturesWithAttachments) {
lecturesWithFilteredAttachments.add(filterActiveAttachments(lecture, user));
if (lecture.isVisibleToStudents()) {
lecturesWithFilteredAttachments.add(filterActiveAttachments(lecture, user));
}
}
return lecturesWithFilteredAttachments;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,15 +458,16 @@ public List<Conversation> findAllConversationsForNotifications(User user, boolea
*/
public Stream<Channel> filterVisibleChannelsForStudents(Stream<Channel> channels) {
return channels.filter(channel -> {
if (channel.getExercise() != null) {
if (channel.getLecture() != null) {
return channel.getLecture().isVisibleToStudents();
}
else if (channel.getExercise() != null) {
return channel.getExercise().isVisibleToStudents();
}
else if (channel.getExam() != null) {
return channel.getExam().isVisibleToStudents();
}
else {
return true;
}
return true;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ private static Map<String, Object> getParameters(String channelName) {
Map<String, String> params = new HashMap<>();
params.put("channelName", channelName);
Map<String, Object> parameters = new HashMap<>();
parameters.put("skipAlert", true);
parameters.put("message", "artemisApp.errors." + ERROR_KEY);
parameters.put("params", params);
return parameters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ public ResponseEntity<Set<Lecture>> getLecturesWithSlidesForCourse(@PathVariable

User user = userRepository.getUserWithGroupsAndAuthorities();
Set<Lecture> lectures = lectureRepository.findAllByCourseIdWithAttachmentsAndLectureUnitsAndSlides(courseId);
lectures = lectureService.filterVisibleLecturesWithActiveAttachments(course, lectures, user);
lectures.forEach(lectureService::filterActiveAttachmentUnits);
lectures.forEach(lecture -> lectureService.filterActiveAttachments(lecture, user));
return ResponseEntity.ok().body(lectures);
}

Expand All @@ -208,11 +208,13 @@ public ResponseEntity<Set<Lecture>> getLecturesWithSlidesForCourse(@PathVariable
public ResponseEntity<Lecture> getLecture(@PathVariable Long lectureId) {
log.debug("REST request to get lecture {}", lectureId);
Lecture lecture = lectureRepository.findById(lectureId).orElseThrow();
authCheckService.checkIsAllowedToSeeLectureElseThrow(lecture, userRepository.getUserWithGroupsAndAuthorities());

Channel lectureChannel = channelRepository.findChannelByLectureId(lectureId);
if (lectureChannel != null) {
lecture.setChannelName(lectureChannel.getName());
}
authCheckService.checkHasAtLeastRoleForLectureElseThrow(Role.STUDENT, lecture, null);

return ResponseEntity.ok(lecture);
}

Expand Down Expand Up @@ -268,7 +270,7 @@ public ResponseEntity<Lecture> getLectureWithDetails(@PathVariable Long lectureI
return ResponseEntity.badRequest().build();
}
User user = userRepository.getUserWithGroupsAndAuthorities();
authCheckService.checkHasAtLeastRoleInCourseElseThrow(Role.STUDENT, course, user);
authCheckService.checkIsAllowedToSeeLectureElseThrow(lecture, user);
lecture = filterLectureContentForUser(lecture, user);

return ResponseEntity.ok(lecture);
Expand All @@ -289,7 +291,7 @@ public ResponseEntity<Lecture> getLectureWithDetailsAndSlides(@PathVariable Long
if (course == null) {
return ResponseEntity.badRequest().build();
}
authCheckService.checkHasAtLeastRoleInCourseElseThrow(Role.STUDENT, course, null);
authCheckService.checkIsAllowedToSeeLectureElseThrow(lecture, userRepository.getUserWithGroupsAndAuthorities());

User user = userRepository.getUserWithGroupsAndAuthorities();
lectureService.filterActiveAttachmentUnits(lecture);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@ public ResponseEntity<Participation> startParticipation(@PathVariable Long exerc
if (exercise instanceof ProgrammingExercise) {
// fetch additional objects needed for the startExercise method below
var programmingExercise = programmingExerciseRepository.findByIdWithTemplateAndSolutionParticipationElseThrow(exercise.getId());
if (!featureToggleService.isFeatureEnabled(Feature.ProgrammingExercises) || !isAllowedToParticipateInProgrammingExercise(programmingExercise, null)) {
// only editors and instructors have permission to trigger participation after due date passed
if (!featureToggleService.isFeatureEnabled(Feature.ProgrammingExercises)
|| (!authCheckService.isAtLeastEditorForExercise(exercise, user) && !isAllowedToParticipateInProgrammingExercise(programmingExercise, null))) {
throw new AccessForbiddenException("Not allowed");
}
exercise = programmingExercise;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="keller" id="20230630151806">
<addColumn tableName="lecture">
<column name="visible_date" type="datetime(3)" />
</addColumn>
</changeSet>
</databaseChangeLog>
1 change: 1 addition & 0 deletions src/main/resources/config/liquibase/master.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<include file="classpath:config/liquibase/changelog/20230601154000_changelog.xml" relativeToChangelogFile="false"/>
<include file="classpath:config/liquibase/changelog/20230609100000_changelog.xml" relativeToChangelogFile="false"/>
<include file="classpath:config/liquibase/changelog/20230605115500_changelog.xml" relativeToChangelogFile="false"/>
<include file="classpath:config/liquibase/changelog/20230630151806_changelog.xml" relativeToChangelogFile="false"/>
<include file="classpath:config/liquibase/changelog/20230626220000_changelog.xml" relativeToChangelogFile="false"/>
<include file="classpath:config/liquibase/changelog/20230629194400_changelog.xml" relativeToChangelogFile="false"/>
<include file="classpath:config/liquibase/changelog/20230524102945_changelog.xml" relativeToChangelogFile="false"/>
Expand Down
1 change: 1 addition & 0 deletions src/main/webapp/app/entities/lecture.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export class Lecture implements BaseEntity {
description?: string;
startDate?: dayjs.Dayjs;
endDate?: dayjs.Dayjs;
visibleDate?: dayjs.Dayjs;
attachments?: Attachment[];
posts?: Post[];
lectureUnits?: LectureUnit[];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div
id="inline-feedback"
id="code-editor-inline-feedback-{{ codeLine }}"
class="alert p-1 border rounded"
[style.max-width]="'780px'"
[class.alert-success]="feedback.credits! > 0 && feedback.isSubsequent === undefined"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

&__save {
position: absolute;
top: 1px;
top: -16px;
right: 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
this.annotationChange.unsubscribe();
}
// remove all line widgets so that no old ones are displayed when the editor is opened again
if (this.editorSession && this.editorSession.widgetManager) {
if (this.editorSession?.widgetManager && this.editorSession?.lineWidgets) {
for (const line of this.linesWithInlineFeedbackShown) {
const widget = this.editorSession.lineWidgets.find((w: any) => w?.el === this.getInlineFeedbackNode(line));
this.editorSession.widgetManager.removeLineWidget(widget);
Expand Down
4 changes: 4 additions & 0 deletions src/main/webapp/app/lecture/lecture-detail.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ <h2><span jhiTranslate="artemisApp.lecture.detail.title">Lecture</span> {{ lectu
</dd>
<dt><span jhiTranslate="artemisApp.lecture.description">Description</span></dt>
<dd class="markdown-preview editor-outline-background" [innerHTML]="lecture.description | htmlForMarkdown"></dd>
<dt><span jhiTranslate="artemisApp.lecture.visibleDate">Visible from</span></dt>
<dd>
<span>{{ lecture.visibleDate | artemisDate }}</span>
</dd>
<dt><span jhiTranslate="artemisApp.lecture.startDate">Start Date</span></dt>
<dd>
<span>{{ lecture.startDate | artemisDate }}</span>
Expand Down
11 changes: 9 additions & 2 deletions src/main/webapp/app/lecture/lecture-update.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
[validateDatesFunction]="onDatesValuesChanged"
[lecture]="lecture"
[isSaving]="isSaving"
[startDate]="startDate"
[endDate]="endDate"
></jhi-lecture-update-wizard>
<form name="editForm" role="form" (ngSubmit)="save()" #editForm="ngForm" *ngIf="!isShowingWizardMode">
<div class="d-flex">
Expand Down Expand Up @@ -49,6 +47,15 @@ <h2 id="jhi-lecture-heading" jhiTranslate="artemisApp.lecture.home.createOrEditL
</div>
<div class="d-flex">
<div class="form-group flex-grow-1">
<jhi-date-time-picker
labelName="{{ 'artemisApp.lecture.visibleDate' | artemisTranslate }}"
[(ngModel)]="lecture.visibleDate"
(valueChange)="onDatesValuesChanged()"
name="visibleDate"
id="visible-date"
></jhi-date-time-picker>
</div>
<div class="form-group flex-grow-1 ms-3">
<jhi-date-time-picker
labelName="{{ 'artemisApp.lecture.startDate' | artemisTranslate }}"
[(ngModel)]="lecture.startDate"
Expand Down
21 changes: 11 additions & 10 deletions src/main/webapp/app/lecture/lecture-update.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ import { KatexCommand } from 'app/shared/markdown-editor/commands/katex.command'
import { onError } from 'app/shared/util/global.utils';
import { ArtemisNavigationUtilService } from 'app/utils/navigation.utils';
import { DocumentationType } from 'app/shared/components/documentation-button/documentation-button.component';
import { faBan, faHandshakeAngle, faPuzzlePiece, faSave } from '@fortawesome/free-solid-svg-icons';
import { faBan, faHandshakeAngle, faPuzzlePiece, faQuestionCircle, faSave } from '@fortawesome/free-solid-svg-icons';
import { LectureUpdateWizardComponent } from 'app/lecture/wizard-mode/lecture-update-wizard.component';
import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
import { FILE_EXTENSIONS } from 'app/shared/constants/file-extensions.constants';

@Component({
Expand All @@ -35,8 +34,6 @@ export class LectureUpdateComponent implements OnInit {
isShowingWizardMode: boolean;

courses: Course[];
startDate: string;
endDate: string;

domainCommandsDescription = [new KatexCommand()];
file: File;
Expand Down Expand Up @@ -197,14 +194,18 @@ export class LectureUpdateComponent implements OnInit {
}

onDatesValuesChanged() {
if (this.lecture.startDate === undefined || this.lecture.endDate === undefined) {
return;
}
const startDate = this.lecture.startDate;
const endDate = this.lecture.endDate;
const visibleDate = this.lecture.visibleDate;

if (this.lecture.startDate.isSameOrBefore(this.lecture.endDate)) {
return;
// Prevent endDate from being before startDate, if both dates are set
if (endDate && startDate?.isAfter(endDate)) {
this.lecture.endDate = startDate.clone();
}

this.lecture.endDate = this.lecture.startDate;
// Prevent visibleDate from being after startDate, if both dates are set
if (visibleDate && startDate?.isBefore(visibleDate)) {
this.lecture.visibleDate = startDate.clone();
}
}
}
2 changes: 2 additions & 0 deletions src/main/webapp/app/lecture/lecture.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ <h2 id="page-heading">
<th><span jhiTranslate="global.field.id">ID</span></th>
<th><span jhiTranslate="artemisApp.lecture.title">Title</span></th>
<th><span jhiTranslate="artemisApp.lecture.description">Description</span></th>
<th><span jhiTranslate="artemisApp.lecture.visibleDate">Visible from</span></th>
<th><span jhiTranslate="artemisApp.lecture.startDate">Start Date</span></th>
<th><span jhiTranslate="artemisApp.lecture.endDate">End Date</span></th>
<th><span jhiTranslate="artemisApp.lecture.course">Course</span></th>
Expand All @@ -105,6 +106,7 @@ <h2 id="page-heading">
<a [routerLink]="[lecture.id]">{{ lecture.title }}</a>
</td>
<td [innerHTML]="lecture.description | htmlForMarkdown"></td>
<td>{{ lecture.visibleDate | artemisDate }}</td>
<td>{{ lecture.startDate | artemisDate }}</td>
<td>{{ lecture.endDate | artemisDate }}</td>
<td>
Expand Down
Loading

0 comments on commit 61771e1

Please sign in to comment.