Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iris: Add lecture transcription storage #10176

Open
wants to merge 37 commits into
base: develop
Choose a base branch
from

Conversation

isabellagessl
Copy link

@isabellagessl isabellagessl commented Jan 20, 2025

⚠️ Do NOT deploy to test servers - contains database migration ⚠️

Checklist

General

Server

  • Important: I implemented the changes with a very good performance and prevented too many (unnecessary) and too complex database calls.
  • I strictly followed the principle of data economy for all database calls.
  • I strictly followed the server coding and design guidelines.
  • I added multiple integration tests (Spring) related to the features (with a high test coverage).
  • I added pre-authorization annotations according to the guidelines and checked the course groups for all new REST Calls (security).
  • I documented the Java code using JavaDoc style.

Client

  • Important: I implemented the changes with a very good performance, prevented too many (unnecessary) REST calls and made sure the UI is responsive, even with large data (e.g. using paging).
  • I strictly followed the principle of data economy for all client-server REST calls.
  • I strictly followed the client coding and design guidelines.
  • I added multiple integration tests (Jest) related to the features (with a high test coverage), while following the test guidelines.
  • I added authorities to all new routes and checked the course groups for displaying navigation elements (links, buttons).

Motivation and Context

This is a temporary solution to ingest lecture video transcriptions into the Artemis MySQL database until the transcription generation is implemented. Those transcriptions are needed for Pyris, so that Iris can later on reference lecture videos in student questions.

Description

  • An UI endpoint was created to insert transcriptions
  • The transcriptions are added to the Artemis database
  • The ingestion pipeline can be triggered, and the transcriptions will be queried from the Artemis database and sent to Pyris

Steps for Testing

Prerequisites:

  • 1 Artemis Admin
  • 1 course
  • 1 lecture
  • 1 lecture unit
  • 1 transcription JSON
    example:
{
    "lectureId": 1,
    "language": "en",
    "segments": [
        {
            "startTime": 0.96,
            "endTime": 5.36,
            "text": "Welcome to the second lecture in the course Introduction to Software Engineering.",
            "lectureUnitId": 1,
            "slideNumber": 1
        },
        {
            "startTime": 5.36,
            "endTime": 11.120000000000001,
            "text": "Today we would like to talk about model-based software engineering from the problem statement",
            "lectureUnitId": 1,
            "slideNumber": 2
        },
        {
            "startTime": 11.120000000000001,
            "endTime": 17.04,
            "text": "to the potentially shippable product increment that you deliver to your end users.",
            "lectureUnitId": 1,
            "slideNumber": 3
        }
    ]
}
  1. Log in to Artemis as admin
  2. Navigate to admin/lecture-transcription-ingestion
  3. create a transcription by adding the JSON (with the lecture id of your lecture and the lecture unit id of your lecture unit)
  4. check whether status code 200 is returned (in the browser dev tools for POST api/transcription) or a green status message is shown & the transcription was inserted into the database
  5. query for the lecture id and the course id of your lecture & course in the ingest section
  6. Status code 500 with the body "could not fetch response from Pyris" should be returned (in the browser dev tools for api/courses/{courseId}/ingest-transcription)

Testserver States

Note

These badges show the state of the test servers.
Green = Currently available, Red = Currently locked
Click on the badges to get to the test servers.







Review Progress

Performance Review

  • I (as a reviewer) confirm that the client changes (in particular related to REST calls and UI responsiveness) are implemented with a very good performance even for very large courses with more than 2000 students.
  • I (as a reviewer) confirm that the server changes (in particular related to database calls) are implemented with a very good performance even for very large courses with more than 2000 students.

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Test Coverage

Summary by CodeRabbit

Summary by CodeRabbit

Here are the release notes for the provided pull request:

  • New Features

    • Added lecture transcription functionality to the Artemis platform.
    • Introduced ability to ingest and create lecture transcriptions.
    • Created admin interface for managing lecture transcriptions.
    • Implemented webhook support for transcription ingestion with Pyris.
  • Backend Improvements

    • Added new domain models for lecture transcriptions and transcription segments.
    • Created repositories and services to support transcription management.
    • Implemented REST endpoints for transcription creation and retrieval.
  • Frontend Improvements

    • Added new admin component for transcription ingestion.
    • Created service for handling transcription-related HTTP requests.
    • Implemented client-side validation and error handling for transcription operations.
  • Security

    • Restricted transcription ingestion to admin users.
    • Added permission checks for transcription access and creation.

@isabellagessl isabellagessl requested a review from a team as a code owner January 20, 2025 14:06
@github-actions github-actions bot added tests server Pull requests that update Java code. (Added Automatically!) client Pull requests that update TypeScript code. (Added Automatically!) database Pull requests that update the database. (Added Automatically!). Require a CRITICAL deployment. core Pull requests that affect the corresponding module iris Pull requests that affect the corresponding module lecture Pull requests that affect the corresponding module labels Jan 20, 2025
Copy link

coderabbitai bot commented Jan 20, 2025

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 pmd (7.8.0)
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java

The following rules are missing or misspelled in your ruleset file category/vm/bestpractices.xml: BooleanInstantiation, DontImportJavaLang, DuplicateImports, EmptyFinallyBlock, EmptyIfStmt, EmptyInitializer, EmptyStatementBlock, EmptyStatementNotInLoop, EmptySwitchStatements, EmptySynchronizedBlock, EmptyTryBlock, EmptyWhileStmt, ExcessiveClassLength, ExcessiveMethodLength, ImportFromSamePackage, MissingBreakInSwitch, SimplifyBooleanAssertion. Please check your ruleset configuration.

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

The following rules are missing or misspelled in your ruleset file category/vm/bestpractices.xml: BooleanInstantiation, DontImportJavaLang, DuplicateImports, EmptyFinallyBlock, EmptyIfStmt, EmptyInitializer, EmptyStatementBlock, EmptyStatementNotInLoop, EmptySwitchStatements, EmptySynchronizedBlock, EmptyTryBlock, EmptyWhileStmt, ExcessiveClassLength, ExcessiveMethodLength, ImportFromSamePackage, MissingBreakInSwitch, SimplifyBooleanAssertion. Please check your ruleset configuration.

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

The following rules are missing or misspelled in your ruleset file category/vm/bestpractices.xml: BooleanInstantiation, DontImportJavaLang, DuplicateImports, EmptyFinallyBlock, EmptyIfStmt, EmptyInitializer, EmptyStatementBlock, EmptyStatementNotInLoop, EmptySwitchStatements, EmptySynchronizedBlock, EmptyTryBlock, EmptyWhileStmt, ExcessiveClassLength, ExcessiveMethodLength, ImportFromSamePackage, MissingBreakInSwitch, SimplifyBooleanAssertion. Please check your ruleset configuration.

  • 1 others

Walkthrough

The pull request introduces a comprehensive feature for lecture transcription management in the Artemis application. The changes span both backend and frontend components, adding support for creating, ingesting, and managing lecture transcriptions. Key additions include new domain entities for transcriptions and transcription segments, repositories, services, and REST endpoints. The frontend receives a new admin component for transcription ingestion, along with corresponding services and tests. The implementation supports integration with the Pyris system for transcription processing and provides a robust mechanism for handling transcription data across different parts of the application.

Changes

