diff --git a/backend/.idea/workspace.xml b/backend/.idea/workspace.xml index 93c0480..449d5dd 100644 --- a/backend/.idea/workspace.xml +++ b/backend/.idea/workspace.xml @@ -5,14 +5,12 @@ + - - - + - - - + + diff --git a/backend/src/main/java/core/api/controller/ScheduleController.java b/backend/src/main/java/core/api/controller/ScheduleController.java index c80aab6..e119421 100644 --- a/backend/src/main/java/core/api/controller/ScheduleController.java +++ b/backend/src/main/java/core/api/controller/ScheduleController.java @@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashMap; import java.util.List; @CrossOrigin(origins = "*", maxAge = 3600) @@ -186,7 +187,11 @@ public class ScheduleController { } else { return ResponseEntity.ok(new TaskScheduleStopResponse(stopResult.getResult())); } + } - + @GetMapping("/schedules/workedMinutesToday") + public ResponseEntity getWorkedMinutesToday() { + ServiceResult getWorkedMinutes = taskScheduleService.getWorkedMinutes(SecurityContextHolder.getContext().getAuthentication().getName()); + return ResponseEntity.ok(new ActiveMinutesInformation(getWorkedMinutes.getResult())); } } diff --git a/backend/src/main/java/core/api/models/timemanager/taskSchedule/ActiveMinutesInformation.java b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ActiveMinutesInformation.java new file mode 100644 index 0000000..3f84af3 --- /dev/null +++ b/backend/src/main/java/core/api/models/timemanager/taskSchedule/ActiveMinutesInformation.java @@ -0,0 +1,18 @@ +package core.api.models.timemanager.taskSchedule; + +public class ActiveMinutesInformation { + + public int activeMinutes; + + public ActiveMinutesInformation(int activeMinutes) { + this.activeMinutes = activeMinutes; + } + + public int getActiveMinutes() { + return activeMinutes; + } + + public void setActiveMinutes(int activeMinutes) { + this.activeMinutes = activeMinutes; + } +} diff --git a/backend/src/main/java/core/services/TaskScheduleService.java b/backend/src/main/java/core/services/TaskScheduleService.java index 9d62574..5e1d559 100644 --- a/backend/src/main/java/core/services/TaskScheduleService.java +++ b/backend/src/main/java/core/services/TaskScheduleService.java @@ -8,6 +8,7 @@ import core.repositories.UserRepository; import core.repositories.timemanager.BasicTaskScheduleRepository; import core.repositories.timemanager.TaskRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import java.time.Duration; @@ -133,4 +134,20 @@ public class TaskScheduleService { taskRepository.save(taskSchedule.getTask()); return new ServiceResult<>((int) activeTime); } + + public ServiceResult getWorkedMinutes(String username) { + Optional user = userRepository.findByUsername(username); + if(user.isEmpty()) { + return new ServiceResult<>(ServiceExitCode.MISSING_ENTITY); + } + + List basicTaskSchedules = basicTaskScheduleRepository.findAllByUser(user.get()); + long workedMinutes = 0; + for(BasicTaskSchedule basicTaskSchedule : basicTaskSchedules) { + if(basicTaskSchedule.getFinishedTime() != null && basicTaskSchedule.getFinishedTime().toLocalDate().isEqual(LocalDate.now())) { + workedMinutes += Duration.between(basicTaskSchedule.getStartTime(), basicTaskSchedule.getFinishedTime()).toMinutes(); + } + } + return new ServiceResult<>((int) workedMinutes); + } } diff --git a/frontend/src/api/.openapi-generator/FILES b/frontend/src/api/.openapi-generator/FILES index 97c4929..51b0542 100644 --- a/frontend/src/api/.openapi-generator/FILES +++ b/frontend/src/api/.openapi-generator/FILES @@ -14,6 +14,7 @@ encoder.ts git_push.sh index.ts model/accountDeleteRequest.ts +model/activeMinutesInformation.ts model/basicScheduleEntityInfo.ts model/basicScheduleFieldInfo.ts model/eMailChangeRequest.ts diff --git a/frontend/src/api/api/schedule.service.ts b/frontend/src/api/api/schedule.service.ts index d354d76..eceb46f 100644 --- a/frontend/src/api/api/schedule.service.ts +++ b/frontend/src/api/api/schedule.service.ts @@ -18,6 +18,7 @@ import { HttpClient, HttpHeaders, HttpParams, import { CustomHttpParameterCodec } from '../encoder'; import { Observable } from 'rxjs'; +import { ActiveMinutesInformation } from '../model/models'; import { BasicScheduleEntityInfo } from '../model/models'; import { BasicScheduleFieldInfo } from '../model/models'; import { ScheduleActivateInfo } from '../model/models'; @@ -707,4 +708,59 @@ export class ScheduleService { ); } + /** + * get number of active minutes + * get number of worked minutes today + * @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 schedulesWorkedMinutesTodayGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; + public schedulesWorkedMinutesTodayGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesWorkedMinutesTodayGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesWorkedMinutesTodayGet(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/workedMinutesToday`, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/frontend/src/api/api/schedules.service.ts b/frontend/src/api/api/schedules.service.ts new file mode 100644 index 0000000..4ebfc3b --- /dev/null +++ b/frontend/src/api/api/schedules.service.ts @@ -0,0 +1,144 @@ +/** + * API Title + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +/* tslint:disable:no-unused-variable member-ordering */ + +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent, HttpParameterCodec, HttpContext + } from '@angular/common/http'; +import { CustomHttpParameterCodec } from '../encoder'; +import { Observable } from 'rxjs'; + +import { ActiveMinutesInformation } from '../model/models'; +import { SimpleStatusResponse } from '../model/models'; + +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + + + +@Injectable({ + providedIn: 'root' +}) +export class SchedulesService { + + protected basePath = 'http://localhost:8080/api'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + public encoder: HttpParameterCodec; + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (configuration) { + this.configuration = configuration; + } + if (typeof this.configuration.basePath !== 'string') { + if (typeof basePath !== 'string') { + basePath = this.basePath; + } + this.configuration.basePath = basePath; + } + this.encoder = this.configuration.encoder || new CustomHttpParameterCodec(); + } + + + private addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams { + if (typeof value === "object" && value instanceof Date === false) { + httpParams = this.addToHttpParamsRecursive(httpParams, value); + } else { + httpParams = this.addToHttpParamsRecursive(httpParams, value, key); + } + return httpParams; + } + + private addToHttpParamsRecursive(httpParams: HttpParams, value?: any, key?: string): HttpParams { + if (value == null) { + return httpParams; + } + + if (typeof value === "object") { + if (Array.isArray(value)) { + (value as any[]).forEach( elem => httpParams = this.addToHttpParamsRecursive(httpParams, elem, key)); + } else if (value instanceof Date) { + if (key != null) { + httpParams = httpParams.append(key, + (value as Date).toISOString().substr(0, 10)); + } else { + throw Error("key may not be null if value is Date"); + } + } else { + Object.keys(value).forEach( k => httpParams = this.addToHttpParamsRecursive( + httpParams, value[k], key != null ? `${key}.${k}` : k)); + } + } else if (key != null) { + httpParams = httpParams.append(key, value); + } else { + throw Error("key may not be null if value is not object or array"); + } + return httpParams; + } + + /** + * get number of active minutes + * get number of worked minutes today + * @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 schedulesWorkedMinutesTodayGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; + public schedulesWorkedMinutesTodayGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesWorkedMinutesTodayGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public schedulesWorkedMinutesTodayGet(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/workedMinutesToday`, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + +} diff --git a/frontend/src/api/model/activeMinutesInformation.ts b/frontend/src/api/model/activeMinutesInformation.ts new file mode 100644 index 0000000..53a9f43 --- /dev/null +++ b/frontend/src/api/model/activeMinutesInformation.ts @@ -0,0 +1,20 @@ +/** + * API Title + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export interface ActiveMinutesInformation { + /** + * number of minutes it was worked today + */ + activeMinutes: number; +} + diff --git a/frontend/src/api/model/models.ts b/frontend/src/api/model/models.ts index 31bf812..d539dab 100644 --- a/frontend/src/api/model/models.ts +++ b/frontend/src/api/model/models.ts @@ -1,4 +1,5 @@ export * from './accountDeleteRequest'; +export * from './activeMinutesInformation'; export * from './basicScheduleEntityInfo'; export * from './basicScheduleFieldInfo'; export * from './eMailChangeRequest'; diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index 3a9e648..07cf48d 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -27,6 +27,12 @@ export class DashboardComponent implements OnInit{ this.schedules = resp; } }) + + this.scheduleService.schedulesWorkedMinutesTodayGet().subscribe({ + next: resp => { + this.workedMinutesToday = resp.activeMinutes; + } + }) } startSchedule(schedule: ScheduleInfo) { diff --git a/openapi.yaml b/openapi.yaml index c7a16a9..9d81ead 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1597,6 +1597,28 @@ paths: schema: type: object $ref: "#/components/schemas/SimpleStatusResponse" + /schedules/workedMinutesToday: + get: + security: + - API_TOKEN: [] + tags: + - schedule + description: get number of worked minutes today + summary: get number of active minutes + responses: + 200: + description: operation successfull + content: + application/json: + schema: + $ref: '#/components/schemas/ActiveMinutesInformation' + 404: + description: User not found + content: + 'application/json': + schema: + type: object + $ref: "#/components/schemas/SimpleStatusResponse" @@ -2105,3 +2127,12 @@ components: type: number description: number in minutes that was already worked on this task example: 10 + ActiveMinutesInformation: + required: + - activeMinutes + additionalProperties: false + properties: + activeMinutes: + type: number + example: 1 + description: number of minutes it was worked today \ No newline at end of file