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

Programming exercises: Allow to choose preliminary feedback model #10441

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

Conversation

dmytropolityka
Copy link
Contributor

@dmytropolityka dmytropolityka commented Mar 5, 2025

Please test only on TS3
!!! Contains database migrations !!!

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 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.
  • Following the theming guidelines, I specified colors only in the theming variable files and checked that the changes look consistent in both the light and the dark theme.
  • I added multiple integration tests (Jest) related to the features (with a high test coverage), while following the test guidelines.
  • I documented the TypeScript code using JSDoc style.
  • I added multiple screenshots/screencasts of my UI changes.
  • I translated all newly inserted strings into English and German.

Changes affecting Programming Exercises

  • High priority: I tested all changes and their related features with all corresponding user types on a test server configured with the integrated lifecycle setup (LocalVC and LocalCI).
  • I tested all changes and their related features with all corresponding user types on a test server configured with Gitlab and Jenkins.

Motivation and Context

Currently, Artemis allows only one module to be set for Athena Feedback Requests, be it for preliminary or graded feedback. This PR addresses the limitation and enables setting separate modules for each type of feedback.

Description

This PR introduces functionality that allows instructors to configure different Athena Feedback Request modules for preliminary feedback and graded feedback. Preliminary feedback can now be assigned a dedicated module without affecting the graded feedback settings.

Steps for Testing

Disclaimer:
Currently, only LLM modules support preliminary feedback. You can easily test this functionality with non-LLM modules to verify if the correct module is being used (non-LLM modules will not work).

  1. Deploy this branch to Test Server 3 (TS3).

As an instructor:
2. Navigate to the course settings.
3. Create a Programming, Text, or Modeling exercise.
4. Select a module for preliminary feedback (no due date required). For graded feedback, enable Feedback Suggestions, set a due date, and select a module(text or programming).
5. Save the changes.

As a student:
6. Open the created exercise.
7. Submit something.
8. Submit an AI feedback request.
9. Verify that the appropriate module is used based on the type of feedback.

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

Performance Tests

  • Test 1
  • Test 2

Screenshots

image
image

Summary by CodeRabbit

  • New Features

    • Introduced distinct preliminary feedback options alongside manual feedback requests for exercise assessments across programming, text, and modeling modules.
    • Updated user interface elements to clearly display and toggle feedback suggestions and requests, ensuring more intuitive assessment workflows.
  • Documentation

    • Enhanced tooltips and localized text labels to better describe the new feedback features for improved user guidance.

dmytropolityka and others added 28 commits December 3, 2024 11:28
…g-exercises/choose-preliminary-feedback-model
…oose-preliminary-feedback-model' into feature/programming-exercises/choose-preliminary-feedback-model
…g-exercises/choose-preliminary-feedback-model

# Conflicts:
#	src/main/webapp/app/exercises/modeling/manage/modeling-exercise.module.ts
#	src/main/webapp/app/exercises/programming/shared/lifecycle/programming-exercise-lifecycle.module.ts
#	src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts
#	src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.module.ts
#	src/main/webapp/app/overview/exercise-details/exercise-details-student-actions.component.html
#	src/main/webapp/i18n/de/exercise.json
#	src/test/javascript/spec/component/exercises/shared/feedback/feedback-suggestion-option.component.spec.ts
#	src/test/javascript/spec/component/modeling-exercise/modeling-exercise-update.component.spec.ts
#	src/test/javascript/spec/component/overview/exercise-details/exercise-details-student-actions.component.spec.ts
#	src/test/javascript/spec/component/overview/exercise-details/request-feedback-button/request-feedback-button.component.spec.ts
#	src/test/javascript/spec/component/programming-exercise/programming-exercise-lifecycle.component.spec.ts
#	src/test/javascript/spec/component/text-exercise/text-exercise-update.component.spec.ts
@github-actions github-actions bot added tests server Pull requests that update Java code. (Added Automatically!) labels Mar 5, 2025
@helios-aet helios-aet bot temporarily deployed to artemis-test3.artemis.cit.tum.de March 11, 2025 09:23 Inactive
@helios-aet helios-aet bot temporarily deployed to artemis-test3.artemis.cit.tum.de March 11, 2025 12:16 Inactive
Copy link
Contributor

@magaupp magaupp left a comment

Choose a reason for hiding this comment

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

Some code quality suggestions

@dmytropolityka dmytropolityka requested a review from magaupp March 11, 2025 14:14
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: 1

🔭 Outside diff range comments (1)
src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.html (1)

33-34: ⚠️ Potential issue

Remove extraneous closing brace

There appears to be an extra closing brace at the end of the file that doesn't match any opening brace. This is likely a syntax error.

}
33
}
34

-33
-}
-34
🧹 Nitpick comments (5)
src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (3)

56-59: Consider using more concise observable testing pattern.

You're subscribing to an observable within the test which makes the test more verbose. Since this is a test for a simple boolean value, you could use the firstValueFrom utility or testing utilities for more concise observable assertions.

-component.isAthenaEnabled$.subscribe((result) => {
-    expect(result).toBeTrue();
-});
+import { firstValueFrom } from 'rxjs';
+
+// Later in the test
+const isEnabled = await firstValueFrom(component.isAthenaEnabled$);
+expect(isEnabled).toBeTrue();

101-113: Avoid mutating test objects directly.

Instead of mutating the event object directly at line 109, create a new event object for the second test case. This makes the test more readable and isolates test scenarios better.

-event.target.checked = false;
-component.togglePreliminaryFeedback(event);
+const uncheckedEvent = { target: { checked: false } };
+component.togglePreliminaryFeedback(uncheckedEvent);

41-42: Consider using more explicit object construction for test data.

Using as Exercise type assertion with incomplete objects may hide potential type errors. Consider constructing a more complete test object for better test readability and maintainability.

-component.exercise = { type: ExerciseType.TEXT, dueDate: futureDueDate, preliminaryFeedbackModule: undefined } as Exercise;
+component.exercise = new Exercise(
+    undefined,             // id
+    undefined,             // title
+    ExerciseType.TEXT,     // type
+    undefined,             // categories
+    undefined,             // difficulty
+    { dueDate: futureDueDate }
+);
+component.exercise.preliminaryFeedbackModule = undefined;

Alternatively, if full object construction is too verbose, at least create a helper function that returns a properly typed object.

src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.html (1)

17-17: Add translation directive to the label for consistency

The label for the athenaModuleSelect dropdown is not using the translation directive unlike other text elements in the template. For consistency with the app's internationalization approach, consider adding jhiTranslate.