File Change Summary
src/main/java/de/tum/cit/aet/artemis/lecture/domain/Lecture.java Added lectureTranscriptions field and related methods to manage transcriptions
src/main/java/de/tum/cit/aet/artemis/lecture/domain/LectureTranscription.java New domain entity for lecture transcriptions with JPA mapping
src/main/java/de/tum/cit/aet/artemis/lecture/domain/LectureTranscriptionSegment.java New domain entity for transcription segments
src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java Added LectureTranscriptionResource for REST endpoints to create and retrieve transcriptions
src/main/java/de/tum/cit/aet/artemis/lecture/service/LectureService.java Added ingestTranscriptionInPyris method
src/main/webapp/app/admin/... New Angular component and service for lecture transcription ingestion
src/test/java/... Added integration and unit tests for transcription-related functionality

Sequence Diagram

sequenceDiagram
    participant User
    participant LectureTranscriptionIngestionComponent
    participant LectureTranscriptionService
    participant LectureTranscriptionResource
    participant PyrisWebhookService

    User->>LectureTranscriptionIngestionComponent: Enter transcription details
    LectureTranscriptionIngestionComponent->>LectureTranscriptionService: ingestTranscription(courseId, lectureId)
    LectureTranscriptionService->>LectureTranscriptionResource: createLectureTranscription
    LectureTranscriptionResource-->>PyrisWebhookService: addTranscriptionsToPyrisDB
    PyrisWebhookService->>PyrisWebhookService: executeTranscriptionAdditionWebhook
    PyrisWebhookService-->>User: Transcription Ingested
Loading
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 25

🧹 Nitpick comments (15)
src/main/java/de/tum/cit/aet/artemis/iris/web/IrisTranscriptionResource.java (1)

73-81: Consider refactoring to eliminate code duplication

