-
Notifications
You must be signed in to change notification settings - Fork 297
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
General
: Add cleanup service for admins
#9296
Conversation
…utions to the database
118d5b4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🧹 Outside diff range and nitpick comments (9)
src/test/javascript/spec/component/admin/cleanup-service/cleanup-service.service.spec.ts (1)
11-12
: Consider making the mock data more explicit.The mock date could be more explicit to avoid potential timezone issues in tests.
-const mockDate = dayjs(); +const mockDate = dayjs('2024-03-08T12:00:00.000Z');src/test/javascript/spec/component/admin/cleanup-service/cleanup-service.component.spec.ts (4)
1-10
: Optimize imports for better performance and maintainability.
- Replace the full dayjs import with a specific import:
-import dayjs from 'dayjs/esm'; +import { Dayjs } from 'dayjs/esm';
- Consider mocking dayjs functionality instead of using the actual implementation to improve test performance.
17-38
: Consider using async/await for cleaner test setup.The promise chain can be simplified:
- beforeEach(() => { + beforeEach(async () => { const mockCleanupService = { getLastExecutions: jest.fn(), deleteOrphans: jest.fn(), deletePlagiarismComparisons: jest.fn(), deleteNonRatedResults: jest.fn(), deleteOldRatedResults: jest.fn(), deleteOldSubmissionVersions: jest.fn(), deleteOldFeedback: jest.fn(), }; - TestBed.configureTestingModule({ + await TestBed.configureTestingModule({ imports: [ArtemisTestModule, CleanupServiceComponent], providers: [{ provide: DataCleanupService, useValue: mockCleanupService }], - }) - .compileComponents() - .then(() => { - fixture = TestBed.createComponent(CleanupServiceComponent); - comp = fixture.componentInstance; - cleanupService = TestBed.inject(DataCleanupService); - }); + }).compileComponents(); + + fixture = TestBed.createComponent(CleanupServiceComponent); + comp = fixture.componentInstance; + cleanupService = TestBed.inject(DataCleanupService); });
40-52
: Enhance date comparison assertion specificity.Replace the generic equality check with a more specific date comparison:
-expect(comp.cleanupOperations[0].lastExecuted).toEqual(dayjs(executionRecord[0].executionDate)); +expect(comp.cleanupOperations[0].lastExecuted?.isSame(executionRecord[0].executionDate)).toBeTrue();
90-112
: Enhance date validation test coverage.While the current test covers basic valid/invalid cases, consider adding tests for:
- Edge cases (same date for from/to)
- Null/undefined dates
- Extreme date ranges
Also, consider extracting the test data setup:
const createOperation = (from: Dayjs, to: Dayjs): CleanupOperation => ({ name: 'deleteOrphans', deleteFrom: from, deleteTo: to, lastExecuted: undefined, datesValid: signal(true), });src/main/java/de/tum/cit/aet/artemis/assessment/repository/cleanup/LongFeedbackTextCleanupRepository.java (2)
34-42
: SQL keywords should be uppercase for consistency.According to the coding guidelines (
sql: uppercase
), SQL keywords should be uppercase for better readability.- delete from LongFeedbackText lft - where lft.feedback.id in ( - select f.id - from Feedback f - where f.result.participation is null - and f.result.submission is null + DELETE FROM LongFeedbackText lft + WHERE lft.feedback.id IN ( + SELECT f.id + FROM Feedback f + WHERE f.result.participation IS NULL + AND f.result.submission IS NULL
1-125
: Consider adding safeguards for large-scale deletions.Since this repository handles cleanup operations that could affect a large number of records:
- Consider adding batch processing to prevent memory issues and reduce database load
- Add monitoring/logging to track the number of records deleted in each operation
- Consider implementing rate limiting to prevent database overload
This is especially important for the date-range based methods that could potentially match a large number of records.
src/main/webapp/app/admin/cleanup-service/data-cleanup.service.ts (1)
33-34
: Refactor duplicated date conversion logic into a helper methodThe date conversion code in the
deletePlagiarismComparisons
,deleteNonRatedResults
, anddeleteOldRatedResults
methods is duplicated. To improve code reuse and maintainability, consider extracting this logic into a private helper method.Apply this diff to refactor the code:
+ private convertDeleteDates(deleteFrom: dayjs.Dayjs, deleteTo: dayjs.Dayjs): { deleteFromString: string; deleteToString: string } { + return { + deleteFromString: convertDateFromClient(deleteFrom)!, + deleteToString: convertDateFromClient(deleteTo)!, + }; + } deletePlagiarismComparisons(deleteFrom: dayjs.Dayjs, deleteTo: dayjs.Dayjs): Observable<HttpResponse<CleanupServiceExecutionRecordDTO>> { - const deleteFromString = convertDateFromClient(deleteFrom)!; - const deleteToString = convertDateFromClient(deleteTo)!; + const { deleteFromString, deleteToString } = this.convertDeleteDates(deleteFrom, deleteTo); return this.http.delete<CleanupServiceExecutionRecordDTO>(`${this.adminResourceUrl}/plagiarism-comparisons`, { params: { deleteFrom: deleteFromString, deleteTo: deleteToString }, observe: 'response', }); } deleteNonRatedResults(deleteFrom: dayjs.Dayjs, deleteTo: dayjs.Dayjs): Observable<HttpResponse<CleanupServiceExecutionRecordDTO>> { - const deleteFromString = convertDateFromClient(deleteFrom)!; - const deleteToString = convertDateFromClient(deleteTo)!; + const { deleteFromString, deleteToString } = this.convertDeleteDates(deleteFrom, deleteTo); return this.http.delete<CleanupServiceExecutionRecordDTO>(`${this.adminResourceUrl}/non-rated-results`, { params: { deleteFrom: deleteFromString, deleteTo: deleteToString }, observe: 'response', }); } deleteOldRatedResults(deleteFrom: dayjs.Dayjs, deleteTo: dayjs.Dayjs): Observable<HttpResponse<CleanupServiceExecutionRecordDTO>> { - const deleteFromString = convertDateFromClient(deleteFrom)!; - const deleteToString = convertDateFromClient(deleteTo)!; + const { deleteFromString, deleteToString } = this.convertDeleteDates(deleteFrom, deleteTo); return this.http.delete<CleanupServiceExecutionRecordDTO>(`${this.adminResourceUrl}/old-rated-results`, { params: { deleteFrom: deleteFromString, deleteTo: deleteToString }, observe: 'response', }); }Also applies to: 47-48, 61-62
src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminCleanupResource.java (1)
28-28
: Remove trailing slash from@RequestMapping
pathThe trailing slash in the
@RequestMapping("api/admin/cleanup/")
may cause inconsistent URL mappings or unnecessary complexity. It's recommended to remove the trailing slash to standardize the endpoints and prevent potential issues with request handling.Apply this diff:
-@RequestMapping("api/admin/cleanup/") +@RequestMapping("api/admin/cleanup")
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (8)
src/main/java/de/tum/cit/aet/artemis/assessment/repository/cleanup/FeedbackCleanupRepository.java
(1 hunks)src/main/java/de/tum/cit/aet/artemis/assessment/repository/cleanup/LongFeedbackTextCleanupRepository.java
(1 hunks)src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminCleanupResource.java
(1 hunks)src/main/webapp/app/admin/cleanup-service/data-cleanup.service.ts
(1 hunks)src/main/webapp/i18n/en/cleanupService.json
(1 hunks)src/test/java/de/tum/cit/aet/artemis/core/CleanupIntegrationTest.java
(1 hunks)src/test/javascript/spec/component/admin/cleanup-service/cleanup-service.component.spec.ts
(1 hunks)src/test/javascript/spec/component/admin/cleanup-service/cleanup-service.service.spec.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/main/webapp/i18n/en/cleanupService.json
🚧 Files skipped from review as they are similar to previous changes (2)
- src/main/java/de/tum/cit/aet/artemis/assessment/repository/cleanup/FeedbackCleanupRepository.java
- src/test/java/de/tum/cit/aet/artemis/core/CleanupIntegrationTest.java
🧰 Additional context used
📓 Path-based instructions (5)
src/main/java/de/tum/cit/aet/artemis/assessment/repository/cleanup/LongFeedbackTextCleanupRepository.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/admin/AdminCleanupResource.java (1)
Pattern src/main/java/**/*.java
: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports
src/main/webapp/app/admin/cleanup-service/data-cleanup.service.ts (1)
src/test/javascript/spec/component/admin/cleanup-service/cleanup-service.component.spec.ts (1)
Pattern src/test/javascript/spec/**/*.ts
: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}
src/test/javascript/spec/component/admin/cleanup-service/cleanup-service.service.spec.ts (1)
Pattern src/test/javascript/spec/**/*.ts
: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}
🔇 Additional comments (2)
src/test/javascript/spec/component/admin/cleanup-service/cleanup-service.service.spec.ts (1)
1-6
: LGTM! Modern Angular testing setup.
The imports are minimal and follow best practices by using the new provider-based HTTP testing setup.
src/main/java/de/tum/cit/aet/artemis/assessment/repository/cleanup/LongFeedbackTextCleanupRepository.java (1)
1-26
: LGTM! Repository declaration follows best practices.
The repository is well-structured with appropriate annotations, clear documentation, and follows coding guidelines for imports and dependency injection.
src/test/javascript/spec/component/admin/cleanup-service/cleanup-service.service.spec.ts
Show resolved
Hide resolved
src/test/javascript/spec/component/admin/cleanup-service/cleanup-service.service.spec.ts
Show resolved
Hide resolved
src/test/javascript/spec/component/admin/cleanup-service/cleanup-service.component.spec.ts
Show resolved
Hide resolved
.../de/tum/cit/aet/artemis/assessment/repository/cleanup/LongFeedbackTextCleanupRepository.java
Show resolved
Hide resolved
.../de/tum/cit/aet/artemis/assessment/repository/cleanup/LongFeedbackTextCleanupRepository.java
Show resolved
Hide resolved
src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminCleanupResource.java
Show resolved
Hide resolved
src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminCleanupResource.java
Show resolved
Hide resolved
src/main/java/de/tum/cit/aet/artemis/core/web/admin/AdminCleanupResource.java
Show resolved
Hide resolved
# Conflicts: # src/main/webapp/app/shared/date-time-picker/date-time-picker.component.html # src/main/webapp/app/shared/date-time-picker/date-time-picker.component.ts
There was a problem hiding this 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
🧹 Outside diff range and nitpick comments (2)
src/main/webapp/app/shared/date-time-picker/date-time-picker.component.html (1)
Line range hint
17-45
: Consider improving button positioning for better responsiveness.While the implementation is functional, the absolute positioning of buttons might cause layout issues on different screen sizes.
Consider using a more flexible layout approach:
- <button [owlDateTimeTrigger]="dt" class="btn position-absolute" type="button"> + <button [owlDateTimeTrigger]="dt" class="btn" type="button"> <fa-icon [icon]="faCalendarAlt" /> </button> - <div class="position-relative"> - <button class="btn position-absolute" type="button" style="right: 0" (click)="clearDate()"> + <div class="ms-auto"> + <button class="btn" type="button" (click)="clearDate()"> <fa-icon [icon]="faCircleXmark" /> </button> </div>src/main/webapp/app/shared/date-time-picker/date-time-picker.component.ts (1)
28-28
: Add JSDoc documentation for the new input property.While the implementation is correct and follows Angular's new input() API, adding JSDoc documentation would improve maintainability by clearly describing the property's purpose and expected values.
+ /** Controls the visibility of the label. When true, the label is hidden. */ hideLabelName = input<boolean>(false);
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
⛔ Files ignored due to path filters (1)
docs/admin/cleanup/cleanup-menu.png
is excluded by!**/*.png
,!**/*.png
📒 Files selected for processing (3)
docs/admin/cleanup-service.rst
(1 hunks)src/main/webapp/app/shared/date-time-picker/date-time-picker.component.html
(1 hunks)src/main/webapp/app/shared/date-time-picker/date-time-picker.component.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/admin/cleanup-service.rst
🧰 Additional context used
📓 Path-based instructions (2)
src/main/webapp/app/shared/date-time-picker/date-time-picker.component.html (1)
Pattern src/main/webapp/**/*.html
: @if and @for are new and valid Angular syntax replacing *ngIf and *ngFor. They should always be used over the old style.
src/main/webapp/app/shared/date-time-picker/date-time-picker.component.ts (1)
🔇 Additional comments (5)
src/main/webapp/app/shared/date-time-picker/date-time-picker.component.html (4)
Line range hint 1-5
: LGTM! Proper usage of @if directive.
The label visibility logic is well-implemented and follows the new Angular syntax guidelines by using @if instead of *ngIf.
Line range hint 6-10
: LGTM! Clean tooltip implementation.
The tooltip rendering follows best practices with proper icon usage and accessibility considerations.
Line range hint 11-16
: LGTM! Well-structured timezone warning.
The timezone warning implementation properly handles internationalization with parameter interpolation.
Line range hint 46-55
: LGTM! Comprehensive validation feedback.
The validation messages are well-structured with proper internationalization and warning states.
src/main/webapp/app/shared/date-time-picker/date-time-picker.component.ts (1)
28-28
: Verify template usage of hideLabelName.
The implementation looks good. Let's verify that the template is correctly using this property for conditional rendering.
✅ Verification successful
Let me gather more information to verify the template usage.
Template correctly uses hideLabelName for conditional rendering
The template properly uses hideLabelName()
in a conditional statement to control the visibility of the label element. The implementation is correct as it shows the label only when labelName()
is truthy and hideLabelName()
is falsy:
@if (labelName() && !hideLabelName()) {
<label for="date-input-field" class="form-control-label col">
{{ labelName() }}
</label>
}
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the template is correctly using hideLabelName for conditional rendering
# Test: Check if the template file exists and contains the expected condition
rg -l "date-time-picker.component.html" | xargs rg "hideLabelName"
Length of output: 107
Script:
#!/bin/bash
# Search for the template file and show its content
fd "date-time-picker.component.html" --type f --exec cat {}
Length of output: 2156
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re-approve
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re-approve
Checklist
General
Server
Client
authorities
to all new routes and checked the course groups for displaying navigation elements (links, buttons).Motivation and Context
Artemis stores a large amount of information, some of which can become corrupted or irrelevant over time. These records occupy significant database space, which can be reclaimed by deleting unused data. This includes old results, unresolved plagiarism cases, and unused feedback.
Currently, there are scripts for cleaning up results and feedback, but no automated process exists for clearing unresolved plagiarism cases. Additionally, orphaned entities, such as results without associated submissions or participation, remain unaddressed, leading to inefficient database usage. Furthermore, these cleanup scripts must be run manually by administrators, which is not ideal. To address these issues, a dedicated cleanup service for administrators was implemented to streamline the process.
Description
A cleanup service has been added to the admin panel, allowing administrators to select specific cleanup operations to perform on the database. They can specify a time period for which the cleanup should be executed, providing flexibility in managing old or unused data. In future iterations, a scheduled job is planned to be introduced, which will automatically execute the cleanup operations periodically, reducing the need for manual intervention and ensuring ongoing database optimization.
Steps for Testing
Prerequisites:
large_course_main.py
script. See README in the folderquick-course-setup
for more details.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
Code Review
Manual Tests
Performance Tests
Test Coverage
Info: ✅ ❌ in Confirmation (assert/expect) have to be adjusted manually, also delete trivial files!
Client
Server
Screenshots
View from the navigation bar
Cleanup service
Confirmation dialog
Summary by CodeRabbit
New Features
CleanupServiceComponent
for managing data cleanup operations in the admin interface.CleanupServiceComponent
in the admin module.DataCleanupService
to handle HTTP requests for various cleanup operations.Bug Fixes
Documentation
Tests
CleanupServiceComponent
andDataCleanupService
to validate functionality and HTTP requests.