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

Adaptive learning: Add implementation for grade or bonus goal in learner profile #10159

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

Conversation

JohannesStoehr
Copy link
Contributor

@JohannesStoehr JohannesStoehr commented Jan 17, 2025

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 documented the Java code using JavaDoc style.

Motivation and Context

Stacked on #9673
#8758

Description

Adapted scheduling of exercises in the learning path to respect the preferences regarding the inclusion of graded exercises.

This PR does not add any UI!

Steps for Testing

Prerequisites:

  • 1 Instructor
  • 1 Student
  1. Log in to Artemis
  2. Create or find a course with a few competencies and linked exercises and lecture units
  3. Participate as student in the learning path and check that no errors occur

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

Test Coverage

Summary by CodeRabbit

  • New Features

    • Introduced a preference scale enum for learner profiles.
    • Enhanced learning path recommendation system with personalized exercise selection.
    • Added support for course learner profiles and user profile management.
  • Improvements

    • Updated learning path retrieval to include learner profiles.
    • Refined exercise recommendation logic based on user preferences.
    • Improved data fetching methods in repositories.
  • Technical Updates

    • Added new repository and service methods for learner profile management.
    • Updated integration and unit tests to support new profile-related functionality.

N0W0RK and others added 30 commits November 5, 2024 10:56
…/adaptive-learning/learner-profile-graded-exercises
…/adaptive-learning/learner-profile-graded-exercises

# Conflicts:
#	src/main/java/de/tum/cit/aet/artemis/atlas/repository/CourseLearnerProfileRepository.java
…/adaptive-learning/learner-profile-graded-exercises
…nto feature/adaptive-learning/learner-profile-graded-exercises
…/adaptive-learning/learner-profile-graded-exercises
…/adaptive-learning/learner-profile-graded-exercises
…/adaptive-learning/learner-profile-graded-exercises
…/adaptive-learning/learner-profile-graded-exercises
@JohannesStoehr JohannesStoehr requested a review from a team as a code owner January 17, 2025 11:56
@github-actions github-actions bot added tests server Pull requests that update Java code. (Added Automatically!) database Pull requests that update the database. (Added Automatically!). Require a CRITICAL deployment. atlas Pull requests that affect the corresponding module core Pull requests that affect the corresponding module programming Pull requests that affect the corresponding module labels Jan 17, 2025
Copy link

coderabbitai bot commented Jan 17, 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/atlas/service/learningpath/LearningPathService.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.

Walkthrough

This pull request introduces several enhancements to the Artemis Atlas learning path and learner profile system. Key changes include the addition of a new PreferenceScale enum to represent learner preferences, the introduction of a CourseLearnerProfileRepository for managing course learner profiles, and updates to various services and repositories to improve the retrieval and management of learner profiles. Additionally, several methods have been modified or added to enhance the recommendation logic and data retrieval processes, ensuring that learner profiles are integrated throughout the system.

Changes

File Change Summary
PreferenceScale.java New enum defining Likert scale preferences with integer values from 1 to 5
CourseLearnerProfileRepository.java New repository interface with methods for deleting course learner profiles
LearningPathRepository.java Updated methods for fetching learning paths with eager loading of related entities
LearningPathRecommendationService.java Enhanced exercise recommendation logic incorporating learner profiles
LearningPathService.java Modified method to include learner profile retrieval
LearningPathResource.java Updated method calls to include learner profile data
UserRepository.java Added methods for retrieving users with learner profiles
Test files Updated test cases to support new learner profile functionality

Possibly related PRs

Suggested labels

client, database, ready to merge, programming, small

Suggested reviewers

  • MaximilianAnzinger
  • florian-glombik
  • pzdr7

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

🧹 Nitpick comments (17)
src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathRecommendationService.java (2)

605-619: Use PreferenceScale enum for type safety and readability.

In the getExerciseOrderComparator method, aimForGradeOrBonus is an integer value derived from CourseLearnerProfile. Using the PreferenceScale enum directly enhances code clarity and prevents errors due to invalid values.

Apply this diff to improve the code:

-private static Comparator<CompetencyExerciseLink> getExerciseOrderComparator(int aimForGradeOrBonus) {
+private static Comparator<CompetencyExerciseLink> getExerciseOrderComparator(PreferenceScale aimForGradeOrBonus) {
     Comparator<CompetencyExerciseLink> exerciseComparator = Comparator.comparingDouble(exerciseLink -> 
         (COMPETENCY_LINK_WEIGHT_TO_GRADE_AIM_RATIO * exerciseLink.getWeight())
-        + aimForGradeOrBonus * getIncludeInOverallScoreWeight(exerciseLink.getExercise().getIncludedInOverallScore()));
+        + aimForGradeOrBonus.getValue() * getIncludeInOverallScoreWeight(exerciseLink.getExercise().getIncludedInOverallScore()));
     exerciseComparator = exerciseComparator.reversed();
     exerciseComparator = exerciseComparator.thenComparing(exerciseLink -> exerciseLink.getExercise().getTitle());
     return exerciseComparator;
 }