The two methods getStatusOfTranscriptionIngestion and getStatusOfLectureUnitsTranscriptionIngestion share similar code structures, including exception handling and authorization checks. Refactoring common logic into a private helper method can improve maintainability and adhere to the DRY (Don't Repeat Yourself) principle.

For example, you could create a private method to handle common authorization and error handling logic.

Also applies to: 101-109

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/job/TranscriptionIngestionWebhookJob.java (1)

8-9: Fix typographical error in class documentation

There's a typo in the class comment: "then Ingestion" should be "the Ingestion."

Apply this diff to correct the typo:

- * This job is used to reference the details of then Ingestion when Pyris sends a status update.
+ * This job is used to reference the details of the Ingestion when Pyris sends a status update.
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/dto/transcriptionIngestion/PyrisTranscriptionIngestionWebhookDTO.java (2)

14-14: Consider minimizing the DTO fields for data economy.

The DTO includes descriptive fields (lectureName, courseName, courseDescription) that might not be necessary for the transcription ingestion process. Consider if these fields are actually used by Pyris.

-public record PyrisTranscriptionIngestionWebhookDTO(Transcription transcription, long lectureId, String lectureName, long courseId, String courseName, String courseDescription) {
+public record PyrisTranscriptionIngestionWebhookDTO(Transcription transcription, long lectureId, long courseId) {

7-11: Enhance documentation with @param annotations.

The Javadoc should include @param annotations for each field to better document their purpose and requirements.

 /**
  * Represents a webhook data transfer object for lecture units in the Pyris system.
  * This DTO is used to encapsulate the information related to updates of lecture units,
  * providing necessary details such as lecture and course identifiers, names, and descriptions.
+ *
+ * @param transcription The transcription data to be ingested
+ * @param lectureId The unique identifier of the lecture
+ * @param lectureName The name of the lecture
+ * @param courseId The unique identifier of the course
+ * @param courseName The name of the course
+ * @param courseDescription The description of the course
  */
src/main/java/de/tum/cit/aet/artemis/lecture/repository/TranscriptionRepository.java (1)

23-29: Consider adding index hint for performance.

The query by ID with segments could benefit from an index hint.

     @Query("""
             SELECT t
             FROM Transcription t
+            /*+ INDEX(t transcription_id_idx) */
             LEFT JOIN FETCH t.segments
             WHERE t.id = :id
             """)
src/main/java/de/tum/cit/aet/artemis/lecture/domain/Transcription.java (2)

34-37: Consider adding index for ordered segments.

The @OrderBy annotation suggests frequent ordering of segments by start time. Consider adding a database index to optimize these queries.

Add index annotation:

     @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
     @OrderBy("startTime asc")
+    @Index(name = "idx_transcription_segment_start_time")
     @JoinColumn(name = "transcription_id")
     private List<TranscriptionSegment> segments = new ArrayList<>();

72-75: Enhance toString method with more relevant information.

The current toString implementation excludes the ID field, which could be useful for debugging.

Consider including the ID in the string representation:

     @Override
     public String toString() {
-        return "Transcription [language=" + language + ", segments=" + segments + "]";
+        return "Transcription [id=" + getId() + ", language=" + language + ", segments.size=" + segments.size() + "]";
     }
src/main/java/de/tum/cit/aet/artemis/lecture/domain/TranscriptionSegment.java (1)

28-29: Consider adding length constraint for text field.

The @Lob annotation allows for large text storage, but consider adding a reasonable maximum length to prevent excessive storage usage.

Add length constraint:

     @Lob
+    @Column(length = 10000) // Adjust the length based on your requirements
     private String text;
src/main/java/de/tum/cit/aet/artemis/lecture/web/TranscriptionResource.java (2)

31-31: Consider using a more specific base path.

The current base path "api/" is too generic. Consider using a more specific path like "api/transcriptions/" to better reflect the resource hierarchy.

-@RequestMapping("api/")
+@RequestMapping("api/transcriptions/")

65-67: Avoid explicit null assignment.

Setting the ID to null is unnecessary as it's already null for new entities.

         Transcription transcription = new Transcription(lecture, transcriptionDTO.language(), segments);
-        transcription.setId(null);
src/test/java/de/tum/cit/aet/artemis/iris/PyrisTranscriptionIngestionTest.java (1)

54-56: Avoid array initialization with List.of.

The current implementation uses an array initialization with List.of which is less readable. Consider using a direct List.of call.

-        Transcription transcription = new Transcription(this.lecture1, "en", List.of(new TranscriptionSegment[] { segment1, segment2 }));
+        Transcription transcription = new Transcription(this.lecture1, "en", List.of(segment1, segment2));
src/main/java/de/tum/cit/aet/artemis/lecture/domain/Lecture.java (1)

63-66: Consider using Set instead of List for transcriptions.

Since the order of transcriptions doesn't seem to be important (no @OrderColumn), using a Set might be more appropriate and could prevent duplicate entries.

     @OneToMany(mappedBy = "lecture", cascade = CascadeType.ALL, orphanRemoval = true)
     @JsonIgnoreProperties("lecture")
     @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
-    private List<Transcription> transcriptions = new ArrayList<>();
+    private Set<Transcription> transcriptions = new HashSet<>();
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisJobService.java (1)

112-126: Extract timeout constants and add parameter validation.

The implementation looks good but could be improved in two areas:

  1. The timeout values (60 minutes) are duplicated with addIngestionWebhookJob. Consider extracting these as class constants.
  2. Missing validation for negative course/lecture IDs.

Apply this diff to improve the implementation:

+    private static final long WEBHOOK_JOB_TIMEOUT = 60;
+    private static final TimeUnit WEBHOOK_JOB_TIMEOUT_UNIT = TimeUnit.MINUTES;
+
     public String addTranscriptionIngestionWebhookJob(long courseId, long lectureId) {
+        if (courseId < 0 || lectureId < 0) {
+            throw new IllegalArgumentException("Course ID and Lecture ID must be non-negative");
+        }
         var token = generateJobIdToken();
         var job = new TranscriptionIngestionWebhookJob(token, courseId, lectureId);
-        long timeoutWebhookJob = 60;
-        TimeUnit unitWebhookJob = TimeUnit.MINUTES;
-        jobMap.put(token, job, timeoutWebhookJob, unitWebhookJob);
+        jobMap.put(token, job, WEBHOOK_JOB_TIMEOUT, WEBHOOK_JOB_TIMEOUT_UNIT);
         return token;
     }
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (1)

88-100: Extract constants and document empty lists.

The implementation could be improved in two areas:

  1. The variant "fullIngestion" is hardcoded and duplicated with executeLectureAdditionWebhook.
  2. The purpose of empty lists in DTO construction is not documented.

Apply this diff to improve the implementation:

+    private static final String FULL_INGESTION_VARIANT = "fullIngestion";
+
     private String executeTranscriptionAdditionWebhook(
             PyrisTranscriptionIngestionWebhookDTO toUpdateTranscription) {
         String jobToken = pyrisJobService.addTranscriptionIngestionWebhookJob(
             toUpdateTranscription.courseId(), toUpdateTranscription.lectureId());
+        // TODO: Document the purpose of empty lists in DTO construction
         PyrisPipelineExecutionSettingsDTO settingsDTO = 
             new PyrisPipelineExecutionSettingsDTO(jobToken, List.of(), artemisBaseUrl);
         PyrisWebhookTranscriptionIngestionExecutionDTO executionDTO = 
             new PyrisWebhookTranscriptionIngestionExecutionDTO(
                 toUpdateTranscription, settingsDTO, List.of());
-        pyrisConnectorService.executeTranscriptionAdditionWebhook("fullIngestion", executionDTO);
+        pyrisConnectorService.executeTranscriptionAdditionWebhook(
+            FULL_INGESTION_VARIANT, executionDTO);
         return jobToken;
     }
src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.html (1)

1-18: Enhance accessibility and user experience.

The component would benefit from the following improvements:

  1. Add ARIA labels and roles for better accessibility
  2. Add form validation feedback
  3. Add loading state indicators during API calls

Apply this diff to improve the implementation:

-<div>
+<div role="main" aria-labelledby="page-title">
-    <h1>Lecture Transcription</h1>
+    <h1 id="page-title">Lecture Transcription</h1>
-    <div>
+    <div role="form" aria-label="Transcription Ingestion Form">
         <h2>Ingest</h2>
         <p>Ingest transcription into Pyris Weaviate DB</p>
-        <input placeholder="Course Id" [(ngModel)]="courseIdInput" />
-        <input placeholder="Lecture Id" [(ngModel)]="lectureIdInput" />
+        <input 
+            placeholder="Course Id" 
+            [(ngModel)]="courseIdInput"
+            aria-label="Course ID"
+            [attr.aria-invalid]="!isValidCourseId"
+            required />
+        <div *ngIf="!isValidCourseId" class="error-message" role="alert">
+            Please enter a valid course ID
+        </div>
+        <input 
+            placeholder="Lecture Id" 
+            [(ngModel)]="lectureIdInput"
+            aria-label="Lecture ID"
+            [attr.aria-invalid]="!isValidLectureId"
+            required />
+        <div *ngIf="!isValidLectureId" class="error-message" role="alert">
+            Please enter a valid lecture ID
+        </div>
-        <jhi-button id="ingest-transcription-button" [icon]="faCheck" (onClick)="ingestTranscription()" />
+        <jhi-button 
+            id="ingest-transcription-button" 
+            [icon]="faCheck" 
+            (onClick)="ingestTranscription()"
+            [loading]="isIngesting"
+            [disabled]="!isValidForm || isIngesting"
+            aria-label="Ingest Transcription" />
     </div>
-    <div class="insert-db-container">
+    <div class="insert-db-container" role="form" aria-label="Transcription Creation Form">
         <h2>Create</h2>
         <p>Create transcription into Artemis DB</p>
         <div class="insert-transcription-row">
-            <textarea placeholder="Transcription as JSON" class="insert-transcription-area" [(ngModel)]="transcriptionInput"></textarea>
-            <jhi-button id="create-transcription-button" [icon]="faCheck" (onClick)="createTranscription()" />
+            <textarea 
+                placeholder="Transcription as JSON" 
+                class="insert-transcription-area" 
+                [(ngModel)]="transcriptionInput"
+                aria-label="Transcription JSON"
+                [attr.aria-invalid]="!isValidJson"
+                required></textarea>
+            <div *ngIf="!isValidJson" class="error-message" role="alert">
+                Please enter valid JSON
+            </div>
+            <jhi-button 
+                id="create-transcription-button" 
+                [icon]="faCheck" 
+                (onClick)="createTranscription()"
+                [loading]="isCreating"
+                [disabled]="!isValidJson || isCreating"
+                aria-label="Create Transcription" />
         </div>
     </div>
 </div>
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between acb1220 and 57427ed.

⛔ Files ignored due to path filters (2)
  • src/main/resources/config/liquibase/changelog/20250113154600_changelog.xml is excluded by !**/*.xml
  • src/main/resources/config/liquibase/master.xml is excluded by !**/*.xml
📒 Files selected for processing (27)
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisConnectorService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisJobService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/dto/transcriptionIngestion/PyrisTranscriptionIngestionWebhookDTO.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/dto/transcriptionIngestion/PyrisWebhookTranscriptionIngestionExecutionDTO.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/job/TranscriptionIngestionWebhookJob.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/iris/web/IrisTranscriptionResource.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/domain/Lecture.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/domain/Transcription.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/domain/TranscriptionSegment.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/dto/TranscriptionDTO.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/dto/TranscriptionSegmentDTO.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/repository/LectureRepository.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/repository/TranscriptionRepository.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/service/LectureService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (5 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/web/TranscriptionResource.java (1 hunks)
  • src/main/webapp/app/admin/admin.routes.ts (1 hunks)
  • src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.html (1 hunks)
  • src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.scss (1 hunks)
  • src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.ts (1 hunks)
  • src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription.service.ts (1 hunks)
  • src/main/webapp/i18n/en/global.json (1 hunks)
  • src/test/java/de/tum/cit/aet/artemis/core/connector/IrisRequestMockProvider.java (2 hunks)
  • src/test/java/de/tum/cit/aet/artemis/iris/PyrisTranscriptionIngestionTest.java (1 hunks)
  • src/test/javascript/spec/component/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.spec.ts (1 hunks)
  • src/test/javascript/spec/component/admin/lecture-transcription-ingestion/lecture-transcription.service.spec.ts (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • src/main/java/de/tum/cit/aet/artemis/lecture/dto/TranscriptionSegmentDTO.java
  • src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.scss
  • src/main/java/de/tum/cit/aet/artemis/lecture/dto/TranscriptionDTO.java
🧰 Additional context used
📓 Path-based instructions (23)
src/main/webapp/app/admin/admin.routes.ts (1)

Pattern src/main/webapp/**/*.ts: angular_style:https://angular.io/guide/styleguide;methods_in_html:false;lazy_loading:true;code_reuse:true;tests:meaningful;types:PascalCase;enums:PascalCase;funcs:camelCase;props:camelCase;no_priv_prefix:true;strings:single_quotes;localize:true;btns:functionality;links:navigation;icons_text:newline;labels:associate;code_style:arrow_funcs,curly_braces,open_braces_same_line,indent_4;memory_leak_prevention:true;routes:naming_schema;chart_framework:ngx-charts;responsive_layout:true

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisConnectorService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/dto/transcriptionIngestion/PyrisWebhookTranscriptionIngestionExecutionDTO.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.ts (1)

Pattern src/main/webapp/**/*.ts: angular_style:https://angular.io/guide/styleguide;methods_in_html:false;lazy_loading:true;code_reuse:true;tests:meaningful;types:PascalCase;enums:PascalCase;funcs:camelCase;props:camelCase;no_priv_prefix:true;strings:single_quotes;localize:true;btns:functionality;links:navigation;icons_text:newline;labels:associate;code_style:arrow_funcs,curly_braces,open_braces_same_line,indent_4;memory_leak_prevention:true;routes:naming_schema;chart_framework:ngx-charts;responsive_layout:true

src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.html (1)

Pattern src/main/webapp/**/*.html: @if and @for are new and valid Angular syntax replacing *ngIf and *ngFor. They should always be used over the old style.

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/dto/transcriptionIngestion/PyrisTranscriptionIngestionWebhookDTO.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/lecture/repository/TranscriptionRepository.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

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

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/job/TranscriptionIngestionWebhookJob.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/lecture/web/TranscriptionResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

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

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription.service.ts (1)

Pattern src/main/webapp/**/*.ts: angular_style:https://angular.io/guide/styleguide;methods_in_html:false;lazy_loading:true;code_reuse:true;tests:meaningful;types:PascalCase;enums:PascalCase;funcs:camelCase;props:camelCase;no_priv_prefix:true;strings:single_quotes;localize:true;btns:functionality;links:navigation;icons_text:newline;labels:associate;code_style:arrow_funcs,curly_braces,open_braces_same_line,indent_4;memory_leak_prevention:true;routes:naming_schema;chart_framework:ngx-charts;responsive_layout:true

src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/lecture/domain/TranscriptionSegment.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/test/javascript/spec/component/admin/lecture-transcription-ingestion/lecture-transcription.service.spec.ts (1)

Pattern src/test/javascript/spec/**/*.ts: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}

src/test/java/de/tum/cit/aet/artemis/core/connector/IrisRequestMockProvider.java (1)

Pattern src/test/java/**/*.java: test_naming: descriptive; test_size: small_specific; fixed_data: true; junit5_features: true; assert_use: assertThat; assert_specificity: true; archunit_use: enforce_package_rules; db_query_count_tests: track_performance; util_service_factory_pattern: true; avoid_db_access: true; mock_strategy: static_mocks; context_restart_minimize: true

src/test/javascript/spec/component/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.spec.ts (1)

Pattern src/test/javascript/spec/**/*.ts: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}

src/test/java/de/tum/cit/aet/artemis/iris/PyrisTranscriptionIngestionTest.java (1)

Pattern src/test/java/**/*.java: test_naming: descriptive; test_size: small_specific; fixed_data: true; junit5_features: true; assert_use: assertThat; assert_specificity: true; archunit_use: enforce_package_rules; db_query_count_tests: track_performance; util_service_factory_pattern: true; avoid_db_access: true; mock_strategy: static_mocks; context_restart_minimize: true

src/main/java/de/tum/cit/aet/artemis/iris/web/IrisTranscriptionResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisJobService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/lecture/domain/Lecture.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/lecture/domain/Transcription.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: client-tests
  • GitHub Check: server-tests
  • GitHub Check: Build and Push Docker Image
  • GitHub Check: Build .war artifact
  • GitHub Check: Analyse
🔇 Additional comments (7)
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/dto/transcriptionIngestion/PyrisWebhookTranscriptionIngestionExecutionDTO.java (1)

1-13: Implementation aligns with DTO best practices

The PyrisWebhookTranscriptionIngestionExecutionDTO is correctly implemented as a Java record, which is suitable for a simple data carrier. The use of @JsonInclude(JsonInclude.Include.NON_EMPTY) ensures that only non-empty fields are serialized, which is efficient for JSON payloads.

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/job/TranscriptionIngestionWebhookJob.java (1)

13-20: Verify the intended behavior of canAccess methods

Both canAccess methods return false, which might restrict all access. Please verify if this is the intended behavior. If so, consider adding a comment to explain why access is always denied, improving code clarity.

src/main/webapp/app/admin/admin.routes.ts (1)

156-163: LGTM! Route configuration follows best practices.

The route configuration is well-structured with:

  • Proper lazy loading
  • Correct authority checks
  • Consistent naming with other routes
src/test/java/de/tum/cit/aet/artemis/core/connector/IrisRequestMockProvider.java (2)

40-40: LGTM!

The import statement follows the project's import organization pattern.


175-182: LGTM!

The implementation follows the established pattern for mock methods in this class, with proper request handling and response generation.

src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (1)

54-56: LGTM!

The imports and field declaration follow the project's conventions.

src/main/webapp/i18n/en/global.json (1)

120-121: LGTM!

The new translation key follows the existing pattern and naming conventions.

@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java (2)

89-89: 🛠️ Refactor suggestion

Use UriComponentsBuilder for safe and consistent URI construction.

Manually constructing URIs can be error-prone and may lead to issues if path variables change. Utilize UriComponentsBuilder for safer URI construction and to ensure consistency across the application.

Apply this diff to improve URI construction:

-return ResponseEntity.created(new URI("/api/lecture/" + lectureId + "/transcriptions/" + result.getId())).body(result);
+return ResponseEntity.created(UriComponentsBuilder
+    .fromPath("/api/courses/{courseId}/lecture/{lectureId}/transcriptions/{transcriptionId}")
+    .buildAndExpand(courseId, lectureId, result.getId())
+    .toUri())
+    .body(result);

99-101: 🛠️ Refactor suggestion

Ensure URI paths are consistent and update method naming.

The GET endpoint's URI is inconsistent with the POST endpoint's URI. To maintain consistency and clarity, update the URI path to include courses/{courseId} and adjust the method name to getLectureTranscription to reflect that it retrieves a single transcription.

Apply this diff to correct the URI path and method name:

-@GetMapping("lectures/{lectureId}/transcription/{transcriptionId}")
+@GetMapping("courses/{courseId}/lecture/{lectureId}/transcriptions/{transcriptionId}")
 @EnforceAtLeastStudent
-public ResponseEntity<LectureTranscription> getLectureTranscriptions(@PathVariable Long lectureId, @PathVariable Long transcriptionId) {
+public ResponseEntity<LectureTranscription> getLectureTranscription(@PathVariable Long courseId, @PathVariable Long lectureId, @PathVariable Long transcriptionId) {
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (1)

118-118: ⚠️ Potential issue

Handle exceptions during webhook execution.

The call to pyrisConnectorService.executeTranscriptionAdditionWebhook might throw exceptions. Implement try-catch blocks to handle these exceptions gracefully and log appropriate error messages.

Apply this diff to add error handling:

-        pyrisConnectorService.executeTranscriptionAdditionWebhook("fullIngestion", executionDTO);
+        try {
+            pyrisConnectorService.executeTranscriptionAdditionWebhook("fullIngestion", executionDTO);
+        } catch (Exception e) {
+            log.error("Failed to execute transcription addition webhook: {}", e.getMessage());
+            throw new IrisInternalPyrisErrorException("Error executing transcription addition webhook", e);
+        }
🧹 Nitpick comments (7)
src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java (3)

80-82: Delegate business logic to a service layer.

The controller currently handles business logic such as mapping DTOs to entities and processing data. Moving this logic to a dedicated service class adheres to the Single Responsibility Principle and improves maintainability.

Consider creating a service method to handle the transcription creation process, which can be called from the controller.


42-42: Declare the logger as private static final.

It's a best practice to declare loggers as private static final to indicate that they are class-level constants and to prevent unnecessary allocation of resources.

Apply this diff to adjust the logger declaration:

-private final Logger log = LoggerFactory.getLogger(LectureTranscriptionResource.class);
+private static final Logger log = LoggerFactory.getLogger(LectureTranscriptionResource.class);

70-70: Ensure consistency in URI path formatting.

The URI path should start with a forward slash for consistency and to adhere to common RESTful practices.

Apply this diff to adjust the URI path:

-@PostMapping(value = "courses/{courseId}/lecture/{lectureId}/transcriptions")
+@PostMapping(value = "/courses/{courseId}/lectures/{lectureId}/transcriptions")
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (4)

83-83: Clarify exception message for empty transcriptions.

The exception message should accurately reflect that transcriptions cannot be null or empty to provide clear feedback when validation fails.

Apply this diff to update the exception message:

-            throw new IllegalArgumentException("Transcriptions cannot be empty");
+            throw new IllegalArgumentException("Transcriptions cannot be null or empty");

108-112: Improve method documentation for clarity and completeness.

The method documentation is currently vague and does not provide detailed information about the parameters and return value. Enhance the Javadoc to fully describe the method's purpose, parameters, and expected outcomes.

Update the documentation:

/**
 * Executes the transcription addition webhook to insert the transcriptions into the Pyris vector database.
 *
 * @param toUpdateTranscriptions The list of transcriptions to update.
 * @param course The course associated with the transcriptions.
 * @param lecture The lecture associated with the transcriptions.
 * @return The job token if the job was successfully created.
 */

116-117: Add null checks for method parameters.

To prevent unexpected errors, add null checks for toUpdateTranscriptions, course, and lecture. This ensures that all required data is present before proceeding.

Consider adding these validations:

if (toUpdateTranscriptions == null || toUpdateTranscriptions.isEmpty()) {
    throw new IllegalArgumentException("Transcriptions to update cannot be null or empty");
}
if (course == null) {
    throw new IllegalArgumentException("Course cannot be null");
}
if (lecture == null) {
    throw new IllegalArgumentException("Lecture cannot be null");
}

118-118: Log the transaction details for auditing purposes.

Adding logging statements that include the course and lecture IDs can help with monitoring and debugging the ingestion process.

Add a logging statement before executing the webhook:

log.info("Executing transcription addition webhook for course {}, lecture {}", course.getId(), lecture.getId());
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1a820ed and 90344df.

⛔ Files ignored due to path filters (1)
  • src/main/resources/config/liquibase/changelog/20250113154600_changelog.xml is excluded by !**/*.xml
📒 Files selected for processing (6)
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisConnectorService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/dto/transcriptionIngestion/PyrisWebhookTranscriptionIngestionExecutionDTO.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/service/LectureService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (5 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/java/de/tum/cit/aet/artemis/lecture/service/LectureService.java
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisConnectorService.java
  • src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java
🧰 Additional context used
📓 Path-based instructions (3)
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/dto/transcriptionIngestion/PyrisWebhookTranscriptionIngestionExecutionDTO.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: server-tests
  • GitHub Check: client-tests-selected
  • GitHub Check: client-style
  • GitHub Check: server-style
  • GitHub Check: client-tests
  • GitHub Check: Build and Push Docker Image
  • GitHub Check: Build .war artifact
  • GitHub Check: Analyse
🔇 Additional comments (4)
src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java (2)

85-85: Remove redundant setId(null) when creating new entities.

Setting the id to null is unnecessary. When saving a new entity, the persistence framework will handle ID assignment automatically.

Apply this diff to remove the redundant line:

-        lectureTranscription.setId(null);

74-74: Use path variable lectureId instead of transcriptionDTO.lectureId().

For security and consistency, use the lectureId from the path variable when retrieving the lecture. This ensures that the client cannot override the lecture ID in the request body.

[security_issue]

Apply this diff to use the path variable:

-Lecture lecture = lectureRepository.findById(transcriptionDTO.lectureId()).orElseThrow(() -> new EntityNotFoundException("no lecture found for this id"));
+Lecture lecture = lectureRepository.findById(lectureId).orElseThrow(() -> new EntityNotFoundException("No lecture found for ID " + lectureId));
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/dto/transcriptionIngestion/PyrisWebhookTranscriptionIngestionExecutionDTO.java (1)

1-13: Code conforms to DTO best practices.

The PyrisWebhookTranscriptionIngestionExecutionDTO record appropriately encapsulates the necessary data fields and follows the project's DTO guidelines, including using Java records and minimal data.

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (1)

99-102: Avoid passing entities directly to DTO constructors.

To reduce coupling and prevent unintended data exposure, avoid passing entity objects directly to DTO constructors. Instead, extract only the necessary fields from the entities.

[security_issue]

Refactor the DTO creation to use explicit fields:

.map(transcription -> new PyrisTranscriptionIngestionWebhookDTO(
    transcription.getId(),
    lecture.getId(),
    lecture.getTitle(),
    course.getId(),
    course.getTitle(),
    course.getDescription()
))

@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 21, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/test/java/de/tum/cit/aet/artemis/iris/PyrisTranscriptionIngestionTest.java (1)

61-86: 🛠️ Refactor suggestion

Enhance test coverage with additional test cases.

The current test suite could be expanded to cover more scenarios:

  1. Missing negative test cases (e.g., invalid input)
  2. Limited assertions (only checking auth token)
  3. No validation of the actual transcription data

Consider adding these test cases:

@Test
@WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR")
void testIngestTranscriptionWithInvalidJson() {
    activateIrisFor(lecture1.getCourse());
    request.put("/api/courses/" + lecture1.getCourse().getId() + "/lectures/" + lecture1.getId() + "/ingest-transcription",
        Optional.of("invalid json"), 
        HttpStatus.BAD_REQUEST);
}

@Test
@WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR")
void testIngestTranscriptionVerifyData() {
    activateIrisFor(lecture1.getCourse());
    irisRequestMockProvider.mockTranscriptionIngestionWebhookRunResponse(dto -> {
        assertThat(dto.settings().authenticationToken()).isNotNull();
        assertThat(dto.data()).isNotNull();
        // Add more specific data validations
    });
    request.put("/api/courses/" + lecture1.getCourse().getId() + "/lectures/" + lecture1.getId() + "/ingest-transcription", 
        Optional.empty(), 
        HttpStatus.OK);
}
🧹 Nitpick comments (4)
src/test/java/de/tum/cit/aet/artemis/iris/PyrisTranscriptionIngestionTest.java (2)

28-28: Follow Java naming conventions for repository variable.

The variable name lecturetranscriptionRepository should be in camelCase format.

-    private LectureTranscriptionRepository lecturetranscriptionRepository;
+    private LectureTranscriptionRepository lectureTranscriptionRepository;

41-59: Improve test setup organization and documentation.

The setup method could be improved in several ways:

  1. Add JavaDoc explaining the test setup and data
  2. Extract helper methods for better organization
  3. Use constants for test data values

Consider refactoring like this:

+    private static final double SEGMENT_START_TIME = 0.0;
+    private static final double SEGMENT_END_TIME = 12.0;
+    private static final String SEGMENT_1_TEXT = "Welcome to today's lecture";
+    private static final String SEGMENT_2_TEXT = "Today we will talk about Artemis";
+
+    /**
+     * Sets up test environment with:
+     * - Users: 1 instructor, 1 student, 1 tutor
+     * - Course with exercises and lectures
+     * - Lecture with two transcription segments
+     * - Additional users not in the course
+     */
     @BeforeEach
     void initTestCase() throws Exception {
+        setupUsers();
+        setupCourseAndLecture();
+        setupTranscription();
+    }
+
+    private void setupUsers() {
         userUtilService.addUsers(TEST_PREFIX, 1, 1, 0, 1);
+        setupAdditionalUsers();
+    }
src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (2)

301-307: Update the JavaDoc description.

The current description appears to be copied from another endpoint. It should describe the transcription ingestion functionality instead.

-     * This endpoint is for starting the ingestion of all lectures or only one lecture when triggered in Artemis.
+     * This endpoint is for ingesting lecture transcriptions into Pyris.
      *
-     * @param lectureId If this id is present then only ingest this one lecture of the respective course
+     * @param courseId the ID of the course containing the lecture
+     * @param lectureId the ID of the lecture whose transcriptions should be ingested
      * @return the ResponseEntity with status 200 (OK) and a message success or null if the operation failed

324-325: Remove unnecessary Set conversion.

The transcriptions variable is already a Set, making the HashSet conversion redundant.

-        Set<LectureTranscription> transcriptionsToIngest = new HashSet<>(transcriptions);
-        lectureService.ingestTranscriptionInPyris(transcriptionsToIngest, course, lecture);
+        lectureService.ingestTranscriptionInPyris(transcriptions, lecture.getCourse(), lecture);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 90344df and 5191ef0.

📒 Files selected for processing (6)
  • src/main/java/de/tum/cit/aet/artemis/lecture/repository/LectureTranscriptionRepository.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/repository/LectureUnitRepository.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (5 hunks)
  • src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.ts (1 hunks)
  • src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription.service.ts (1 hunks)
  • src/test/java/de/tum/cit/aet/artemis/iris/PyrisTranscriptionIngestionTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/main/java/de/tum/cit/aet/artemis/lecture/repository/LectureUnitRepository.java
  • src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription.service.ts
  • src/main/webapp/app/admin/lecture-transcription-ingestion/lecture-transcription-ingestion.component.ts
  • src/main/java/de/tum/cit/aet/artemis/lecture/repository/LectureTranscriptionRepository.java
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/test/java/de/tum/cit/aet/artemis/iris/PyrisTranscriptionIngestionTest.java (1)

Pattern src/test/java/**/*.java: test_naming: descriptive; test_size: small_specific; fixed_data: true; junit5_features: true; assert_use: assertThat; assert_specificity: true; archunit_use: enforce_package_rules; db_query_count_tests: track_performance; util_service_factory_pattern: true; avoid_db_access: true; mock_strategy: static_mocks; context_restart_minimize: true

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: server-tests
  • GitHub Check: client-tests
  • GitHub Check: Analyse
  • GitHub Check: Build and Push Docker Image
🔇 Additional comments (3)
src/test/java/de/tum/cit/aet/artemis/iris/PyrisTranscriptionIngestionTest.java (1)

71-76: 🛠️ Refactor suggestion

Improve error handling test expectations.

The test expects INTERNAL_SERVER_ERROR for an invalid lecture ID, which is not the most appropriate status code. A NOT_FOUND status would be more suitable for this scenario.

-        request.put("/api/courses/" + lecture1.getCourse().getId() + "/lectures/" + 9999L + "/ingest-transcription", Optional.empty(), HttpStatus.INTERNAL_SERVER_ERROR);
+        request.put("/api/courses/" + lecture1.getCourse().getId() + "/lectures/" + 9999L + "/ingest-transcription", Optional.empty(), HttpStatus.NOT_FOUND);

Likely invalid or redundant comment.

src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (2)

53-53: LGTM!

The imports are specific and follow Java best practices.

Also applies to: 56-56


74-75: LGTM!

The changes follow Spring best practices:

  • Constructor injection is used
  • Repository field is properly encapsulated

Also applies to: 99-110

@ls1intum ls1intum deleted a comment from coderabbitai bot Jan 21, 2025
coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 21, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java (1)

101-106: ⚠️ Potential issue

Fix inconsistencies in endpoint implementation.

  1. URL pattern is inconsistent with POST endpoint (should be courses/{courseId}/lecture/{lectureId}/transcriptions/{transcriptionId})
  2. Method name should be getTranscription (singular) to match its functionality
  3. Improve exception handling for not found case
-    @GetMapping("lectures/{lectureId}/transcription/{transcriptionId}")
+    @GetMapping("courses/{courseId}/lecture/{lectureId}/transcriptions/{transcriptionId}")
     @EnforceAtLeastStudent
-    public ResponseEntity<LectureTranscription> getLectureTranscriptions(@PathVariable Long lectureId, @PathVariable Long transcriptionId) {
+    public ResponseEntity<LectureTranscription> getTranscription(
+            @PathVariable Long courseId,
+            @PathVariable Long lectureId,
+            @PathVariable Long transcriptionId) {
         log.debug("REST request to get transcription {}", transcriptionId);
-        LectureTranscription transcription = lectureTranscriptionRepository.findById(transcriptionId).orElseThrow();
+        LectureTranscription transcription = lectureTranscriptionRepository.findById(transcriptionId)
+            .orElseThrow(() -> new EntityNotFoundException("Transcription not found with id " + transcriptionId));
🧹 Nitpick comments (7)
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (3)

75-82: Enhance JavaDoc with @throws documentation.

Add @throws IllegalArgumentException to document the validation exceptions.

     /**
      * adds the transcription to the vector database in Pyris
      *
      * @param transcriptions The transcription that got Updated
      * @param course         The course of the transcriptions
      * @param lecture        The lecture of the transcriptions
      * @return jobToken if the job was created else null
+     * @throws IllegalArgumentException if transcriptions is null/empty or if any transcription is invalid
      */

83-107: Consider consolidating validation checks.

The implementation looks good but could benefit from consolidating the validation checks for better maintainability.

     public String addTranscriptionsToPyrisDB(Set<LectureTranscription> transcriptions, Course course, Lecture lecture) {
-        if (transcriptions == null || transcriptions.isEmpty()) {
-            throw new IllegalArgumentException("Transcriptions cannot be empty");
-        }
-
-        if (!lectureIngestionEnabled(course)) {
-            return null;
-        }
-
-        transcriptions.forEach(transcription -> {
-            if (transcription.getLecture() == null) {
-                throw new IllegalArgumentException("Transcription must be associated with a lecture");
-            }
-            else if (!transcription.getLecture().equals(lecture)) {
-                throw new IllegalArgumentException("All transcriptions must be associated with the same lecture");
-            }
-        });
+        validateTranscriptions(transcriptions, lecture);
+        
+        if (!lectureIngestionEnabled(course)) {
+            return null;
+        }
 
         List<PyrisTranscriptionIngestionWebhookDTO> pyrisTranscriptionIngestionWebhookDTOs = transcriptions.stream()
                 .map(transcription -> new PyrisTranscriptionIngestionWebhookDTO(transcription, lecture.getId(), lecture.getTitle(), course.getId(), course.getTitle(),
                         course.getDescription()))
                 .toList();
 
         return executeTranscriptionAdditionWebhook(pyrisTranscriptionIngestionWebhookDTOs, course, lecture);
     }
+
+    private void validateTranscriptions(Set<LectureTranscription> transcriptions, Lecture lecture) {
+        if (transcriptions == null || transcriptions.isEmpty()) {
+            throw new IllegalArgumentException("Transcriptions cannot be empty");
+        }
+
+        transcriptions.forEach(transcription -> {
+            if (transcription.getLecture() == null) {
+                throw new IllegalArgumentException("Transcription must be associated with a lecture");
+            }
+            else if (!transcription.getLecture().equals(lecture)) {
+                throw new IllegalArgumentException("All transcriptions must be associated with the same lecture");
+            }
+        });
+    }

109-122: Document all parameters and hardcoded values.

The implementation looks good but needs better documentation:

  1. Add missing parameter documentation.
  2. Document the hardcoded "fullIngestion" variant.
     /**
      * executes executeTranscriptionAdditionWebhook to insert the transcription into the vector database of Pyris
      *
      * @param toUpdateTranscriptions The transcription that are going to be Updated
+     * @param course The course containing the transcriptions
+     * @param lecture The lecture containing the transcriptions
      * @return jobToken if the job was created
      */
     private String executeTranscriptionAdditionWebhook(List<PyrisTranscriptionIngestionWebhookDTO> toUpdateTranscriptions, Course course, Lecture lecture) {
         String jobToken = pyrisJobService.addTranscriptionIngestionWebhookJob(course.getId(), lecture.getId());
         PyrisPipelineExecutionSettingsDTO settingsDTO = new PyrisPipelineExecutionSettingsDTO(jobToken, List.of(), artemisBaseUrl);
         PyrisWebhookTranscriptionIngestionExecutionDTO executionDTO = new PyrisWebhookTranscriptionIngestionExecutionDTO(toUpdateTranscriptions, lecture.getTitle(), settingsDTO,
                 List.of());
+        // "fullIngestion" variant indicates a complete ingestion of all transcription data
         pyrisConnectorService.executeTranscriptionAdditionWebhook("fullIngestion", executionDTO);
         return jobToken;
     }
src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (1)

301-308: Update the JavaDoc description.

The current JavaDoc description appears to be copy-pasted from another endpoint and incorrectly describes the functionality. Update it to accurately describe the transcription ingestion endpoint.

-     * This endpoint is for starting the ingestion of all lectures or only one lecture when triggered in Artemis.
+     * This endpoint triggers the ingestion of transcriptions for a specific lecture into Pyris.
src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java (3)

39-39: Consider adding API version prefix to base path.

The base path api/ should include version information (e.g., api/v1/) to support future API versioning and backward compatibility.

-@RequestMapping("api/")
+@RequestMapping("api/v1/")

86-88: Remove redundant ID nullification.

Setting ID to null is redundant as new entities should not have an ID set in the DTO.

         LectureTranscription lectureTranscription = new LectureTranscription(lecture, transcriptionDTO.language(), segments);
-        lectureTranscription.setId(null);

91-91: Use UriComponentsBuilder for URI construction.

Use Spring's UriComponentsBuilder to safely construct URIs instead of string concatenation.

-        return ResponseEntity.created(new URI("/api/lecture/" + lectureId + "/transcriptions/" + result.getId())).body(result);
+        return ResponseEntity.created(
+            UriComponentsBuilder.fromPath("/api/lecture/{lectureId}/transcriptions/{id}")
+                .buildAndExpand(lectureId, result.getId())
+                .toUri()
+        ).body(result);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5191ef0 and 53dcba7.

📒 Files selected for processing (4)
  • src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/service/LectureService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (5 hunks)
  • src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/de/tum/cit/aet/artemis/lecture/service/LectureService.java
🧰 Additional context used
📓 Path-based instructions (3)
src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

🔇 Additional comments (4)
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisWebhookService.java (1)

33-34: LGTM! Clean import statements.

The imports are well-organized and follow Java best practices by avoiding wildcard imports.

Also applies to: 39-39

src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureResource.java (2)

53-53: LGTM!

The imports are specific and follow Java conventions.

Also applies to: 56-56


74-75: LGTM!

The dependency injection follows the constructor injection pattern and maintains consistency with other repository fields.

Also applies to: 99-111

src/main/java/de/tum/cit/aet/artemis/lecture/web/LectureTranscriptionResource.java (1)

42-61: Well-structured dependency injection!

Good practices observed:

  • Constructor injection
  • Final fields
  • Proper logger setup

Comment on lines +319 to +326
Set<LectureTranscription> transcriptions = lectureTranscriptionRepository.findAllWithTranscriptionSegmentsByLectureId(lectureId);
if (transcriptions.isEmpty()) {
return ResponseEntity.badRequest().headers(HeaderUtil.createAlert(applicationName, "artemisApp.iris.ingestionAlert.noTranscriptionError", "noTranscription"))
.body(null);
}
Set<LectureTranscription> transcriptionsToIngest = new HashSet<>(transcriptions);
lectureService.ingestTranscriptionInPyris(transcriptionsToIngest, course, lecture);
return ResponseEntity.ok().build();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove redundant course variable and simplify transcription ingestion.

The course variable is only used as a parameter for ingestTranscriptionInPyris. Since we can get the course from the lecture object, we can simplify this code.

         Set<LectureTranscription> transcriptions = lectureTranscriptionRepository.findAllWithTranscriptionSegmentsByLectureId(lectureId);
         if (transcriptions.isEmpty()) {
             return ResponseEntity.badRequest().headers(HeaderUtil.createAlert(applicationName, "artemisApp.iris.ingestionAlert.noTranscriptionError", "noTranscription"))
                     .body(null);
         }
         Set<LectureTranscription> transcriptionsToIngest = new HashSet<>(transcriptions);
-        lectureService.ingestTranscriptionInPyris(transcriptionsToIngest, course, lecture);
+        lectureService.ingestTranscriptionInPyris(transcriptionsToIngest, lecture.getCourse(), lecture);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Set<LectureTranscription> transcriptions = lectureTranscriptionRepository.findAllWithTranscriptionSegmentsByLectureId(lectureId);
if (transcriptions.isEmpty()) {
return ResponseEntity.badRequest().headers(HeaderUtil.createAlert(applicationName, "artemisApp.iris.ingestionAlert.noTranscriptionError", "noTranscription"))
.body(null);
}
Set<LectureTranscription> transcriptionsToIngest = new HashSet<>(transcriptions);
lectureService.ingestTranscriptionInPyris(transcriptionsToIngest, course, lecture);
return ResponseEntity.ok().build();
Set<LectureTranscription> transcriptions = lectureTranscriptionRepository.findAllWithTranscriptionSegmentsByLectureId(lectureId);
if (transcriptions.isEmpty()) {
return ResponseEntity.badRequest().headers(HeaderUtil.createAlert(applicationName, "artemisApp.iris.ingestionAlert.noTranscriptionError", "noTranscription"))
.body(null);
}
Set<LectureTranscription> transcriptionsToIngest = new HashSet<>(transcriptions);
lectureService.ingestTranscriptionInPyris(transcriptionsToIngest, lecture.getCourse(), lecture);
return ResponseEntity.ok().build();

Comment on lines +313 to +318
Lecture lecture = lectureRepository.findById(lectureId).orElseThrow();
Course course = lecture.getCourse();
if (!lecture.getCourse().getId().equals(courseId)) {
return ResponseEntity.badRequest().headers(HeaderUtil.createAlert(applicationName, "artemisApp.iris.ingestionAlert.wrongLectureError", "lectureDoesNotMatchCourse"))
.body(null);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify error handling using custom exceptions.

Replace the manual course ID validation with a custom exception for better error handling consistency.

-        Course course = lecture.getCourse();
-        if (!lecture.getCourse().getId().equals(courseId)) {
-            return ResponseEntity.badRequest().headers(HeaderUtil.createAlert(applicationName, "artemisApp.iris.ingestionAlert.wrongLectureError", "lectureDoesNotMatchCourse"))
-                    .body(null);
-        }
+        if (!lecture.getCourse().getId().equals(courseId)) {
+            throw new BadRequestAlertException("Lecture does not belong to the specified course", ENTITY_NAME, "lectureDoesNotMatchCourse");
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Lecture lecture = lectureRepository.findById(lectureId).orElseThrow();
Course course = lecture.getCourse();
if (!lecture.getCourse().getId().equals(courseId)) {
return ResponseEntity.badRequest().headers(HeaderUtil.createAlert(applicationName, "artemisApp.iris.ingestionAlert.wrongLectureError", "lectureDoesNotMatchCourse"))
.body(null);
}
Lecture lecture = lectureRepository.findById(lectureId).orElseThrow();
if (!lecture.getCourse().getId().equals(courseId)) {
throw new BadRequestAlertException("Lecture does not belong to the specified course", ENTITY_NAME, "lectureDoesNotMatchCourse");
}

Comment on lines +74 to +75
public ResponseEntity<LectureTranscription> createLectureTranscription(@RequestBody LectureTranscriptionDTO transcriptionDTO, @PathVariable Long courseId,
@PathVariable Long lectureId) throws URISyntaxException {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation annotations to DTO parameters.

Add @Valid annotation to validate the DTO and consider adding validation constraints to the DTO fields.

-    public ResponseEntity<LectureTranscription> createLectureTranscription(@RequestBody LectureTranscriptionDTO transcriptionDTO, @PathVariable Long courseId,
+    public ResponseEntity<LectureTranscription> createLectureTranscription(@Valid @RequestBody LectureTranscriptionDTO transcriptionDTO, @PathVariable Long courseId,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public ResponseEntity<LectureTranscription> createLectureTranscription(@RequestBody LectureTranscriptionDTO transcriptionDTO, @PathVariable Long courseId,
@PathVariable Long lectureId) throws URISyntaxException {
public ResponseEntity<LectureTranscription> createLectureTranscription(@Valid @RequestBody LectureTranscriptionDTO transcriptionDTO, @PathVariable Long courseId,
@PathVariable Long lectureId) throws URISyntaxException {

Comment on lines +78 to +84
Set<Long> lectureUnitIds = transcriptionDTO.segments().stream().map(LectureTranscriptionSegmentDTO::lectureUnitId).collect(Collectors.toSet());
Set<LectureUnit> lectureUnits = lectureUnitRepository.findAllByIdIn(lectureUnitIds);

List<LectureTranscriptionSegment> segments = transcriptionDTO.segments().stream().map(segment -> {
LectureUnit lectureUnit = lectureUnits.stream().filter(lu -> lu.getId().equals(segment.lectureUnitId())).findFirst().orElseThrow();
return new LectureTranscriptionSegment(segment.startTime(), segment.endTime(), segment.text(), lectureUnit, segment.slideNumber());
}).toList();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null checks and improve error handling in stream operations.

The stream operations lack null checks and proper error handling:

  1. segments() could be null
  2. lectureUnit stream operation uses findFirst().orElseThrow() without a custom exception
-        Set<Long> lectureUnitIds = transcriptionDTO.segments().stream().map(LectureTranscriptionSegmentDTO::lectureUnitId).collect(Collectors.toSet());
+        Set<Long> lectureUnitIds = Optional.ofNullable(transcriptionDTO.segments())
+            .orElse(List.of())
+            .stream()
+            .map(LectureTranscriptionSegmentDTO::lectureUnitId)
+            .collect(Collectors.toSet());
         Set<LectureUnit> lectureUnits = lectureUnitRepository.findAllByIdIn(lectureUnitIds);

         List<LectureTranscriptionSegment> segments = transcriptionDTO.segments().stream().map(segment -> {
-            LectureUnit lectureUnit = lectureUnits.stream().filter(lu -> lu.getId().equals(segment.lectureUnitId())).findFirst().orElseThrow();
+            LectureUnit lectureUnit = lectureUnits.stream()
+                .filter(lu -> lu.getId().equals(segment.lectureUnitId()))
+                .findFirst()
+                .orElseThrow(() -> new EntityNotFoundException("Lecture unit not found with id: " + segment.lectureUnitId()));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Set<Long> lectureUnitIds = transcriptionDTO.segments().stream().map(LectureTranscriptionSegmentDTO::lectureUnitId).collect(Collectors.toSet());
Set<LectureUnit> lectureUnits = lectureUnitRepository.findAllByIdIn(lectureUnitIds);
List<LectureTranscriptionSegment> segments = transcriptionDTO.segments().stream().map(segment -> {
LectureUnit lectureUnit = lectureUnits.stream().filter(lu -> lu.getId().equals(segment.lectureUnitId())).findFirst().orElseThrow();
return new LectureTranscriptionSegment(segment.startTime(), segment.endTime(), segment.text(), lectureUnit, segment.slideNumber());
}).toList();
Set<Long> lectureUnitIds = Optional.ofNullable(transcriptionDTO.segments())
.orElse(List.of())
.stream()
.map(LectureTranscriptionSegmentDTO::lectureUnitId)
.collect(Collectors.toSet());
Set<LectureUnit> lectureUnits = lectureUnitRepository.findAllByIdIn(lectureUnitIds);
List<LectureTranscriptionSegment> segments = transcriptionDTO.segments().stream().map(segment -> {
LectureUnit lectureUnit = lectureUnits.stream()
.filter(lu -> lu.getId().equals(segment.lectureUnitId()))
.findFirst()
.orElseThrow(() -> new EntityNotFoundException("Lecture unit not found with id: " + segment.lectureUnitId()));
return new LectureTranscriptionSegment(segment.startTime(), segment.endTime(), segment.text(), lectureUnit, segment.slideNumber());
}).toList();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
client Pull requests that update TypeScript code. (Added Automatically!) core Pull requests that affect the corresponding module database Pull requests that update the database. (Added Automatically!). Require a CRITICAL deployment. iris Pull requests that affect the corresponding module lecture Pull requests that affect the corresponding module ready for review server Pull requests that update Java code. (Added Automatically!) tests
Projects
Status: Ready For Review
Status: In review
Development

Successfully merging this pull request may close these issues.

4 participants