-                <label for="athenaModuleSelect">Athena Preliminary Feedback Module</label>
+                <label for="athenaModuleSelect" jhiTranslate="artemisApp.exercise.athenaPreliminaryFeedbackModule"></label>

You'll need to add the corresponding translation key to the i18n files.

src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts (1)

75-82: Add type for event parameter

The event parameter in the togglePreliminaryFeedback method should have a more specific type than any for better type safety.

- togglePreliminaryFeedback(event: any) {
+ togglePreliminaryFeedback(event: Event) {
    this.showDropdownList = event.target.checked;
    if (event.target.checked) {
        this.exercise().preliminaryFeedbackModule = this.availableAthenaModules.first();
    } else {
        this.exercise().preliminaryFeedbackModule = undefined;
    }
}

You'll need to add a type assertion for event.target as HTMLInputElement to access the checked property.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between bf20e72 and 881fac7.

📒 Files selected for processing (19)
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts (2 hunks)
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.html (1 hunks)
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts (1 hunks)
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts (1 hunks)
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts (3 hunks)
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (1 hunks)
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts (1 hunks)
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts (1 hunks)
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (2 hunks)
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.html (1 hunks)
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts (1 hunks)
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts (2 hunks)
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (0 hunks)
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts (1 hunks)
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts (2 hunks)
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts (0 hunks)
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.html (1 hunks)
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts (5 hunks)
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts
🚧 Files skipped from review as they are similar to previous changes (13)
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.html
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts
  • src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.html
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts
  • src/main/webapp/app/exercises/shared/feedback-suggestion/exercise-feedback-suggestion-options.component.ts
🧰 Additional context used
📓 Path-based instructions (3)
`src/main/webapp/**/*.ts`: angular_style:https://angular.io/...

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/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts
`src/test/javascript/spec/**/*.ts`: jest: true; mock: NgMock...

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/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts
`src/main/webapp/**/*.html`: @if and @for are new and valid ...

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/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.html
🧠 Learnings (1)
src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts (3)
Learnt from: dmytropolityka
PR: ls1intum/Artemis#10441
File: src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts:76-83
Timestamp: 2025-03-05T22:14:15.408Z
Learning: In the Artemis client code, the Array prototype is extended with `first()`, `last()`, and `shuffle()` methods (defined in src/main/webapp/app/shared/util/array.extension.ts). The `first()` method returns the first element of an array or undefined if the array is empty, while `last()` returns the last element or undefined if empty. These extensions allow for calls like `array.first()` and `array.last()` instead of using standard array indexing like `array[0]` or `array[array.length-1]`.
Learnt from: dmytropolityka
PR: ls1intum/Artemis#10441
File: src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts:76-83
Timestamp: 2025-03-05T22:14:15.408Z
Learning: In the Artemis client code, the Array prototype is extended with `first()` and `last()` methods (defined in src/main/webapp/app/shared/util/array.extension.ts), allowing for calls like `array.first()` and `array.last()` instead of using standard array indexing like `array[0]` or `array[array.length-1]`.
Learnt from: dmytropolityka
PR: ls1intum/Artemis#10441
File: src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts:76-83
Timestamp: 2025-03-05T22:14:15.408Z
Learning: In the Artemis client code, the Array prototype is extended with `first()` and `last()` methods, allowing for calls like `array.first()` and `array.last()` instead of using standard array indexing like `array[0]` or `array[array.length-1]`.
🔇 Additional comments (10)
src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (5)

38-47: Good use of Jest spies and asynchronous testing.

The test correctly uses Jest spying to mock service responses and properly awaits async operations before assertions.


22-24: Effective use of MockProvider for dependency injection.

Good job using MockProvider from ng-mocks to provide test doubles for the component's dependencies.


1-10: Clean imports with appropriate dependencies.

The imports are well-organized and only include what's necessary for the tests.


62-71: Good test for conditional disabling of UI controls.

This test effectively verifies that input controls are disabled under appropriate conditions (assessment type and read-only state).


96-113: Comprehensive test for toggle behavior.

The test properly verifies that toggling the preliminary feedback checkbox sets the module and controls the dropdown visibility.

src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.html (3)

25-27: LGTM on the new @for syntax

The new @for syntax is correctly implemented, replacing the older *ngFor directive as per the coding guidelines.


1-1: LGTM on the new @if syntax

The new @if syntax is correctly implemented, replacing the older *ngIf directive as per the coding guidelines.


15-15: LGTM on the new @if syntax

The nested conditional for showing the dropdown list correctly uses the new @if syntax.

src/main/webapp/app/exercises/shared/preliminary-feedback/exercise-preliminary-feedback-options.component.ts (2)

19-21: LGTM on using input signals

You've correctly implemented the new Angular Signal-based input API (input()) as recommended in the previous review comments.


78-78: Correctly using array extensions

The use of the first() method on arrays is consistent with the Artemis client code conventions, as noted in the previous review thread.

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: 0

🧹 Nitpick comments (4)
src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (4)

46-46: Use toBeTrue() instead of toBeTruthy()

According to the coding guidelines for tests, boolean assertions should use the more specific toBeTrue() or toBeFalse() rather than toBeTruthy().

-        expect(component.modulesAvailable).toBeTruthy();
+        expect(component.modulesAvailable).toBeTrue();

66-66: Use toBeTrue() instead of toBeTruthy()

For boolean assertions, use toBeTrue() as specified in the coding guidelines for better expectation specificity.

-        expect(result).toBeTruthy();
+        expect(result).toBeTrue();

70-70: Use toBeTrue() instead of toBeTruthy()

For consistent test assertions, replace toBeTruthy() with toBeTrue() as per your test guidelines.

-        expect(result).toBeTruthy();
+        expect(result).toBeTrue();

77-77: Use toBeTrue() instead of toBeTruthy()

Replace toBeTruthy() with toBeTrue() for boolean assertions to follow the coding guidelines.

-        expect(result).toBeTruthy();
+        expect(result).toBeTrue();
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 881fac7 and f0c2436.

📒 Files selected for processing (5)
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (1 hunks)
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (0 hunks)
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (4 hunks)
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts
  • src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts
🧰 Additional context used
📓 Path-based instructions (1)
`src/test/javascript/spec/**/*.ts`: jest: true; mock: NgMock...

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/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: Call Build Workflow / Build .war artifact
  • GitHub Check: Call Build Workflow / Build and Push Docker Image
  • GitHub Check: server-style
  • GitHub Check: client-tests-selected
  • GitHub Check: client-tests
  • GitHub Check: server-tests
  • GitHub Check: Analyse
🔇 Additional comments (1)
src/test/javascript/spec/component/exercises/shared/feedback/preliminary-feedback-options.component.spec.ts (1)

1-114: Test structure and coverage looks good

The test file is well-structured with comprehensive coverage of the component's functionality. It correctly uses MockProvider from ng-mocks and follows most of the test guidelines with appropriate assertions for different data types.

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 11, 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.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 10

🔭 Outside diff range comments (7)
src/main/java/de/tum/cit/aet/artemis/programming/repository/BuildJobRepository.java (1)

123-126: 💡 Verification agent

🧩 Analysis chain

Fix file structure issue - misplaced code.

There appears to be a structural issue in the file. Lines 123-126 seem to be misplaced and likely belong to a different method. The file doesn't compile correctly with the current structure.

The lines:

}
            GROUP BY b.exerciseId
            """)
    BuildJobStatisticsDTO findBuildJobStatisticsByExerciseId(@Param("exerciseId") Long exerciseId);

appear to be part of a different query method but are incorrectly placed after the closing brace of the repository interface and before additional methods. Please review the file structure and correct the placement of these lines.


🏁 Script executed:

#!/bin/bash
# Description: Verify file structure and locate the correct context for this method

# Look for findBuildJobStatisticsByExerciseId method in the repository
rg "findBuildJobStatisticsByExerciseId" -A 2 -B 2 --no-heading

Length of output: 1464


Critical Structural Issue: Misplaced Query Parts in BuildJobRepository

It appears that the query for the method findBuildJobStatisticsByExerciseId in src/main/java/de/tum/cit/aet/artemis/programming/repository/BuildJobRepository.java is broken due to misplaced lines. In particular, the lines

GROUP BY b.exerciseId
""")
BuildJobStatisticsDTO findBuildJobStatisticsByExerciseId(@Param("exerciseId") Long exerciseId);

