diff --git a/backend/.idea/workspace.xml b/backend/.idea/workspace.xml index eea8ce0..8a49128 100644 --- a/backend/.idea/workspace.xml +++ b/backend/.idea/workspace.xml @@ -6,8 +6,13 @@ + + - + + + + diff --git a/backend/src/main/java/core/api/controller/ScheduleController.java b/backend/src/main/java/core/api/controller/ScheduleController.java index 7168f1a..34f0d79 100644 --- a/backend/src/main/java/core/api/controller/ScheduleController.java +++ b/backend/src/main/java/core/api/controller/ScheduleController.java @@ -220,4 +220,15 @@ public class ScheduleController { return ResponseEntity.ok(new TaskScheduleStopResponse(serviceResult.getResult())); } } + + @GetMapping("/schedules/missed") + public ResponseEntity loadMissedSchedules() { + Optional user = userRepository.findByUsername(SecurityContextHolder.getContext().getAuthentication().getName()); + if(user.isEmpty()) { + return ResponseEntity.status(403).body(new SimpleStatusResponse("failed")); + } + + List schedules = taskScheduleService.loadMissedSchedules(user.get()); + return ResponseEntity.ok(schedules.stream().map(ScheduleInfo::new).toList()); + } } diff --git a/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java b/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java index 5a1b24a..9395be1 100644 --- a/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java +++ b/backend/src/main/java/core/repositories/timemanager/BasicTaskScheduleRepository.java @@ -39,4 +39,7 @@ public interface BasicTaskScheduleRepository extends CrudRepository findAllFinishedByUserAndDate(User user, LocalDate now); + + @Query(value = "SELECT bts FROM BasicTaskSchedule bts WHERE bts.task.taskgroup.user = ?1 AND bts.startTime IS NULL AND bts.finishedTime IS NULL") + List findAllUnstartedSchedulesOfUser(User user); } diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index b1fe601..bde5b23 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -213,4 +213,16 @@ public class TaskScheduleService { } } + + public List loadMissedSchedules(User user) { + List unstartedSchedules = basicTaskScheduleRepository.findAllUnstartedSchedulesOfUser(user); + LocalDate currentDate = LocalDate.now(); + List missedSchedules = new LinkedList<>(); + for(BasicTaskSchedule schedule : unstartedSchedules) { + if(schedule.getScheduleDate().isBefore(currentDate)) { + missedSchedules.add(schedule); + } + } + return missedSchedules; + } } diff --git a/frontend/src/api/api/schedule.service.ts b/frontend/src/api/api/schedule.service.ts index da226af..688885f 100644 --- a/frontend/src/api/api/schedule.service.ts +++ b/frontend/src/api/api/schedule.service.ts @@ -202,6 +202,61 @@ export class ScheduleService { ); } + /** + * registers forgotten schedule + * Registers forgotten schedule + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public schedulesMissedGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesMissedGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>>; + public schedulesMissedGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>>; + public schedulesMissedGet(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + + let localVarHeaders = this.defaultHeaders; + + let localVarCredential: string | undefined; + // authentication (API_TOKEN) required + localVarCredential = this.configuration.lookupCredential('API_TOKEN'); + if (localVarCredential) { + localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential); + } + + let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; + if (localVarHttpHeaderAcceptSelected === undefined) { + // to determine the Accept header + const httpHeaderAccepts: string[] = [ + 'application/json' + ]; + localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); + } + if (localVarHttpHeaderAcceptSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); + } + + let localVarHttpContext: HttpContext | undefined = options && options.context; + if (localVarHttpContext === undefined) { + localVarHttpContext = new HttpContext(); + } + + + let responseType_: 'text' | 'json' = 'json'; + if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) { + responseType_ = 'text'; + } + + return this.httpClient.get>(`${this.configuration.basePath}/schedules/missed`, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + /** * activates schedule * activates schedule diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 468aec4..051dbee 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -69,6 +69,7 @@ import { TaskgroupOverviewComponent } from './dashboard/taskgroup-overview/taskg import { TaskOverviewComponent } from './dashboard/task-overview/task-overview.component'; import { ForgottenTaskStartDialogComponent } from './dashboard/forgotten-task-start-dialog/forgotten-task-start-dialog.component'; import {MatAutocompleteModule} from "@angular/material/autocomplete"; +import { MissedSchedulesComponent } from './missed-schedules/missed-schedules.component'; @NgModule({ declarations: [ AppComponent, @@ -100,7 +101,8 @@ import {MatAutocompleteModule} from "@angular/material/autocomplete"; ActiveScheduleComponent, TaskgroupOverviewComponent, TaskOverviewComponent, - ForgottenTaskStartDialogComponent + ForgottenTaskStartDialogComponent, + MissedSchedulesComponent ], imports: [ BrowserModule, diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html index 54db53e..1e110fb 100644 --- a/frontend/src/app/dashboard/dashboard.component.html +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -3,7 +3,7 @@

There are missed schedules. Please reschedule them.

- Reschedule + Reschedule

NowToday: {{workedMinutesToday}} min

diff --git a/openapi.yaml b/openapi.yaml index 06c21fd..1ddeaca 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1694,9 +1694,30 @@ paths: schema: type: object $ref: "#/components/schemas/SimpleStatusResponse" - - - + /schedules/missed: + get: + security: + - API_TOKEN: [] + tags: + - schedule + description: Registers forgotten schedule + summary: registers forgotten schedule + responses: + 200: + description: Operation successfull + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ScheduleInfo' + 403: + description: User not found/No permission + content: + application/json: + schema: + $ref: '#/components/schemas/SimpleStatusResponse' + components: securitySchemes: API_TOKEN: @@ -2231,4 +2252,5 @@ components: minutesSpent: type: number description: number of minutes spent on task - example: 10 \ No newline at end of file + example: 10 + \ No newline at end of file