Ensure that all calls to this method pass the PreferenceScale enum instead of an integer value.


628-639: Refactor to use PreferenceScale in predicate logic.

In getExerciseSelectionPredicate, using the PreferenceScale enum directly improves readability and reduces the chance of errors from magic numbers.

Apply this diff to enhance the code:

-private static Predicate<Exercise> getExerciseSelectionPredicate(int aimForGradeOrBonus, AtomicDouble remainingExercisePoints) {
+private static Predicate<Exercise> getExerciseSelectionPredicate(PreferenceScale aimForGradeOrBonus, AtomicDouble remainingExercisePoints) {
     Predicate<Exercise> exercisePredicate = exercise -> remainingExercisePoints.getAndAdd(-exercise.getMaxPoints()) >= 0;
-    if (aimForGradeOrBonus == HIGH.getValue()) {
+    if (aimForGradeOrBonus == PreferenceScale.HIGH) {
         exercisePredicate = exercisePredicate
             .or(exercise -> exercise.getIncludedInOverallScore() == INCLUDED_COMPLETELY || exercise.getIncludedInOverallScore() == INCLUDED_AS_BONUS);
     }
-    else if (aimForGradeOrBonus == MEDIUM_HIGH.getValue()) {
+    else if (aimForGradeOrBonus == PreferenceScale.MEDIUM_HIGH) {
         exercisePredicate = exercisePredicate.or(exercise -> exercise.getIncludedInOverallScore() == INCLUDED_COMPLETELY);
     }
     return exercisePredicate;
 }
src/main/java/de/tum/cit/aet/artemis/atlas/repository/LearnerProfileRepository.java (1)

26-26: Remove unnecessary comment.

The comment // ok because of delete is redundant and doesn't add value. The @Transactional annotation is standard for delete operations.

-    @Transactional // ok because of delete
+    @Transactional
src/main/java/de/tum/cit/aet/artemis/atlas/repository/CourseLearnerProfileRepository.java (1)

21-21: Remove unnecessary comment.

The comment // ok because of delete is redundant and doesn't add value. The @Transactional annotation is standard for delete operations.

-    @Transactional // ok because of delete
+    @Transactional
src/main/java/de/tum/cit/aet/artemis/atlas/service/profile/LearnerProfileService.java (1)

26-36: Enhance JavaDoc with more details.

The JavaDoc could be more descriptive about the method's behavior, potential exceptions, and the bidirectional relationship setup.

     /**
      * Create a learner profile for a user and saves it in the database
      *
      * @param user the user for which the profile is created
+     * @throws IllegalStateException if the user already has a profile
+     * @implNote This method sets up a bidirectional relationship between
+     *           the user and the learner profile before saving
      */
src/main/java/de/tum/cit/aet/artemis/atlas/domain/profile/LearnerProfile.java (1)

21-22: Consider bidirectional relationship management.

The one-to-one relationship with User should include helper methods to manage both sides of the relationship.

Add this method to maintain the bidirectional relationship:

+    public void setUser(User user) {
+        if (user == null) {
+            if (this.user != null) {
+                this.user.setLearnerProfile(null);
+            }
+        } else {
+            user.setLearnerProfile(this);
+        }
+        this.user = user;
+    }
src/main/java/de/tum/cit/aet/artemis/atlas/domain/profile/CourseLearnerProfile.java (1)

28-41: Document the meaning of preference scales.

The numerical fields use a 0-5 scale, but the meaning of these values is not documented.

Add JavaDoc to explain the scale:

+    /**
+     * Indicates the learner's goal for grade or bonus achievement.
+     * Scale: 0 (not important) to 5 (highest priority)
+     */
     @Column(name = "aim_for_grade_or_bonus")
     @Min(0)
     @Max(5)
     private int aimForGradeOrBonus;
src/test/java/de/tum/cit/aet/artemis/core/test_repository/UserTestRepository.java (1)

62-63: Consider pagination for large result sets.

The EntityGraph loads multiple collections which could result in large amounts of data being fetched. Consider adding a paginated version of this method.

Add a paginated version:

+    @EntityGraph(type = LOAD, attributePaths = { "learningPaths", "learnerProfile", "learnerProfile.courseLearnerProfiles" })
+    Page<User> findAllWithLearningPathsAndLearnerProfile(Pageable pageable);
src/main/java/de/tum/cit/aet/artemis/atlas/service/profile/CourseLearnerProfileService.java (1)

52-62: Optimize batch creation for better performance.

The current implementation of createCourseLearnerProfiles creates a new CourseLearnerProfile instance for each user. For large sets of users, this could be optimized.

Consider using batch processing:

 public void createCourseLearnerProfiles(Course course, Set<User> users) {
+    // Process in batches of 100 to optimize memory usage and database operations
+    final int batchSize = 100;
+    List<CourseLearnerProfile> allProfiles = new ArrayList<>();
     Set<CourseLearnerProfile> courseProfiles = users.stream().map(user -> {
         var courseProfile = new CourseLearnerProfile();
         courseProfile.setCourse(course);
         courseProfile.setLearnerProfile(user.getLearnerProfile());
         return courseProfile;
-    }).collect(Collectors.toSet());
+    }).collect(Collectors.toList());
 
-    courseLearnerProfileRepository.saveAll(courseProfiles);
+    for (int i = 0; i < courseProfiles.size(); i += batchSize) {
+        int end = Math.min(i + batchSize, courseProfiles.size());
+        courseLearnerProfileRepository.saveAll(courseProfiles.subList(i, end));
+    }
 }
src/test/java/de/tum/cit/aet/artemis/atlas/service/LearningPathServiceTest.java (1)

68-70: Enhance test setup with profile verification.

The setup creates learner profiles but doesn't verify their creation. Also, consider adding cleanup to prevent test data pollution.

Add verification and cleanup:

 @BeforeEach
 void setup() {
     userUtilService.addUsers(TEST_PREFIX, 5, 1, 1, 1);
     learnerProfileUtilService.createLearnerProfilesForUsers(TEST_PREFIX);
+    // Verify profiles were created
+    assertThat(learnerProfileUtilService.getAllLearnerProfiles())
+        .hasSize(8); // 5 users + 1 tutor + 1 editor + 1 instructor
 }

+@AfterEach
+void cleanup() {
+    learnerProfileUtilService.deleteAllLearnerProfiles(TEST_PREFIX);
+}
src/test/java/de/tum/cit/aet/artemis/atlas/learningpath/LearningPathIntegrationTest.java (1)

548-580: Enhance navigation preferences test coverage.

The test verifies completion states but doesn't validate how the preferences affect navigation behavior.

Consider adding assertions to verify that the preferences influence the navigation:

 assertThat(result.predecessorLearningObject().completed()).isTrue();
 assertThat(result.currentLearningObject().completed()).isFalse();
 assertThat(result.successorLearningObject().completed()).isFalse();
+// Verify that preferences influence navigation
+assertThat(result.currentLearningObject().type())
+    .as("High grade preference should prioritize exercises")
+    .isEqualTo(aimForGradeOrBonus > 3 ? LearningPathNavigationObjectDTO.LearningObjectType.EXERCISE : LearningPathNavigationObjectDTO.LearningObjectType.LECTURE);
src/test/java/de/tum/cit/aet/artemis/core/user/util/UserTestService.java (1)

414-415: Enhance learner profile verification.

The learner profile verification only checks existence but not the profile's contents or structure.

Consider adding more detailed assertions:

-assertThat(learnerProfileRepository.findByUser(student)).isNotEmpty();
+var learnerProfile = learnerProfileRepository.findByUser(student);
+assertThat(learnerProfile)
+    .isPresent()
+    .hasValueSatisfying(profile -> {
+        assertThat(profile.getUser()).isEqualTo(student);
+        assertThat(profile.getCourseLearnerProfiles()).isEmpty();
+    });
src/main/java/de/tum/cit/aet/artemis/core/service/CourseService.java (3)

1058-1064: Avoid unnecessary database calls in addUserToGroup method

In the addUserToGroup method, you're fetching the Course entity again from the database using findWithEagerCompetenciesAndPrerequisitesByIdElseThrow(course.getId()), even though you already have the course object. This introduces an unnecessary database call and could impact performance.

Consider using the existing course object if it already contains the necessary data. If additional data is needed, adjust the initial retrieval of the course to include the required relationships.

 public void addUserToGroup(User user, String group, Course course) {
     userService.addUserToGroup(user, group);
     if (group.equals(course.getStudentGroupName()) && course.getLearningPathsEnabled()) {
-        Course courseWithCompetencies = courseRepository.findWithEagerCompetenciesAndPrerequisitesByIdElseThrow(course.getId());
-        learnerProfileApi.createCourseLearnerProfile(course, user);
-        learningPathApi.generateLearningPathForUser(courseWithCompetencies, user);
+        learnerProfileApi.createCourseLearnerProfile(course, user);
+        learningPathApi.generateLearningPathForUser(course, user);
     }
 }

Line range hint 660-664: Optimize batch processing when registering multiple users

In the registerUsersForCourseGroup method, creating learner profiles and generating learning paths for each user individually might lead to performance issues when handling large numbers of users.

Consider optimizing the process by batching database operations or processing users asynchronously to improve performance.


58-58: Remove unused imports and organize import statements

There are import statements that might not be used in the class, and organizing imports improves code readability and maintenance.

Please review the imports and remove any that are unused. Ensure that the imports adhere to the project's conventions and coding guidelines.

src/main/java/de/tum/cit/aet/artemis/atlas/domain/profile/PreferenceScale.java (2)

4-5: Correct typo in Javadoc: 'lickert-scale' should be 'Likert scale'

In the Javadoc comment, 'lickert-scale' is misspelled.

Please correct the typo to improve documentation clarity.

 /**
- * Enum for the preferences as lickert-scale regarding settings in the (course) learner profile, see {@link CourseLearnerProfile} and {@link LearnerProfile}.
+ * Enum for the preferences as Likert scale regarding settings in the (course) learner profile, see {@link CourseLearnerProfile} and {@link LearnerProfile}.
  */

6-19: Provide a method to retrieve enum by value

Currently, there's no method to get a PreferenceScale based on an integer value. Providing such a method can enhance usability and prevent duplicate code.

Consider adding a static method to retrieve the enum constant by its associated value.

public static PreferenceScale fromValue(int value) {
    for (PreferenceScale scale : PreferenceScale.values()) {
        if (scale.getValue() == value) {
            return scale;
        }
    }
    throw new IllegalArgumentException("Invalid PreferenceScale value: " + value);
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d4d178b and ff1e356.

⛔ Files ignored due to path filters (2)
  • src/main/resources/config/liquibase/changelog/20241107130000_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/atlas/api/LearnerProfileApi.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/domain/profile/CourseLearnerProfile.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/domain/profile/LearnerProfile.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/domain/profile/PreferenceScale.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/CourseLearnerProfileRepository.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/LearnerProfileRepository.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/repository/LearningPathRepository.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathRecommendationService.java (10 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathService.java (7 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/profile/CourseLearnerProfileService.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/profile/LearnerProfileService.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/atlas/web/LearningPathResource.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/domain/User.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/repository/UserRepository.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/service/CourseService.java (9 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/service/UserScheduleService.java (3 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/service/user/UserCreationService.java (5 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/service/user/UserService.java (4 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/web/CourseResource.java (10 hunks)
  • src/test/java/de/tum/cit/aet/artemis/atlas/AbstractAtlasIntegrationTest.java (3 hunks)
  • src/test/java/de/tum/cit/aet/artemis/atlas/learningpath/LearningPathIntegrationTest.java (9 hunks)
  • src/test/java/de/tum/cit/aet/artemis/atlas/profile/util/LearnerProfileUtilService.java (1 hunks)
  • src/test/java/de/tum/cit/aet/artemis/atlas/service/LearningPathServiceTest.java (3 hunks)
  • src/test/java/de/tum/cit/aet/artemis/core/test_repository/UserTestRepository.java (2 hunks)
  • src/test/java/de/tum/cit/aet/artemis/core/user/util/UserTestService.java (3 hunks)
  • src/test/java/de/tum/cit/aet/artemis/programming/AbstractProgrammingIntegrationJenkinsGitlabTest.java (2 hunks)
  • src/test/java/de/tum/cit/aet/artemis/programming/CourseGitlabJenkinsIntegrationTest.java (1 hunks)
🧰 Additional context used
📓 Path-based instructions (27)
src/test/java/de/tum/cit/aet/artemis/programming/AbstractProgrammingIntegrationJenkinsGitlabTest.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/java/de/tum/cit/aet/artemis/atlas/service/LearningPathServiceTest.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/atlas/domain/profile/PreferenceScale.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/programming/CourseGitlabJenkinsIntegrationTest.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/core/domain/User.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/atlas/repository/CourseLearnerProfileRepository.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/atlas/AbstractAtlasIntegrationTest.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/java/de/tum/cit/aet/artemis/atlas/profile/util/LearnerProfileUtilService.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/atlas/repository/LearnerProfileRepository.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/core/test_repository/UserTestRepository.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/atlas/service/profile/LearnerProfileService.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/core/service/UserScheduleService.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/core/service/CourseService.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/atlas/service/profile/CourseLearnerProfileService.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/atlas/domain/profile/CourseLearnerProfile.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/atlas/web/LearningPathResource.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/core/service/user/UserCreationService.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/core/user/util/UserTestService.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/atlas/service/learningpath/LearningPathService.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/core/service/user/UserService.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/core/web/CourseResource.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/core/repository/UserRepository.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/atlas/repository/LearningPathRepository.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/atlas/service/learningpath/LearningPathRecommendationService.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/atlas/domain/profile/LearnerProfile.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/atlas/api/LearnerProfileApi.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/atlas/learningpath/LearningPathIntegrationTest.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

📓 Learnings (1)
src/main/java/de/tum/cit/aet/artemis/core/web/CourseResource.java (1)
Learnt from: Strohgelaender
PR: ls1intum/Artemis#8030
File: src/main/java/de/tum/in/www1/artemis/service/CourseScoreCalculationService.java:21-49
Timestamp: 2024-11-12T12:52:03.805Z
Learning: The project consistently avoids using star-imports in Java files.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (35)
src/test/java/de/tum/cit/aet/artemis/atlas/AbstractAtlasIntegrationTest.java (1)

12-12: Well-organized additions for learner profile testing!

The new fields and imports for learner profile functionality are correctly placed within their respective sections, maintaining the class's clear organization pattern. The additions follow the established conventions and will effectively support integration testing of the learner profile features.

Also applies to: 17-17, 92-93, 153-154

src/test/java/de/tum/cit/aet/artemis/programming/AbstractProgrammingIntegrationJenkinsGitlabTest.java (1)

11-11: LGTM! Well-structured integration of learner profile testing capabilities.

The addition of LearnerProfileUtilService follows the established patterns and enables comprehensive testing of learner profile features across programming exercises.

Also applies to: 207-208

src/main/java/de/tum/cit/aet/artemis/core/web/CourseResource.java (5)

181-182: LGTM! Clean dependency injection implementation.

The addition of LearnerProfileApi follows Spring's constructor injection pattern and immutability best practices.

Also applies to: 201-201, 225-225


Line range hint 1243-1254: LGTM! Good simplification of method signature.

The removal of the redundant Role parameter improves the method's design while maintaining all necessary functionality through the group parameter.


1184-1184: LGTM! Consistent with method signature update.

The method call has been properly updated to match the simplified addUserToCourseGroup signature.


1199-1199: LGTM! Consistent with method signature update.

The method call has been properly updated to match the simplified addUserToCourseGroup signature.


1215-1215: LGTM! Consistent with method signature update.

The method calls have been properly updated to match the simplified addUserToCourseGroup signature.

Also applies to: 1230-1230

src/main/java/de/tum/cit/aet/artemis/atlas/repository/LearningPathRepository.java (3)

39-44: LGTM! The eager loading implementation follows established patterns.

The new method and its default implementation maintain consistency with other similar methods in the repository, appropriately using @EntityGraph for eager loading of the course relationship.


89-91: LGTM! The default method implementation is consistent.

The method name and implementation maintain consistency with the repository's established patterns for handling missing entities.


73-87: Consider query optimization opportunities.

While the query structure is clear, there are potential performance optimizations to consider:

  1. The condition clp.course.id = l.course.id in the WHERE clause could create a cartesian product if multiple course learner profiles exist. Consider moving this to the JOIN clause.
  2. Consider using INNER JOIN for mandatory relationships to improve query performance.

Here's the optimized query:

    @Query("""
            SELECT l
            FROM LearningPath l
            LEFT JOIN FETCH l.competencies c
            LEFT JOIN FETCH c.lectureUnitLinks lul
            LEFT JOIN FETCH lul.lectureUnit
            LEFT JOIN FETCH c.exerciseLinks el
            LEFT JOIN FETCH el.exercise
-           LEFT JOIN FETCH l.user u
-           LEFT JOIN FETCH u.learnerProfile lp
-           LEFT JOIN FETCH lp.courseLearnerProfiles clp
+           INNER JOIN FETCH l.user u
+           INNER JOIN FETCH u.learnerProfile lp
+           INNER JOIN FETCH lp.courseLearnerProfiles clp
+               ON clp.course.id = l.course.id
-           WHERE l.id = :learningPathId
-               AND clp.course.id = l.course.id
+           WHERE l.id = :learningPathId
            """)

Let's verify the relationships to ensure INNER JOIN is safe:

src/test/java/de/tum/cit/aet/artemis/programming/CourseGitlabJenkinsIntegrationTest.java (1)

705-705: LGTM! Consider applying the same setup to similar tests.

The addition of learner profile creation before testing user addition aligns with the PR objectives and maintains test isolation.

Let's check if other similar test methods in this file should also create learner profiles:

✅ Verification successful

Verified: Learner profile creation is correctly placed

The addition of learner profile creation is appropriate for this test and no changes are needed in other tests because:

  • The test inherits learnerProfileUtilService from the base class
  • Similar tests already have access to this functionality through inheritance
  • The setup follows the established pattern in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find similar test methods that might need learner profile setup
# Look for test methods that deal with user management in courses

# Search for test methods related to adding/removing users
rg -A 5 'test.*((Add|Remove)(Student|Tutor|Instructor|Editor).*Course|EnrollInCourse)' src/test/java/de/tum/cit/aet/artemis/programming/CourseGitlabJenkinsIntegrationTest.java

# Search for test methods that use userUtilService
rg -A 5 'userUtilService\.' src/test/java/de/tum/cit/aet/artemis/programming/CourseGitlabJenkinsIntegrationTest.java

Length of output: 5828


Script:

#!/bin/bash
# Check if courseTestService handles learner profiles
rg -A 5 'createLearnerProfiles|LearnerProfile' 'src/test/**/CourseTestService.java'

# Check for other test files that might need similar setup
fd -e java -x rg -l 'class.*Test.*extends.*IntegrationTest' {} \; | xargs rg -l '(Add|Remove)(Student|Tutor|Instructor).*Course'

Length of output: 294


Script:

#!/bin/bash
# Find CourseTestService and check its content
fd CourseTestService.java | xargs rg -A 5 'createLearnerProfiles|LearnerProfile'

# Find similar test services and integration tests
fd -e java | rg -l 'TestService|IntegrationTest' | xargs rg -l '(Student|Tutor|Instructor).*Course'

# Check for learner profile setup in other integration tests
fd -e java | rg -l 'IntegrationTest' | xargs rg -A 5 'learnerProfile|LearnerProfile'

Length of output: 365


Script:

#!/bin/bash
# Simple search for learner profile usage in test files
rg -A 5 'learnerProfile|LearnerProfile' 'src/test'

# Find similar integration test files
rg -l 'class.*IntegrationTest' 'src/test'

# Look for user management test patterns
rg -A 5 '@Test.*((Add|Remove)(Student|Tutor|Instructor)|EnrollInCourse)' 'src/test'

Length of output: 34835

src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathRecommendationService.java (2)

597-603: Clarify the weighting logic in getIncludeInOverallScoreWeight.

The method getIncludeInOverallScoreWeight assigns integer weights to IncludedInOverallScore enum values. It's essential to ensure that these weights accurately reflect the intended prioritization of exercises. Consider adding comments or documentation to explain the rationale behind these specific weight assignments for better maintainability.


613-615: Verify the calculation logic in the exercise comparator.

The formula used in the comparator combines multiple factors to prioritize exercises. Please review and ensure that the calculation accurately reflects the intended prioritization based on the learner's aim and exercise attributes. Adjust the weights or logic if necessary.

src/main/java/de/tum/cit/aet/artemis/atlas/service/profile/LearnerProfileService.java (1)

31-36: 🛠️ Refactor suggestion

Add transaction boundary and enhance error handling.

The createProfile method should be transactional to ensure atomicity of the operation. Also, consider adding validation to check if the user already has a profile.

+    @Transactional
     public void createProfile(User user) {
+        if (user.getLearnerProfile() != null) {
+            throw new IllegalStateException("User already has a learner profile");
+        }
         var profile = new LearnerProfile();
         profile.setUser(user);
         user.setLearnerProfile(profile);
         userRepository.save(user);
     }

Likely invalid or redundant comment.

src/test/java/de/tum/cit/aet/artemis/core/test_repository/UserTestRepository.java (1)

79-84: Consider performance implications of LIKE prefix query.

The findAllByUserPrefix query uses a LIKE operation which might perform poorly on large datasets without proper indexing.

Run this script to check if an index exists:

src/main/java/de/tum/cit/aet/artemis/atlas/service/profile/CourseLearnerProfileService.java (1)

17-82: 🛠️ Refactor suggestion

Add transaction management for database operations.

The service methods perform database operations but lack transaction management. This could lead to data inconsistency if any operation fails.

Add @Transactional annotations:

+import org.springframework.transaction.annotation.Transactional;

 @Profile(PROFILE_CORE)
 @Service
+@Transactional
 public class CourseLearnerProfileService {

Likely invalid or redundant comment.

src/main/java/de/tum/cit/aet/artemis/core/domain/User.java (2)

216-219: LGTM! Well-structured JPA relationship.

The one-to-one relationship with LearnerProfile is properly configured with:

  • Lazy loading for performance optimization
  • Appropriate cascade and orphan removal settings
  • Proper JSON serialization handling

554-560: LGTM! Standard accessor methods.

The getter and setter methods follow Java bean conventions.

src/main/java/de/tum/cit/aet/artemis/atlas/web/LearningPathResource.java (4)

235-235: LGTM! Consistent service method update.

Updated to fetch learner profile data along with competencies and learning objects.


251-251: LGTM! Consistent service method update.

Updated to fetch learner profile data along with competencies and learning objects.


344-344: LGTM! Consistent service method update.

Updated to fetch learner profile data along with competencies and learning objects.


367-367: LGTM! Enhanced user data retrieval.

Updated to fetch user with learner profile data specific to the course context.

src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathService.java (5)

94-95: LGTM! Clean dependency injection.

Added CourseLearnerProfileService with proper constructor injection.

Also applies to: 99-100, 111-111


121-123: LGTM! Proper initialization of learner profiles.

Ensures learner profiles are created for students when enabling learning paths.


134-137: LGTM! Consistent learner profile handling.

Ensures learner profiles are created before generating learning paths.


139-145: LGTM! Well-documented method.

Clear documentation of the method's purpose and parameters.


421-431: Ensure proper error handling for learner profile creation.

The method attempts to create a course learner profile when not found, but there's no explicit error handling if the creation fails.

Consider adding try-catch block to handle potential exceptions during profile creation:

 if (optionalLearningPath.isEmpty()) {
     LearningPath learningPathWithCourse = learningPathRepository.findWithEagerCourseByIdElseThrow(learningPathId);
-    courseLearnerProfileService.createCourseLearnerProfile(learningPathWithCourse.getCourse(), learningPathWithCourse.getUser());
-    learningPath = learningPathRepository.findWithCompetenciesAndLectureUnitsAndExercisesAndLearnerProfileByIdElseThrow(learningPathId);
+    try {
+        courseLearnerProfileService.createCourseLearnerProfile(learningPathWithCourse.getCourse(), learningPathWithCourse.getUser());
+        learningPath = learningPathRepository.findWithCompetenciesAndLectureUnitsAndExercisesAndLearnerProfileByIdElseThrow(learningPathId);
+    } catch (Exception e) {
+        log.error("Failed to create course learner profile for learning path {}: {}", learningPathId, e.getMessage());
+        throw new RuntimeException("Failed to create course learner profile", e);
+    }
 }
✅ Verification successful

Verified: Error handling is needed for profile creation

The implementation of createCourseLearnerProfile uses repository operations that can throw exceptions (findByUserElseThrow and save). Adding a try-catch block as suggested in the review comment is appropriate because:

  • The service method is designed to propagate exceptions (uses methods with "ElseThrow" suffix)
  • Multiple database operations could fail and need proper error handling
  • It's a critical user-facing operation where graceful error handling improves user experience
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Find implementation of createCourseLearnerProfile
ast-grep --pattern 'createCourseLearnerProfile($$$) {
  $$$
}'

# Look for similar error handling patterns
rg "courseLearnerProfileService" -A 5 -B 5

# Find try-catch blocks in service layer
fd "Service.java" --exec rg "try\s*\{.*?catch.*?\}" -U

Length of output: 12577


Script:

#!/bin/bash
# Find CourseLearnerProfileService implementation
fd "CourseLearnerProfileService" --type f

# Look for similar service methods with error handling
rg "class.*Service.*implements" -A 10

# Find error handling patterns in service layer
rg "@Service.*class" -A 20 -B 5

Length of output: 68693


Script:

#!/bin/bash
# Find implementation of createCourseLearnerProfile
cat src/main/java/de/tum/cit/aet/artemis/atlas/service/profile/CourseLearnerProfileService.java

# Look for error handling patterns in similar service methods
rg "try\s*\{.*?catch.*?\}" -A 5 src/main/java/de/tum/cit/aet/artemis/atlas/service/

Length of output: 3326

src/main/java/de/tum/cit/aet/artemis/core/service/user/UserService.java (2)

119-120: LGTM! Clean dependency injection.

Added LearnerProfileApi with proper constructor injection.

Also applies to: 127-127, 142-142


476-478: 🛠️ Refactor suggestion

Consider transaction boundary for profile deletion.

The profile deletion and user updates should be atomic to maintain data consistency.

Consider wrapping the operations in a transaction:

+@Transactional
 public void softDeleteUser(String login) {
     userRepository.findOneWithGroupsByLogin(login).ifPresent(user -> {
         participationVCSAccessTokenService.deleteAllByUserId(user.getId());
-        learnerProfileApi.deleteProfile(user);
-        user.setDeleted(true);
-        user.setLearnerProfile(null);
+        try {
+            learnerProfileApi.deleteProfile(user);
+            user.setDeleted(true);
+            user.setLearnerProfile(null);
+        } catch (Exception e) {
+            log.error("Failed to delete learner profile for user {}: {}", user.getId(), e.getMessage());
+            throw new RuntimeException("Failed to delete learner profile", e);
+        }
         anonymizeUser(user);
         log.warn("Soft Deleted User: {}", user);
     });
 }

Likely invalid or redundant comment.

src/test/java/de/tum/cit/aet/artemis/atlas/learningpath/LearningPathIntegrationTest.java (1)

86-86: Add verification for learner profile creation.

The learner profile creation is added to the setup but there's no verification that the profiles were created successfully.

Add assertions to verify the learner profiles:

 learnerProfileUtilService.createLearnerProfilesForUsers(TEST_PREFIX);
+assertThat(learnerProfileRepository.findAll()).hasSize(NUMBER_OF_STUDENTS + NUMBER_OF_TUTORS + NUMBER_OF_EDITORS + NUMBER_OF_INSTRUCTORS);
src/test/java/de/tum/cit/aet/artemis/core/user/util/UserTestService.java (1)

113-126: LGTM! Clean organization of repository dependencies.

The repository dependencies are well-organized with each repository on its own line for clarity.

src/main/java/de/tum/cit/aet/artemis/core/repository/UserRepository.java (3)

102-112: LGTM! Well-structured JPQL query with efficient joins.

The query is well-organized with appropriate LEFT JOINs to fetch the learner profile data efficiently.


193-194: LGTM! Efficient entity graph usage for eager loading.

The method uses entity graph to efficiently load the related entities in a single query.


1025-1033: LGTM! Well-documented method with clear purpose.

The method is well-documented and follows the repository's pattern for student retrieval methods.

src/main/java/de/tum/cit/aet/artemis/core/service/CourseService.java (1)

515-515: Handle potential exceptions when deleting learner profiles

In the delete method, the call to learnerProfileApi.deleteAllForCourse(course); might throw exceptions if an error occurs during the deletion process. It's important to handle these exceptions to ensure that the course deletion process is robust.

Please ensure that any exceptions thrown by learnerProfileApi.deleteAllForCourse(course); are properly handled, either by catching them and logging an appropriate message or by propagating them with additional context.

…-graded-exercises

# Conflicts:
#	src/main/java/de/tum/cit/aet/artemis/atlas/repository/CourseLearnerProfileRepository.java
#	src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathService.java
#	src/main/java/de/tum/cit/aet/artemis/core/service/CourseService.java
@github-actions github-actions bot removed the programming Pull requests that affect the corresponding module label Jan 17, 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: 0

🧹 Nitpick comments (1)
src/main/java/de/tum/cit/aet/artemis/core/repository/UserRepository.java (1)

906-917: Enhance error message for better debugging.

While the implementation is solid, consider making the error message more specific by including the courseId in case of failure.

-        return getValueElseThrow(findOneWithGroupsAndAuthoritiesAndLearnerProfileByLogin(currentUserLogin, courseId));
+        return getValueElseThrow(
+            findOneWithGroupsAndAuthoritiesAndLearnerProfileByLogin(currentUserLogin, courseId),
+            String.format("User with login '%s' not found for course '%d'", currentUserLogin, courseId)
+        );
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ff1e356 and 2a51d86.

📒 Files selected for processing (2)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathService.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/repository/UserRepository.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathService.java
🧰 Additional context used
📓 Path-based instructions (1)
src/main/java/de/tum/cit/aet/artemis/core/repository/UserRepository.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 (7)
  • GitHub Check: client-style
  • GitHub Check: client-tests
  • GitHub Check: server-style
  • GitHub Check: server-tests
  • GitHub Check: Build and Push Docker Image
  • GitHub Check: Analyse
  • GitHub Check: Build .war artifact
🔇 Additional comments (1)
src/main/java/de/tum/cit/aet/artemis/core/repository/UserRepository.java (1)

102-112: LGTM! Well-structured JPQL query.

The query is well-optimized with appropriate LEFT JOINs and follows SQL best practices.

coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 17, 2025
@JohannesStoehr JohannesStoehr changed the title Adaptive learning: Add implementation for grade or bonus goal in learner profile Adaptive learning: Add implementation for grade or bonus goal in learner profile Jan 17, 2025
@github-actions github-actions bot removed the database Pull requests that update the database. (Added Automatically!). Require a CRITICAL deployment. label Jan 17, 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: 1

🧹 Nitpick comments (1)
src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathService.java (1)

421-421: Consider simplifying the method name.

The current method name is quite long. Consider renaming it to something more concise while maintaining clarity, such as findLearningPathWithDetailsById.

-    public LearningPath findWithCompetenciesAndReleasedLearningObjectsAndCompletedUsersAndLearnerProfileById(long learningPathId) {
+    public LearningPath findLearningPathWithDetailsById(long learningPathId) {

Add a detailed JavaDoc to describe what "details" includes:

    /**
     * Finds a learning path by ID with eagerly fetched:
     * - Competencies
     * - Released learning objects
     * - Completed users
     * - Learner profile
     *
     * @param learningPathId the ID of the learning path
     * @return the learning path with all related details
     * @throws EntityNotFoundException if the learning path is not found
     */
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2a51d86 and 044d4e0.

📒 Files selected for processing (1)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathService.java (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathService.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 (3)
  • GitHub Check: client-tests
  • GitHub Check: server-tests
  • GitHub Check: Analyse
🔇 Additional comments (1)
src/main/java/de/tum/cit/aet/artemis/atlas/service/learningpath/LearningPathService.java (1)

135-135: LGTM! Good initialization of learner profiles.

The addition ensures that learner profiles are created before generating learning paths, which is essential for the adaptive learning feature.

Copy link
Contributor

@raffifasaro raffifasaro left a comment

Choose a reason for hiding this comment

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

code LGTM

Copy link
Contributor

@ufukygmr ufukygmr left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@N0W0RK N0W0RK left a comment

Choose a reason for hiding this comment

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

Interactingnwith the learning path works without error.

Exercises in the learning path view are not rendered until the user interacts with the ui, but this also occurs in production.
See #10196

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
atlas Pull requests that affect the corresponding module core Pull requests that affect the corresponding module lock:artemis-test5 server Pull requests that update Java code. (Added Automatically!) tests
Projects
Status: Ready For Review
Development

Successfully merging this pull request may close these issues.

6 participants