Skip to content

Commit 8e6f67d

Browse files
authored
Lectures: Prefer attachment units over attachments (#10708)
1 parent 96a2285 commit 8e6f67d

File tree

33 files changed

+214
-470
lines changed

33 files changed

+214
-470
lines changed

docs/admin/accessRights.rst

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -197,27 +197,27 @@ Quiz Exercises
197197

198198
Lectures
199199
--------
200-
+---------------------+------------+--------+--------------------+
201-
| | Instructor | Editor | Teaching Assistant |
202-
+---------------------+------------+--------+--------------------+
203-
| Add attachment ||| |
204-
+---------------------+------------+--------+--------------------+
205-
| Edit attachment ||| |
206-
+---------------------+------------+--------+--------------------+
207-
| Delete attachment || | |
208-
+---------------------+------------+--------+--------------------+
209-
| Add Lecture Unit ||| |
210-
+---------------------+------------+--------+--------------------+
211-
| Edit Lecture Unit ||| |
212-
+---------------------+------------+--------+--------------------+
213-
| Delete Lecture Unit || | |
214-
+---------------------+------------+--------+--------------------+
215-
| Create Lecture ||| |
216-
+---------------------+------------+--------+--------------------+
217-
| Edit Lecture ||| |
218-
+---------------------+------------+--------+--------------------+
219-
| Delete Lecture || | |
220-
+---------------------+------------+--------+--------------------+
200+
+--------------------------+------------+--------+--------------------+
201+
| | Instructor | Editor | Teaching Assistant |
202+
+--------------------------+------------+--------+--------------------+
203+
| Add attachment (in unit) ||| |
204+
+--------------------------+------------+--------+--------------------+
205+
| Edit attachment ||| |
206+
+--------------------------+------------+--------+--------------------+
207+
| Delete attachment || | |
208+
+--------------------------+------------+--------+--------------------+
209+
| Add Lecture Unit ||| |
210+
+--------------------------+------------+--------+--------------------+
211+
| Edit Lecture Unit ||| |
212+
+--------------------------+------------+--------+--------------------+
213+
| Delete Lecture Unit || | |
214+
+--------------------------+------------+--------+--------------------+
215+
| Create Lecture ||| |
216+
+--------------------------+------------+--------+--------------------+
217+
| Edit Lecture ||| |
218+
+--------------------------+------------+--------+--------------------+
219+
| Delete Lecture || | |
220+
+--------------------------+------------+--------+--------------------+
221221

222222
Exam
223223
----

docs/dev/guidelines/client-design.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ For example, you could add a reactive flag to your component that indicates whet
209209
isDark = false;
210210
themeSubscription: Subscription;
211211
212-
constructor(private themeService: ThemeService) {}
212+
private themeService = inject(ThemeService);
213213
214214
ngOnInit() {
215215
this.themeSubscription = this.themeService.getCurrentThemeObservable().subscribe((theme) => {

jest.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ module.exports = {
9292
global: {
9393
// TODO: in the future, the following values should increase to at least 90%
9494
statements: 88.98,
95-
branches: 75.18,
96-
functions: 82.98,
95+
branches: 75.15,
96+
functions: 82.96,
9797
lines: 89.04,
9898
},
9999
},

src/main/java/de/tum/cit/aet/artemis/lecture/domain/LectureTranscription.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
import jakarta.persistence.Table;
1111
import jakarta.validation.constraints.Size;
1212

13-
import com.fasterxml.jackson.annotation.JsonIgnore;
14-
1513
import de.tum.cit.aet.artemis.core.domain.DomainObject;
1614

1715
@Entity
@@ -31,7 +29,6 @@ public class LectureTranscription extends DomainObject {
3129

3230
@OneToOne
3331
@JoinColumn(name = "lecture_unit_id", unique = true)
34-
@JsonIgnore
3532
private LectureUnit lectureUnit;
3633

3734
public LectureTranscription() {

src/main/java/de/tum/cit/aet/artemis/lecture/domain/LectureUnit.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import jakarta.persistence.JoinColumn;
1818
import jakarta.persistence.ManyToOne;
1919
import jakarta.persistence.OneToMany;
20-
import jakarta.persistence.OneToOne;
2120
import jakarta.persistence.Table;
2221
import jakarta.persistence.Transient;
2322

@@ -79,10 +78,6 @@ public abstract class LectureUnit extends DomainObject implements LearningObject
7978
@JsonIgnore // important, so that the completion status of other users do not leak to anyone
8079
private Set<LectureUnitCompletion> completedUsers = new HashSet<>();
8180

82-
@OneToOne(mappedBy = "lectureUnit")
83-
@JsonIgnore
84-
protected LectureTranscription lectureTranscription;
85-
8681
public String getName() {
8782
return name;
8883
}
@@ -116,13 +111,7 @@ public void setCompetencyLinks(Set<CompetencyLectureUnitLink> competencyLinks) {
116111
this.competencyLinks = competencyLinks;
117112
}
118113

119-
public LectureTranscription getLectureTranscription() {
120-
return lectureTranscription;
121-
}
122-
123-
public void setLectureTranscription(LectureTranscription lectureTranscription) {
124-
this.lectureTranscription = lectureTranscription;
125-
}
114+
// NOTE: we explicitly do not add LectureTranscription here to avoid Hibernate issues because of its OneToOne relationship which is EAGER and cannot be set to LAZY
126115

127116
@JsonIgnore(false)
128117
@JsonProperty("completed")
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package de.tum.cit.aet.artemis.lecture.dto;
2+
3+
import java.time.ZonedDateTime;
4+
5+
import com.fasterxml.jackson.annotation.JsonInclude;
6+
7+
import de.tum.cit.aet.artemis.lecture.domain.Slide;
8+
9+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
10+
public record SlideDTO(Long id, int slideNumber, ZonedDateTime hidden, Long attachmentUnitId) {
11+
12+
public static SlideDTO from(Slide slide) {
13+
return new SlideDTO(slide.getId(), slide.getSlideNumber(), slide.getHidden(), slide.getAttachmentUnit().getId());
14+
}
15+
}

src/main/java/de/tum/cit/aet/artemis/lecture/repository/LectureRepository.java

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,12 @@ public interface LectureRepository extends ArtemisJpaRepository<Lecture, Long> {
4747
SELECT lecture
4848
FROM Lecture lecture
4949
LEFT JOIN FETCH lecture.attachments
50-
LEFT JOIN FETCH lecture.lectureUnits
50+
LEFT JOIN FETCH lecture.lectureUnits lu
51+
LEFT JOIN FETCH lu.attachment
5152
WHERE lecture.course.id = :courseId
5253
""")
5354
Set<Lecture> findAllByCourseIdWithAttachmentsAndLectureUnits(@Param("courseId") Long courseId);
5455

55-
@Query("""
56-
SELECT lecture
57-
FROM Lecture lecture
58-
LEFT JOIN FETCH lecture.attachments attachment
59-
LEFT JOIN FETCH lecture.lectureUnits lectureUnit
60-
LEFT JOIN FETCH lectureUnit.attachment luAttachment
61-
LEFT JOIN FETCH lectureUnit.slides slides
62-
WHERE lecture.course.id = :courseId
63-
""")
64-
Set<Lecture> findAllByCourseIdWithAttachmentsAndLectureUnitsAndSlides(@Param("courseId") Long courseId);
65-
6656
@Query("""
6757
SELECT lecture
6858
FROM Lecture lecture
@@ -109,17 +99,6 @@ public interface LectureRepository extends ArtemisJpaRepository<Lecture, Long> {
10999
""")
110100
Optional<Lecture> findByIdWithLectureUnitsAndAttachments(@Param("lectureId") Long lectureId);
111101

112-
@Query("""
113-
SELECT lecture
114-
FROM Lecture lecture
115-
LEFT JOIN FETCH lecture.lectureUnits lectureUnit
116-
LEFT JOIN FETCH lectureUnit.attachment luAttachment
117-
LEFT JOIN FETCH lectureUnit.slides slides
118-
LEFT JOIN FETCH lecture.attachments
119-
WHERE lecture.id = :lectureId
120-
""")
121-
Optional<Lecture> findByIdWithLectureUnitsAndSlidesAndAttachments(@Param("lectureId") long lectureId);
122-
123102
@Query("""
124103
SELECT lecture
125104
FROM Lecture lecture
@@ -200,11 +179,6 @@ default Lecture findByIdWithLectureUnitsAndAttachmentsElseThrow(Long lectureId)
200179
return getValueElseThrow(findByIdWithLectureUnitsAndAttachments(lectureId), lectureId);
201180
}
202181

203-
@NotNull
204-
default Lecture findByIdWithLectureUnitsAndSlidesAndAttachmentsElseThrow(long lectureId) {
205-
return getValueElseThrow(findByIdWithLectureUnitsAndSlidesAndAttachments(lectureId), lectureId);
206-
}
207-
208182
@Query("""
209183
SELECT new de.tum.cit.aet.artemis.core.dto.CourseContentCount(
210184
COUNT(l.id),

src/main/java/de/tum/cit/aet/artemis/lecture/repository/SlideRepository.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@
33
import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE;
44

55
import java.util.List;
6+
import java.util.Set;
67

78
import org.springframework.context.annotation.Profile;
9+
import org.springframework.data.jpa.repository.Modifying;
810
import org.springframework.data.jpa.repository.Query;
911
import org.springframework.data.repository.query.Param;
1012
import org.springframework.stereotype.Repository;
1113
import org.springframework.transaction.annotation.Transactional;
1214

1315
import de.tum.cit.aet.artemis.core.repository.base.ArtemisJpaRepository;
1416
import de.tum.cit.aet.artemis.lecture.domain.Slide;
17+
import de.tum.cit.aet.artemis.lecture.dto.SlideDTO;
1518
import de.tum.cit.aet.artemis.lecture.dto.SlideUnhideDTO;
1619

1720
/**
@@ -64,11 +67,20 @@ public interface SlideRepository extends ArtemisJpaRepository<Slide, Long> {
6467
*
6568
* @param slideId The ID of the slide to unhide
6669
*/
67-
@Transactional
68-
default void unhideSlide(Long slideId) {
69-
findById(slideId).ifPresent(slide -> {
70-
slide.setHidden(null);
71-
save(slide);
72-
});
73-
}
70+
@Transactional // ok because of modifying query
71+
@Modifying
72+
@Query("""
73+
UPDATE Slide s
74+
SET s.hidden = NULL
75+
WHERE s.id = :slideId
76+
""")
77+
void unhideSlide(@Param("slideId") Long slideId);
78+
79+
@Query("""
80+
SELECT new de.tum.cit.aet.artemis.lecture.dto.SlideDTO(s.id, s.slideNumber, s.hidden, s.attachmentUnit.id)
81+
FROM Slide s
82+
WHERE s.attachmentUnit.id IN :attachmentUnitIds
83+
AND (s.hidden IS NULL OR s.hidden > CURRENT_TIMESTAMP())
84+
""")
85+
Set<SlideDTO> findVisibleSlidesByAttachmentUnits(@Param("attachmentUnitIds") Set<Long> attachmentUnitIds);
7486
}

src/main/java/de/tum/cit/aet/artemis/lecture/service/LectureService.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import de.tum.cit.aet.artemis.lecture.domain.Lecture;
3232
import de.tum.cit.aet.artemis.lecture.domain.LectureTranscription;
3333
import de.tum.cit.aet.artemis.lecture.domain.LectureUnit;
34-
import de.tum.cit.aet.artemis.lecture.domain.Slide;
3534
import de.tum.cit.aet.artemis.lecture.domain.VideoUnit;
3635
import de.tum.cit.aet.artemis.lecture.repository.LectureRepository;
3736

@@ -211,18 +210,4 @@ public void ingestTranscriptionInPyris(LectureTranscription transcription, Cours
211210
public void deleteLectureTranscriptionInPyris(LectureTranscription existingLectureTranscription) {
212211
irisLectureApi.ifPresent(webhookService -> webhookService.deleteLectureTranscription(existingLectureTranscription));
213212
}
214-
215-
/**
216-
* Filters the slides of all attachment units in a given lecture to exclude slides where `hidden` is not null.
217-
*
218-
* @param lectureWithAttachmentUnits the lecture containing attachment units
219-
*/
220-
public void filterHiddenPagesOfAttachmentUnits(Lecture lectureWithAttachmentUnits) {
221-
for (LectureUnit unit : lectureWithAttachmentUnits.getLectureUnits()) {
222-
if (unit instanceof AttachmentUnit attachmentUnit) {
223-
List<Slide> filteredSlides = attachmentUnit.getSlides().stream().filter(slide -> slide.getHidden() == null).toList();
224-
attachmentUnit.setSlides(filteredSlides);
225-
}
226-
}
227-
}
228213
}

src/main/java/de/tum/cit/aet/artemis/lecture/web/AttachmentResource.java

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import static de.tum.cit.aet.artemis.core.service.FilePathService.actualPathForPublicPath;
55

66
import java.net.URI;
7-
import java.net.URISyntaxException;
87
import java.nio.file.Path;
98
import java.util.List;
109
import java.util.Optional;
@@ -18,7 +17,6 @@
1817
import org.springframework.web.bind.annotation.DeleteMapping;
1918
import org.springframework.web.bind.annotation.GetMapping;
2019
import org.springframework.web.bind.annotation.PathVariable;
21-
import org.springframework.web.bind.annotation.PostMapping;
2220
import org.springframework.web.bind.annotation.PutMapping;
2321
import org.springframework.web.bind.annotation.RequestMapping;
2422
import org.springframework.web.bind.annotation.RequestParam;
@@ -77,29 +75,6 @@ public AttachmentResource(AttachmentRepository attachmentRepository, GroupNotifi
7775
this.fileService = fileService;
7876
}
7977

80-
/**
81-
* POST /attachments : Create a new attachment.
82-
*
83-
* @param attachment the attachment object to create
84-
* @param file the file to save
85-
* @return the ResponseEntity with status 201 (Created) and with body the new attachment, or with status 400 (Bad Request) if the attachment has already an ID
86-
* @throws URISyntaxException if the Location URI syntax is incorrect
87-
*/
88-
@PostMapping(value = "attachments", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
89-
@EnforceAtLeastEditor
90-
public ResponseEntity<Attachment> createAttachment(@RequestPart Attachment attachment, @RequestPart MultipartFile file) throws URISyntaxException {
91-
log.debug("REST request to save Attachment : {}", attachment);
92-
attachment.setId(null);
93-
94-
Path basePath = FilePathService.getLectureAttachmentFilePath().resolve(attachment.getLecture().getId().toString());
95-
Path savePath = fileService.saveFile(file, basePath, true);
96-
attachment.setLink(FilePathService.publicPathForActualPathOrThrow(savePath, attachment.getLecture().getId()).toString());
97-
98-
Attachment result = attachmentRepository.save(attachment);
99-
100-
return ResponseEntity.created(new URI("/api/lecture/attachments/" + result.getId())).body(result);
101-
}
102-
10378
/**
10479
* PUT /attachments/:id : Updates an existing attachment.
10580
*

0 commit comments

Comments
 (0)