seem to be detached from their intended @Query annotation block. It looks like an extraneous closing brace (}) was erroneously inserted before these lines, which disrupts the formation of a complete query string and likely causes compilation errors.

Actionable items:

  • Review the location of the stray closing brace (likely before the query continuation) to ensure that the entire SQL query (including the GROUP BY clause and the closing """) is part of the proper @Query annotation.
  • Adjust the file structure so that findBuildJobStatisticsByExerciseId is correctly annotated with its complete query string.
package.json (2)

201-203: ⚠️ Potential issue

Duplicate Script Key: compile:ts:tests
The script key "compile:ts:tests" is defined twice. Even though both entries have the same value, JSON keys should be unique to avoid unintended behavior. Please remove the duplicate entry.


218-219: ⚠️ Potential issue

Duplicate Script Key: testw8
The script "testw8" appears twice in the scripts section. Remove the duplicate to prevent potential confusion or override issues.

src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseBuildConfigService.java (1)

124-136: ⚠️ Potential issue

Redundant duplicate method
Lines 124-136 re-implement the exact parseDockerFlags functionality from lines 70-90. Having two methods with identical logic poses a maintainability risk.

Remove this duplicate to maintain DRY principles and avoid confusion regarding which method should be used.

src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseService.java (1)

103-104: ⚠️ Potential issue

Potential merge conflict residue
PACKAGE_NAME_REGEX_FOR_JAVA_KOTLIN is declared here, but reappears again on lines 110-111. This is likely leftover code from a merge, producing two definitions of the same constant.

Remove one definition to avoid repeated constants and ensure clarity.

src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobExecutionService.java (2)

419-434: 🛠️ Refactor suggestion

Partially duplicated logic for results parsing
These lines resemble the block around 405-416, leading to potential confusion or mismatch in handling test results. Consolidate if possible.

Refactor to a single code path or method that handles test result files consistently to minimize duplication.


490-498: ⚠️ Potential issue

Confirm single source for SCA parsing
Lines 490-498 replicate the logic from lines 470-473. Consolidate the method to avoid confusion or drifting logic.

Eliminate the duplicate method and use a single version to ensure DRY principles.

🧹 Nitpick comments (19)
src/main/resources/templates/aeolus/javascript/default_static.sh (4)

1-3: Shell Script Initialization: Enhance Robustness
The shebang and set -e usage are correct to catch errors. Consider adding set -o pipefail to ensure that errors in piped commands are also captured.


9-12: static_code_analysis Function: Linting Exit Code Handling
Using npm run lint:ci || [ $? -eq 1 ] permits an exit code of 1 to pass without failing the script. For clarity and maintainability, consider explicitly capturing the exit code or adding a comment explaining the rationale behind allowing exit code 1.


26-30: Subshell Invocation: Consider Improved Quoting
The subshell invocations (e.g., bash -c "source ${_script_name} aeolus_sourcing; install_dependencies") work as intended; however, if the script path contains spaces, this could lead to issues. It is recommended to quote ${_script_name} within the command as follows:

-  bash -c "source ${_script_name} aeolus_sourcing; install_dependencies"
+  bash -c "source \"${_script_name}\" aeolus_sourcing; install_dependencies"

This change should be applied similarly to lines 28 and 30.


34-34: Trailing Line: Consistency Check
There is an extra line (line 34) at the end of the file. Please verify if this blank line is intentional; if not, consider removing it to maintain consistency with the rest of the file.

src/test/javascript/spec/component/standardized-competencies/standardized-competency.service.spec.ts (4)

9-31: Consider using NgMocks for better test isolation.

The test setup correctly configures the testing module with HTTP providers, but according to the project coding guidelines, NgMocks should be used for mocking. Consider refactoring to use NgMocks for better component isolation.

import { HttpResponse, provideHttpClient } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { TestBed, fakeAsync, tick } from '@angular/core/testing';
import { KnowledgeAreaDTO, Source, StandardizedCompetency } from 'app/entities/competency/standardized-competency.model';
+import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';
import { take } from 'rxjs';
import { CompetencyTaxonomy } from 'app/entities/competency.model';
import { StandardizedCompetencyService } from 'app/shared/standardized-competencies/standardized-competency.service';

describe('StandardizedCompetencyService', () => {
    let standardizedCompetencyService: StandardizedCompetencyService;
    let httpTestingController: HttpTestingController;
    let defaultStandardizedCompetency: StandardizedCompetency;

    beforeEach(() => {
-        TestBed.configureTestingModule({
-            providers: [provideHttpClient(), provideHttpClientTesting()],
-        });
-
-        standardizedCompetencyService = TestBed.inject(StandardizedCompetencyService);
-        httpTestingController = TestBed.inject(HttpTestingController);
+        return MockBuilder(StandardizedCompetencyService)
+            .provide(provideHttpClient())
+            .provide(provideHttpClientTesting());
+    });
+
+    beforeEach(() => {
+        standardizedCompetencyService = ngMocks.findInstance(StandardizedCompetencyService);
+        httpTestingController = ngMocks.findInstance(HttpTestingController);

        defaultStandardizedCompetency = {
            id: 1,
            title: 'Standardized Competency1',
            taxonomy: CompetencyTaxonomy.ANALYZE,
        };
    });

33-48: Use more specific assertions for improved test clarity.

According to the project coding guidelines, use more specific assertions for better test clarity. Instead of .toEqual(), consider using .toContainEntries() for the object comparison.

it('should get competency', fakeAsync(() => {
    let actualCompetency = new HttpResponse<StandardizedCompetency>();
    const expectedCompetency = defaultStandardizedCompetency;
    const returnedFromService: StandardizedCompetency = { ...expectedCompetency };

    standardizedCompetencyService
        .getStandardizedCompetency(1)
        .pipe(take(1))
        .subscribe((resp) => (actualCompetency = resp));

    const req = httpTestingController.expectOne({ method: 'GET' });
    req.flush(returnedFromService);
    tick();

-    expect(actualCompetency.body).toEqual(expectedCompetency);
+    expect(actualCompetency.body).toContainEntries(Object.entries(expectedCompetency));
}));

50-86: Update assertions for better specificity and test isolation.

The test for getAllForTreeView should use more specific assertions as per the project guidelines. Also, consider adding additional assertions to verify the structure of the returned data.

it('should get all for tree view', fakeAsync(() => {
    let actualResult = new HttpResponse<KnowledgeAreaDTO[]>();
    const expectedResult: KnowledgeAreaDTO[] = [
        {
            id: 1,
            title: 'KnowledgeAreaDTO1',
            children: [
                {
                    id: 11,
                    title: 'KnowledgeAreaDTO1.1',
                },
            ],
            competencies: [
                {
                    id: 1,
                    title: 'Standardized Competency',
                },
            ],
        },
        {
            id: 2,
            title: 'KnowledgeAreaDTO2',
        },
    ];
    const returnedFromService: KnowledgeAreaDTO[] = [...expectedResult];

    standardizedCompetencyService
        .getAllForTreeView()
        .pipe(take(1))
        .subscribe((resp) => (actualResult = resp));

    const req = httpTestingController.expectOne({ method: 'GET' });
    req.flush(returnedFromService);
    tick();

-    expect(actualResult.body).toEqual(expectedResult);
+    expect(actualResult.body).toContainEntries(Object.entries(expectedResult));
+    expect(actualResult.body?.[0].children).toBeDefined();
+    expect(actualResult.body?.[0].competencies).toBeDefined();
}));

88-106: Use more specific assertions for the sources test.

Following the project guidelines for assertion specificity, update the assertion in the getSources test.

it('should get sources', fakeAsync(() => {
    let actualSources = new HttpResponse<Source[]>();

    const expectedSources: Source[] = [
        { id: 1, title: 'source1' },
        { id: 2, title: 'source2' },
    ];
    const returnedFromService = [...expectedSources];

    standardizedCompetencyService
        .getSources()
        .pipe(take(1))
        .subscribe((resp) => (actualSources = resp));

    const req = httpTestingController.expectOne({ method: 'GET' });
    req.flush(returnedFromService);
    tick();

-    expect(actualSources.body).toEqual(expectedSources);
+    expect(actualSources.body).toContainEntries(Object.entries(expectedSources));
+    expect(actualSources.body?.length).toBe(2);
}));
src/main/java/de/tum/cit/aet/artemis/programming/repository/BuildJobRepository.java (2)

108-115: Method implementation looks good but consider using enum constant.

The new query method fetchSuccessfulBuildJobsByExerciseIdWithLimit follows good repository patterns with appropriate parameter annotations and SQL formatting. However, the query uses a string literal 'SUCCESSFUL' for the build status rather than referencing the BuildStatus enum constant. This could potentially become brittle if enum values change in the future.

Consider modifying the query to use a parameter for the build status:

-            WHERE b.exerciseId = :exerciseId AND b.buildStatus = 'SUCCESSFUL'
+            WHERE b.exerciseId = :exerciseId AND b.buildStatus = :buildStatus

And update the method signature:

-    List<BuildJob> fetchSuccessfulBuildJobsByExerciseIdWithLimit(@Param("exerciseId") Long exerciseId, @Param("limit") int limit);
+    List<BuildJob> fetchSuccessfulBuildJobsByExerciseIdWithLimit(@Param("exerciseId") Long exerciseId, @Param("buildStatus") BuildStatus buildStatus, @Param("limit") int limit);

Then call with BuildStatus.SUCCESSFUL to maintain type safety.


117-122: Method implementation looks good but consider using enum constant.

Similar to the previous method, this query also uses a string literal 'SUCCESSFUL' for the build status instead of the enum constant. The method otherwise follows repository best practices with proper parameter annotations and SQL formatting.

Consider parameterizing the build status:

-            WHERE b.exerciseId = :exerciseId AND b.buildStatus = 'SUCCESSFUL'
+            WHERE b.exerciseId = :exerciseId AND b.buildStatus = :buildStatus

And update the method signature:

-    long fetchSuccessfulBuildJobCountByExerciseId(@Param("exerciseId") Long exerciseId);
+    long fetchSuccessfulBuildJobCountByExerciseId(@Param("exerciseId") Long exerciseId, @Param("buildStatus") BuildStatus buildStatus);
src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts (2)

15-23: Update JSDoc comments to reflect parameter removal.

The JSDoc comments don't reflect the removal of the coverage parameter that was previously in the method signature. Documentation should be updated to match the actual method signature.

 /**
  * Fetches the aeolus template file for the given programming language
  * @param {ProgrammingLanguage} language
  * @param {ProjectType} projectType (if available)
  * @param staticAnalysis (if available) whether static code analysis should be enabled
  * @param sequentialRuns (if available) whether sequential test runs should be enabled
- * @param coverage (if available) whether test coverage should be enabled
  * @returns WindFile or undefined if no template is available
  */

31-39: Update JSDoc comments to reflect parameter removal.

Similarly, these JSDoc comments need to be updated to remove the mention of the coverage parameter that was removed from the method signature.

 /**
  * Fetches the aeolus template file for the given programming language
  * @param {ProgrammingLanguage} language
  * @param {ProjectType} projectType (if available)
  * @param staticAnalysis (if available) whether static code analysis should be enabled
  * @param sequentialRuns (if available) whether sequential test runs should be enabled
- * @param coverage (if available) whether test coverage should be enabled
  * @returns json test file
  */
src/main/java/de/tum/cit/aet/artemis/buildagent/dto/DockerFlagsDTO.java (1)

5-5:

❓ Verification inconclusive

Consider using Integer instead of primitive int for optional parameters.

The new parameters (cpuCount, memory, memorySwap) use primitive int types, which means they can't be null. This might cause issues with backward compatibility if these values are optional in some scenarios.

-public record DockerFlagsDTO(String network, Map<String, String> env, int cpuCount, int memory, int memorySwap) {
+public record DockerFlagsDTO(String network, Map<String, String> env, Integer cpuCount, Integer memory, Integer memorySwap) {

This change would allow these fields to be null when not specified, providing better backward compatibility.


🏁 Script executed:

#!/bin/bash
# Find existing usages of the DockerFlagsDTO to verify backward compatibility concerns
rg -A 3 "new DockerFlagsDTO" --type java

Length of output: 42


🏁 Script executed:

#!/bin/bash
# Search for all references to DockerFlagsDTO constructor usage
rg "DockerFlagsDTO\\s*\\(" --type java

Length of output: 224


Optional Parameter Compatibility Concern

The current implementation declares the fields as primitive int, which means there is no way to represent null for cases where these parameters might not be specified. Our search for usages of DockerFlagsDTO did not reveal any external references that provide further context on how these fields are used. This leaves us with two possibilities:

  • If these parameters are always explicitly provided (i.e., they're effectively required), then using primitives may be acceptable.
  • If, however, there's an expectation in some scenarios for these fields to be optional (and thus potentially null), then the fields should be changed to use Integer to better support backward compatibility.

Actionable recommendation:

  • Review the intended usage of cpuCount, memory, and memorySwap.
    If they are meant to be optional, update the record definition as follows:

    -public record DockerFlagsDTO(String network, Map<String, String> env, int cpuCount, int memory, int memorySwap) {
    +public record DockerFlagsDTO(String network, Map<String, String> env, Integer cpuCount, Integer memory, Integer memorySwap) {

Please verify this change within the broader context of the codebase and confirm that any serialization or downstream processing correctly handles null values.

src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIInfoContributor.java (1)

60-73: Improve memory string parsing robustness.

The memory parsing implementation makes some assumptions about the format of memory strings (e.g., ending with quotes). This could lead to unexpected behavior with differently formatted inputs.

 private static long parseMemoryStringToMB(String memoryString) {
-    if (memoryString.endsWith("g\"")) {
-        return Long.parseLong(memoryString.replaceAll("[^0-9]", "")) * 1024L;
-    }
-    else if (memoryString.endsWith("m\"")) {
-        return Long.parseLong(memoryString.replaceAll("[^0-9]", ""));
-    }
-    else if (memoryString.endsWith("k\"")) {
-        return Long.parseLong(memoryString.replaceAll("[^0-9]", "")) / 1024L;
-    }
-    else {
-        return Long.parseLong(memoryString);
+    String cleanString = memoryString.replaceAll("\"", "").trim();
+    if (cleanString.endsWith("g") || cleanString.endsWith("G")) {
+        return Long.parseLong(cleanString.replaceAll("[^0-9]", "")) * 1024L;
+    }
+    else if (cleanString.endsWith("m") || cleanString.endsWith("M")) {
+        return Long.parseLong(cleanString.replaceAll("[^0-9]", ""));
+    }
+    else if (cleanString.endsWith("k") || cleanString.endsWith("K")) {
+        return Long.parseLong(cleanString.replaceAll("[^0-9]", "")) / 1024L;
+    }
+    else {
+        try {
+            return Long.parseLong(cleanString);
+        } catch (NumberFormatException e) {
+            // Log error or handle the exception
+            return 0;
+        }
     }
 }
src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobExecutionService.java (2)

303-304: Network isolation during script run
Invoking runScriptInContainer with isNetworkDisabled is consistent, though ensure your container itself is configured accordingly (e.g., Docker run param or container-level setting).


311-314: Repeated log message
The log messages for “Collecting test results” seem duplicated across these ranges. This might confuse logs or result in extra clutter.

Consider centralizing such messages or merging them to maintain a succinct log flow.

Also applies to: 320-323

src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-build-configuration/programming-exercise-build-configuration.component.ts (3)

125-128: Type safety concern for CPU count.

event.target.value is likely a string, which could cause type mismatch or unintended comparisons. Convert it to a number (e.g., parseInt) before assignment to cpuCount.

-onCpuCountChange(event: any) {
-    this.cpuCount = event.target.value;
+onCpuCountChange(event: any) {
+    this.cpuCount = parseInt(event.target.value, 10);
    this.parseDockerFlagsToString();
}

130-133: Type safety concern for memory.

Same reasoning as CPU count. Convert event.target.value to a number to prevent type-related issues.

-onMemoryChange(event: any) {
-    this.memory = event.target.value;
+onMemoryChange(event: any) {
+    this.memory = parseInt(event.target.value, 10);
    this.parseDockerFlagsToString();
}

135-138: Type safety concern for memory swap.

Likewise, parse the input as a number to ensure consistent arithmetic operations.

-onMemorySwapChange(event: any) {
-    this.memorySwap = event.target.value;
+onMemorySwapChange(event: any) {
+    this.memorySwap = parseInt(event.target.value, 10);
    this.parseDockerFlagsToString();
}
🛑 Comments failed to post (10)
supporting_scripts/course-scripts/quick-course-setup/create_course.py (2)

35-35: ⚠️ Potential issue

API endpoint structure changed.

The URL for course creation has been updated to include a /core prefix. This change aligns with the PR objective of enhancing the Artemis platform's feedback system and reflects an API reorganization mentioned in the summary.

This change might break backward compatibility with external scripts or clients that rely on the old URL structure. Ensure that:

  1. All client code has been updated to use the new URL pattern
  2. API documentation is updated to reflect this change
  3. Consider if a temporary redirect from the old endpoint to the new one is needed

21-21: ⚠️ Potential issue

Configuration source changed for SPECIAL_CHARACTERS_REGEX.

The regex configuration has been moved from the 'Settings' section to the 'CourseSettings' section, which is a good organizational improvement that keeps course-related settings together. However, this change might break existing configuration files that don't have this field in the 'CourseSettings' section.

Ensure all existing configuration files are updated accordingly, or consider adding a fallback mechanism:

-SPECIAL_CHARACTERS_REGEX: str = config.get('CourseSettings', 'special_character_regex')
+# Try CourseSettings first, fall back to Settings for backward compatibility
+SPECIAL_CHARACTERS_REGEX: str = config.get('CourseSettings', 'special_character_regex') if config.has_option('CourseSettings', 'special_character_regex') else config.get('Settings', 'special_character_regex')
📝 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.

# Try CourseSettings first, fall back to Settings for backward compatibility
SPECIAL_CHARACTERS_REGEX: str = config.get('CourseSettings', 'special_character_regex') if config.has_option('CourseSettings', 'special_character_regex') else config.get('Settings', 'special_character_regex')
src/main/java/de/tum/cit/aet/artemis/atlas/web/StandardizedCompetencyResource.java (1)

34-34: 💡 Verification agent

🧩 Analysis chain

Request mapping updated with correct prefix.

The request mapping has been properly updated to include the "atlas" segment, which aligns with the profile change. This ensures a consistent API structure.

Note that the Javadoc comments on lines 55, 71, and 86 still reference the old API paths and should be updated to match the new paths.


🏁 Script executed:

#!/bin/bash
# Check if there are any client references to the old API path that might break with this change
rg -i "api/standardized-competencies/" --type=ts --type=java --glob=!**/StandardizedCompetencyResource.java

Length of output: 602


Action Required: Update Documentation and Client References to New API Paths

  • The request mapping in StandardizedCompetencyResource.java has been correctly updated to include the "atlas" prefix.
  • However, the Javadoc comments on lines 55, 71, and 86 in the same file still reference the old API paths.
  • Additionally, the search revealed that AdminStandardizedCompetencyResource.java contains active references to the outdated endpoint (/api/standardized-competencies/), which may lead to runtime issues.

Please update the Javadoc comments and the URI constructors in AdminStandardizedCompetencyResource.java to reflect the new API structure (including the "atlas" segment) to ensure consistency across the codebase.

src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCIInfoContributor.java (1)

45-56: 🛠️ Refactor suggestion

Add validation for Docker flags array length.

The loop assumes defaultDockerFlags has an even number of elements (flags and values), but there's no validation to ensure this is the case. A malformed configuration could cause an IndexOutOfBoundsException.

 List<String> defaultDockerFlags = programmingLanguageConfiguration.getDefaultDockerFlags();
 
+if (defaultDockerFlags.size() % 2 != 0) {
+    // Log warning or handle the error
+    return;
+}
+
 for (int i = 0; i < defaultDockerFlags.size(); i += 2) {
     String flag = defaultDockerFlags.get(i);
     String value = defaultDockerFlags.get(i + 1);
📝 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.

        List<String> defaultDockerFlags = programmingLanguageConfiguration.getDefaultDockerFlags();
        
        if (defaultDockerFlags.size() % 2 != 0) {
            // Log warning or handle the error
            return;
        }
        
        for (int i = 0; i < defaultDockerFlags.size(); i += 2) {
            String flag = defaultDockerFlags.get(i);
            String value = defaultDockerFlags.get(i + 1);
    
            switch (flag) {
                case "--cpus" -> builder.withDetail(Constants.DOCKER_FLAG_CPUS, Long.parseLong(value.replaceAll("[^0-9]", "")));
                case "--memory" -> builder.withDetail(Constants.DOCKER_FLAG_MEMORY_MB, parseMemoryStringToMB(value));
                case "--memory-swap" -> builder.withDetail(Constants.DOCKER_FLAG_MEMORY_SWAP_MB, parseMemoryStringToMB(value));
            }
        }
src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseBuildConfigService.java (1)

70-90: 🛠️ Refactor suggestion

Duplicate parseDockerFlags method implementation
The parseDockerFlags method appears again near lines 124-136, creating a duplicate definition. This duplication is prone to future inconsistencies and bloats the code.

Refactor the file to remove one of the duplicated methods, merge any missing logic, and ensure all references call a single source of truth.

src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingExerciseService.java (1)

110-111: 🛠️ Refactor suggestion

Duplicate PACKAGE_NAME_REGEX_FOR_JAVA_KOTLIN
The constant is declared a second time, duplicating the one defined on lines 103-104.

Eliminate the second occurrence so the code remains coherent and DRY.

src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobExecutionService.java (2)

439-442: ⚠️ Potential issue

Inconsistent test file extension checks
Here, .json is not included, yet lines 460-461 do consider .json. This leads to contradictory acceptance rules. Please unify the file extension logic.

Ensure .json logic is consistent across the entire file to avoid mistakes in test result detection.


467-468: 🛠️ Refactor suggestion

Duplicate processStaticCodeAnalysisReportFile
A second definition near lines 490-498 also processes static code analysis. Duplicate methods risk divergence over time.

Remove the duplication and unify the logic in one location.

Also applies to: 470-473

src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-build-configuration/programming-exercise-build-configuration.component.ts (1)

83-91: 🛠️ Refactor suggestion

Potential zero-value handling issue.

Using if (!this.cpuCount) { ... } overrides valid zero values (e.g. 0) with defaults. If a user intends to set cpuCount = 0, it will be replaced by profileInfo.defaultContainerCpuCount. Consider explicitly checking for undefined or null instead to avoid ignoring zero values.

-if (!this.cpuCount) {
+if (this.cpuCount == null) {
    this.cpuCount = profileInfo.defaultContainerCpuCount;
}
📝 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.

                if (this.cpuCount == null) {
                    this.cpuCount = profileInfo.defaultContainerCpuCount;
                }
                if (!this.memory) {
                    this.memory = profileInfo.defaultContainerMemoryLimitInMB;
                }
                if (!this.memorySwap) {
                    this.memorySwap = profileInfo.defaultContainerMemorySwapLimitInMB;
                }
build.gradle (1)

309-309: ⚠️ Potential issue

Duplicate library references with different versions.

The file references com.nimbusds:nimbus-jose-jwt:9.48 (line 309) and also com.nimbusds:nimbus-jose-jwt:10.0.2 (line 326). This can create version conflicts. Consider unifying to one version.

-implementation "com.nimbusds:nimbus-jose-jwt:9.48"
+// Remove or align this to match the other version

Also applies to: 326-326

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: 0

🧹 Nitpick comments (4)
src/test/javascript/spec/helpers/mocks/service/mock-profile.service.ts (1)

5-8: MockProfileService now returns a default ProfileInfo instead of undefined

The getProfileInfo method has been updated to return a BehaviorSubject initialized with a concrete object { activeProfiles: [] } instead of undefined. This change ensures that components that consume this service won't have to handle undefined values, aligning with the PR objectives of enhancing the feedback system.

However, the type assertion as unknown as ProfileInfo suggests that the returned object doesn't fully satisfy the ProfileInfo interface. Consider creating a more complete mock object that properly implements the interface.

-    getProfileInfo = () =>
-        new BehaviorSubject<ProfileInfo | undefined>({
-            activeProfiles: [],
-        } as unknown as ProfileInfo);
+    getProfileInfo = () =>
+        new BehaviorSubject<ProfileInfo>({
+            activeProfiles: [],
+            ribbonEnv: '',
+            inProduction: false,
+            version: ''
+        });
src/main/webapp/app/shared/user-settings/science-settings/science-settings.service.ts (3)

23-29: Constructor subscription is functionally correct
Subscribing in a service constructor to set up profile-dependent logic is reasonable for continuous service availability; however, confirm if this subscription completes once and doesn't need explicit teardown.


56-60: Consider consolidating ProfileService checks
You repeat the profile check here and in the constructor. Extracting this logic could reduce duplication and improve maintainability.

-refreshScienceSettings(): void {
-    this.profileService.getProfileInfo().subscribe((profileInfo) => {
-        if (!profileInfo.activeProfiles.includes(PROFILE_ATLAS)) {
-            return;
-        }
-        ...
-    });
+private isAtlasActive(profileInfo: ProfileInfo): boolean {
+    return profileInfo.activeProfiles.includes(PROFILE_ATLAS);
+}
+
+refreshScienceSettings(): void {
+    this.profileService.getProfileInfo().subscribe((profileInfo) => {
+        if (!this.isAtlasActive(profileInfo)) {
+            return;
+        }
+        ...
+    });
}

61-71: Include an error handling path in the subscription
At present, only the next callback is specified. Consider adding an error callback for better fault tolerance and debugging. This can help track potential backend failures.

this.userSettingsService.loadSettings(UserSettingsCategory.SCIENCE_SETTINGS).subscribe({
    next: (res: HttpResponse<Setting[]>) => { ... },
+   error: (err) => {
+       console.error('Failed to load science settings', err);
+   },
});
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3765a78 and 59eb8d5.

📒 Files selected for processing (15)
  • src/main/webapp/app/shared/competency-selection/competency-selection.component.ts (4 hunks)
  • src/main/webapp/app/shared/user-settings/science-settings/science-settings.service.ts (2 hunks)
  • src/test/javascript/spec/component/competencies/edit-competency.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/lecture-unit/attachment-unit/create-attachment-unit.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/lecture-unit/attachment-unit/edit-attachment-unit.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/lecture-unit/online-unit/create-online-unit.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/lecture-unit/online-unit/edit-online-unit.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/lecture-unit/text-unit/create-text-unit.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/lecture-unit/text-unit/edit-text-unit.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/lecture-unit/video-unit/create-video-unit.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/lecture-unit/video-unit/edit-video-unit.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-problem.component.spec.ts (2 hunks)
  • src/test/javascript/spec/component/shared/competency-selection.component.spec.ts (4 hunks)
  • src/test/javascript/spec/component/shared/user-settings/science-settings.service.spec.ts (2 hunks)
  • src/test/javascript/spec/helpers/mocks/service/mock-profile.service.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
`src/test/javascript/spec/**/*.ts`: jest: true; mock: NgMock...

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/javascript/spec/component/lecture-unit/attachment-unit/create-attachment-unit.component.spec.ts
  • src/test/javascript/spec/component/competencies/edit-competency.component.spec.ts
  • src/test/javascript/spec/component/lecture-unit/attachment-unit/edit-attachment-unit.component.spec.ts
  • src/test/javascript/spec/component/lecture-unit/video-unit/create-video-unit.component.spec.ts
  • src/test/javascript/spec/helpers/mocks/service/mock-profile.service.ts
  • src/test/javascript/spec/component/shared/user-settings/science-settings.service.spec.ts
  • src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-problem.component.spec.ts
  • src/test/javascript/spec/component/lecture-unit/online-unit/create-online-unit.component.spec.ts
  • src/test/javascript/spec/component/lecture-unit/online-unit/edit-online-unit.component.spec.ts
  • src/test/javascript/spec/component/lecture-unit/text-unit/create-text-unit.component.spec.ts
  • src/test/javascript/spec/component/lecture-unit/video-unit/edit-video-unit.component.spec.ts
  • src/test/javascript/spec/component/shared/competency-selection.component.spec.ts
  • src/test/javascript/spec/component/lecture-unit/text-unit/edit-text-unit.component.spec.ts
`src/main/webapp/**/*.ts`: angular_style:https://angular.io/...

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/shared/user-settings/science-settings/science-settings.service.ts
  • src/main/webapp/app/shared/competency-selection/competency-selection.component.ts
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: Call Build Workflow / Build and Push Docker Image
  • GitHub Check: Call Build Workflow / Build .war artifact
  • GitHub Check: client-tests-selected
  • GitHub Check: client-tests
  • GitHub Check: server-tests
  • GitHub Check: server-style
  • GitHub Check: Analyse
🔇 Additional comments (25)
src/test/javascript/spec/component/competencies/edit-competency.component.spec.ts (1)

19-20: LGTM: Added ProfileService dependency to the test setup

The ProfileService is correctly mocked using MockProfileService in the test bed configuration, following proper Angular testing practices. This change ensures that the EditCompetencyComponent can interact with profile-related functionality during testing, supporting the PR objective of enhancing the feedback system configuration.

Also applies to: 33-33

src/test/javascript/spec/component/lecture-unit/attachment-unit/create-attachment-unit.component.spec.ts (1)

22-23: LGTM: Added ProfileService dependency to the test setup

The ProfileService is correctly mocked using MockProfileService in the test bed configuration, following proper Angular testing practices. This change ensures that the CreateAttachmentUnitComponent can interact with profile-related functionality during testing, which supports the PR's objective of improving the flexibility of the feedback system.

Also applies to: 65-65

src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-problem.component.spec.ts (1)

13-14: LGTM: Added ProfileService dependency to the test setup

The ProfileService is correctly mocked using MockProfileService in the test bed configuration, following proper Angular testing practices. This change is particularly relevant for the PR objective since it enables the programming exercise component to differentiate between preliminary and graded feedback modules.

Also applies to: 31-31

src/test/javascript/spec/component/lecture-unit/text-unit/edit-text-unit.component.spec.ts (1)

23-24: The ProfileService integration follows testing best practices.

The addition of ProfileService and its mock implementation follows the pattern of dependency injection in Angular testing. This is in line with the coding guidelines that recommend mocking irrelevant dependencies.

Also applies to: 61-61

src/test/javascript/spec/component/lecture-unit/text-unit/create-text-unit.component.spec.ts (1)

23-24: Good use of MockProfileService.

The implementation correctly provides MockProfileService as a substitute for ProfileService in the test bed, which is consistent with the project's testing approach.

Also applies to: 37-37

src/test/javascript/spec/component/lecture-unit/video-unit/create-video-unit.component.spec.ts (1)

20-21: Consistent mock implementation.

The ProfileService integration matches the pattern used across other component tests, maintaining consistency throughout the test suite.

Also applies to: 66-66

src/test/javascript/spec/component/lecture-unit/online-unit/edit-online-unit.component.spec.ts (1)

20-21: Properly follows test guidelines for dependency mocking.

The addition of ProfileService with its mock implementation adheres to the project's testing guidelines that emphasize mocking irrelevant dependencies for focused unit testing.

Also applies to: 64-64

src/test/javascript/spec/component/lecture-unit/online-unit/create-online-unit.component.spec.ts (1)

20-21: Good addition of ProfileService mock

The addition of ProfileService and MockProfileService imports along with their registration in the TestBed providers array follows good testing practices by properly mocking dependencies instead of using real implementations.

Also applies to: 33-33

src/test/javascript/spec/component/lecture-unit/attachment-unit/edit-attachment-unit.component.spec.ts (1)

22-23: Good addition of ProfileService mock

Adding the ProfileService mock is appropriate and aligns with the testing best practices by properly isolating the component tests from actual service implementations.

Also applies to: 44-44

src/test/javascript/spec/component/lecture-unit/video-unit/edit-video-unit.component.spec.ts (1)

19-20: Good addition of ProfileService mock

The ProfileService mock implementation is correctly added to the providers array, ensuring that component tests don't rely on actual service implementations.

Also applies to: 62-62

src/test/javascript/spec/component/shared/user-settings/science-settings.service.spec.ts (3)

12-14: Good addition of required imports

The addition of ProfileService, ProfileInfo, and PROFILE_ATLAS imports is appropriate for the enhanced test setup.


39-43: Well-implemented ProfileService mock setup

The setup of the ProfileService mock with a specific profile configuration is well-implemented, ensuring that the service behaves correctly during tests.


46-48: Good test cleanup practice

Adding the afterEach block with jest.restoreAllMocks() is a best practice that ensures each test runs with a clean state by resetting all mocks between tests.

src/main/webapp/app/shared/competency-selection/competency-selection.component.ts (7)

1-1: Imports are properly organized and follow Angular guidelines.

The addition of OnDestroy from Angular core, Subscription from rxjs, and the ProfileService along with the PROFILE_ATLAS constant are appropriately imported to support the new lifecycle management and profile feature integration.

Also applies to: 16-16, 22-23


38-38: Component implements OnDestroy to prevent memory leaks.

Good implementation of the OnDestroy interface to properly clean up subscriptions when the component is destroyed.


43-43: ProfileService injection follows Angular DI pattern.

Using the inject function for dependency injection is consistent with modern Angular practices.


71-71: Good subscription management practice.

The private subscription property is properly initialized as undefined and typed as Subscription. This facilitates proper cleanup in ngOnDestroy to prevent memory leaks.


73-81: Well-structured subscription to profile info.

The implementation correctly subscribes to the profile service and conditionally initializes based on the presence of the ATLAS profile. The comment explaining the design decision adds valuable context for other developers.


83-85: Proper implementation of ngOnDestroy.

The component correctly unsubscribes from the profile subscription using the optional chaining operator, preventing memory leaks when the component is destroyed.


87-87: Extracted initialization logic improves readability.

Moving the initialization logic to a separate method makes the code more modular and easier to understand, especially with the conditional execution based on profile information.

src/test/javascript/spec/component/shared/competency-selection.component.spec.ts (3)

5-5: Appropriate imports for testing with profile service.

The addition of BehaviorSubject from rxjs and the profile-related imports are necessary for properly testing the new functionality in the component.

Also applies to: 18-21


42-42: MockProfileService provider correctly added.

The test module configuration has been properly updated to include the MockProfileService, following the pattern used for other service mocks.


54-60: Test setup properly mocks profile service behavior.

The test correctly sets up the ProfileService mock to return an observable containing the profile information with ATLAS enabled. This ensures the component's conditional initialization will be triggered during tests.

The use of BehaviorSubject is appropriate for providing observable test data, and the spying on getProfileInfo ensures the mock implementation will be used during testing.

src/main/webapp/app/shared/user-settings/science-settings/science-settings.service.ts (2)

9-10: Imports align with Angular standards
These imports cleanly reference the required services and constants, and they follow cultural Angular style guides with single quotes.


18-18: Good use of Angular’s inject API
This elegantly injects the ProfileService without needing constructor parameters. No issues found.

@helios-aet helios-aet bot temporarily deployed to artemis-test3.artemis.cit.tum.de March 11, 2025 22:12 Inactive
coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 11, 2025
coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 11, 2025
@helios-aet helios-aet bot temporarily deployed to artemis-test3.artemis.cit.tum.de March 12, 2025 23:35 Inactive
Copy link
Contributor

@eceeeren eceeeren left a comment

Choose a reason for hiding this comment

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

Tested again on TS3, reapprove!

Copy link
Contributor

@ahmetsenturk ahmetsenturk left a comment

Choose a reason for hiding this comment

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

I tested on the TS3, and the functionality works as expected (I was able to select different modules for preliminary and graded feedback, and non-LLM modules do not work for preliminary feedback)

Copy link
Member

@maximiliansoelch maximiliansoelch left a comment

Choose a reason for hiding this comment

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

Found one minor issue with modeling exercises, the rest of the code looks good.

@@ -261,14 +261,17 @@ <h3 jhiTranslate="artemisApp.exercise.sections.grading" id="artemisApp.exercise.
</div>
}
@if (!isExamMode) {
<jhi-exercise-feedback-suggestion-options [exercise]="modelingExercise" [dueDate]="modelingExercise.dueDate" />
Copy link
Member

Choose a reason for hiding this comment

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

Deleting this line is incorrect as it deletes the option to configure Athena's feedback suggestions for modeling exercises. The above checkmark regarding automatic assessment refers to Compass, which is another way to generate feedback suggestions for tutors.
This should be removed in the future.

The UI should look like this:
image

But it looks like this currently:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
athena Pull requests that affect the corresponding module 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. exercise Pull requests that affect the corresponding module modeling Pull requests that affect the corresponding module programming Pull requests that affect the corresponding module ready for review server Pull requests that update Java code. (Added Automatically!) tests text Pull requests that affect the corresponding module
Projects
Status: Ready For Review
Development

Successfully merging this pull request may close these issues.

6 participants