Abstract API Endpoint to filter task fetch also by overdue

This commit is contained in:
Sebastian 2023-10-29 13:13:29 +01:00
parent 2b627b679e
commit 513a51c3db
8 changed files with 120 additions and 54 deletions

View File

@ -5,7 +5,12 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="3a869f59-290a-4ab2-b036-a878ce801bc4" name="Changes" comment="Forget single schedule"> <list default="true" id="3a869f59-290a-4ab2-b036-a878ce801bc4" name="Changes" comment="Forget single schedule">
<change beforePath="$PROJECT_DIR$/src/main/java/core/api/controller/ScheduleController.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/api/controller/ScheduleController.java" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/main/java/core/api/models/timemanager/tasks/TaskScope.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/core/api/controller/TaskController.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/api/controller/TaskController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/core/repositories/timemanager/TaskRepository.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/repositories/timemanager/TaskRepository.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/core/services/TaskService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/services/TaskService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../openapi.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/../openapi.yaml" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -16,8 +21,8 @@
<option name="RECENT_TEMPLATES"> <option name="RECENT_TEMPLATES">
<list> <list>
<option value="Interface" /> <option value="Interface" />
<option value="Enum" />
<option value="Class" /> <option value="Class" />
<option value="Enum" />
</list> </list>
</option> </option>
</component> </component>
@ -41,33 +46,34 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent">{ <component name="PropertiesComponent"><![CDATA[{
&quot;keyToString&quot;: { "keyToString": {
&quot;RequestMappingsPanelOrder0&quot;: &quot;0&quot;, "RequestMappingsPanelOrder0": "0",
&quot;RequestMappingsPanelOrder1&quot;: &quot;1&quot;, "RequestMappingsPanelOrder1": "1",
&quot;RequestMappingsPanelWidth0&quot;: &quot;75&quot;, "RequestMappingsPanelWidth0": "75",
&quot;RequestMappingsPanelWidth1&quot;: &quot;75&quot;, "RequestMappingsPanelWidth1": "75",
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;, "RunOnceActivity.OpenProjectViewOnStart": "true",
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;, "RunOnceActivity.ShowReadmeOnStart": "true",
&quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;, "WebServerToolWindowFactoryState": "false",
&quot;git-widget-placeholder&quot;: &quot;issue-11-angular-update&quot;, "extract.method.default.visibility": "private",
&quot;last_directory_selection&quot;: &quot;D:/Programmierprojekte/TimeManager/backend/src/main/java/core/api/models/timemanager&quot;, "git-widget-placeholder": "issue-11-angular-update",
&quot;last_opened_file_path&quot;: &quot;D:/Programmierprojekte/Dicewars/client&quot;, "last_directory_selection": "D:/Programmierprojekte/TimeManager/backend/src/main/java/core/api/models/timemanager",
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;, "last_opened_file_path": "D:/Programmierprojekte/Dicewars/client",
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;, "node.js.detected.package.eslint": "true",
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;, "node.js.detected.package.tslint": "true",
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;, "node.js.selected.package.eslint": "(autodetect)",
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;, "node.js.selected.package.tslint": "(autodetect)",
&quot;settings.editor.selected.configurable&quot;: &quot;swagger&quot;, "nodejs_package_manager_path": "npm",
&quot;ts.external.directory.path&quot;: &quot;/snap/intellij-idea-ultimate/459/plugins/javascript-impl/jsLanguageServicesImpl/external&quot;, "settings.editor.selected.configurable": "swagger",
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot; "ts.external.directory.path": "/snap/intellij-idea-ultimate/459/plugins/javascript-impl/jsLanguageServicesImpl/external",
"vue.rearranger.settings.migration": "true"
}, },
&quot;keyToStringList&quot;: { "keyToStringList": {
&quot;DatabaseDriversLRU&quot;: [ "DatabaseDriversLRU": [
&quot;mariadb&quot; "mariadb"
] ]
} }
}</component> }]]></component>
<component name="RunManager"> <component name="RunManager">
<configuration name="DemoApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" nameIsGenerated="true"> <configuration name="DemoApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" nameIsGenerated="true">
<module name="demo" /> <module name="demo" />

View File

@ -4,6 +4,7 @@ import core.api.models.auth.SimpleStatusResponse;
import core.api.models.timemanager.taskSchedule.ScheduleInfo; import core.api.models.timemanager.taskSchedule.ScheduleInfo;
import core.api.models.timemanager.tasks.TaskEntityInfo; import core.api.models.timemanager.tasks.TaskEntityInfo;
import core.api.models.timemanager.tasks.TaskFieldInfo; import core.api.models.timemanager.tasks.TaskFieldInfo;
import core.api.models.timemanager.tasks.TaskScope;
import core.api.models.timemanager.tasks.TaskShortInfo; import core.api.models.timemanager.tasks.TaskShortInfo;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup; import core.entities.timemanager.Taskgroup;
@ -31,22 +32,37 @@ public class TaskController {
this.taskgroupService = taskgroupService; this.taskgroupService = taskgroupService;
} }
@GetMapping("/tasks/all/{finished}") @GetMapping("/tasks/all/{scope}/{detailed}")
public ResponseEntity<List<TaskShortInfo>> loadAllTasks(@PathVariable boolean finished) { public ResponseEntity<?> loadAllTasksShort(@PathVariable TaskScope scope, @PathVariable boolean detailed) {
List<Task> taskList = taskService.loadAllTasks(SecurityContextHolder.getContext().getAuthentication().getName(), finished); List<Task> taskList = taskService.loadAllTasks(SecurityContextHolder.getContext().getAuthentication().getName(), scope);
List<TaskShortInfo> taskShortInfos = new ArrayList<>(); List<TaskShortInfo> taskShortInfos = new ArrayList<>();
List<TaskEntityInfo> taskInfos = new ArrayList<>();
for(Task task : taskList) { for(Task task : taskList) {
List<Taskgroup> ancestors = Taskgroup.getAncestorList(task.getTaskgroup()); StringBuilder builder = loadTaskgroupPath(task);
ancestors.add(task.getTaskgroup()); if(!detailed) {
StringBuilder builder = new StringBuilder(); taskShortInfos.add(new TaskShortInfo(task.getTaskID(), builder.toString()));
for(Taskgroup taskgroup : ancestors) { } else {
builder.append(taskgroup.getTaskgroupName()).append("/"); taskInfos.add(new TaskEntityInfo(task));
} }
builder.append(task.getTaskName());
taskShortInfos.add(new TaskShortInfo(task.getTaskID(), builder.toString()));
} }
return ResponseEntity.ok(taskShortInfos);
if(detailed) {
return ResponseEntity.ok(taskInfos);
} else {
return ResponseEntity.ok(taskShortInfos);
}
}
private StringBuilder loadTaskgroupPath(Task task) {
List<Taskgroup> ancestors = Taskgroup.getAncestorList(task.getTaskgroup());
ancestors.add(task.getTaskgroup());
StringBuilder builder = new StringBuilder();
for(Taskgroup taskgroup : ancestors) {
builder.append(taskgroup.getTaskgroupName()).append("/");
}
builder.append(task.getTaskName());
return builder;
} }
@GetMapping("/tasks/{taskgroupID}/{status}") @GetMapping("/tasks/{taskgroupID}/{status}")

View File

@ -0,0 +1,8 @@
package core.api.models.timemanager.tasks;
public enum TaskScope {
FINISHED,
UNFINISHED,
OVERDUE;
}

View File

@ -8,6 +8,7 @@ import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import java.time.LocalDate;
import java.util.List; import java.util.List;
@Repository @Repository
@ -25,4 +26,7 @@ public interface TaskRepository extends CrudRepository<Task, Long> {
@Modifying @Modifying
@Query(value = "DELETE FROM Task t WHERE t.taskID = ?1") @Query(value = "DELETE FROM Task t WHERE t.taskID = ?1")
void deleteByTaskID(long taskID); void deleteByTaskID(long taskID);
@Query(value = "SELECT t FROM Task t WHERE t.taskgroup.user.username = ?1 AND t is NOT NULL AND t.deadline > ?2")
List<Task> findAllOverdue(String username, LocalDate now);
} }

View File

@ -1,6 +1,7 @@
package core.services; package core.services;
import core.api.models.timemanager.tasks.TaskFieldInfo; import core.api.models.timemanager.tasks.TaskFieldInfo;
import core.api.models.timemanager.tasks.TaskScope;
import core.entities.timemanager.BasicTaskSchedule; import core.entities.timemanager.BasicTaskSchedule;
import core.entities.timemanager.Task; import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup; import core.entities.timemanager.Taskgroup;
@ -10,6 +11,7 @@ import core.repositories.timemanager.TaskgroupRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
@ -99,7 +101,18 @@ public class TaskService {
} }
} }
public List<Task> loadAllTasks(String username, boolean finished) { public List<Task> loadAllTasks(String username, TaskScope scope) {
return taskRepository.findAllByUser(username, finished); switch (scope) {
case UNFINISHED, FINISHED -> {
return taskRepository.findAllByUser(username, scope.equals(TaskScope.FINISHED));
}
case OVERDUE -> {
return taskRepository.findAllOverdue(username, LocalDate.now());
}
default -> {
return new ArrayList<>();
}
}
} }
} }

View File

@ -92,16 +92,20 @@ export class TaskService {
/** /**
* edits an existing task * edits an existing task
* edits an existing task * edits an existing task
* @param finished fetches either finished or unfinished tasks * @param scope defines scope of fetched tasks
* @param detailed determines whether an detailed response is required or not
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @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. * @param reportProgress flag to report request and response progress.
*/ */
public tasksAllFinishedGet(finished: boolean, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<Array<TaskShortInfo>>; public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE', detailed: boolean, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<Array<TaskShortInfo> | Array<TaskEntityInfo>>;
public tasksAllFinishedGet(finished: boolean, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<Array<TaskShortInfo>>>; public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE', detailed: boolean, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpResponse<Array<TaskShortInfo> | Array<TaskEntityInfo>>>;
public tasksAllFinishedGet(finished: boolean, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<Array<TaskShortInfo>>>; public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE', detailed: boolean, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<HttpEvent<Array<TaskShortInfo> | Array<TaskEntityInfo>>>;
public tasksAllFinishedGet(finished: boolean, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> { public tasksAllScopeDetailedGet(scope: 'FINISHED' | 'UNFINISHED' | 'OVERDUE', detailed: boolean, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable<any> {
if (finished === null || finished === undefined) { if (scope === null || scope === undefined) {
throw new Error('Required parameter finished was null or undefined when calling tasksAllFinishedGet.'); throw new Error('Required parameter scope was null or undefined when calling tasksAllScopeDetailedGet.');
}
if (detailed === null || detailed === undefined) {
throw new Error('Required parameter detailed was null or undefined when calling tasksAllScopeDetailedGet.');
} }
let localVarHeaders = this.defaultHeaders; let localVarHeaders = this.defaultHeaders;
@ -136,7 +140,7 @@ export class TaskService {
responseType_ = 'text'; responseType_ = 'text';
} }
return this.httpClient.get<Array<TaskShortInfo>>(`${this.configuration.basePath}/tasks/all/${encodeURIComponent(String(finished))}`, return this.httpClient.get<Array<TaskShortInfo> | Array<TaskEntityInfo>>(`${this.configuration.basePath}/tasks/all/${encodeURIComponent(String(scope))}/${encodeURIComponent(String(detailed))}`,
{ {
context: localVarHttpContext, context: localVarHttpContext,
responseType: <any>responseType_, responseType: <any>responseType_,

View File

@ -30,7 +30,7 @@ export class ForgottenTaskStartDialogComponent implements OnInit{
} }
ngOnInit() { ngOnInit() {
this.taskService.tasksAllFinishedGet(false).subscribe({ this.taskService.tasksAllScopeDetailedGet("UNFINISHED", false).subscribe({
next: resp => { next: resp => {
this.tasks = resp; this.tasks = resp;
this.filteredOptions = this.myControl.valueChanges.pipe( this.filteredOptions = this.myControl.valueChanges.pipe(

View File

@ -883,7 +883,7 @@ paths:
schema: schema:
type: object type: object
$ref: "#/components/schemas/SimpleStatusResponse" $ref: "#/components/schemas/SimpleStatusResponse"
/tasks/all/{finished}: /tasks/all/{scope}/{detailed}:
get: get:
security: security:
- API_TOKEN: [] - API_TOKEN: []
@ -892,9 +892,19 @@ paths:
summary: edits an existing task summary: edits an existing task
description: edits an existing task description: edits an existing task
parameters: parameters:
- name: finished - name: scope
in: path in: path
description: fetches either finished or unfinished tasks description: defines scope of fetched tasks
required: true
schema:
type: string
enum:
- FINISHED
- UNFINISHED
- OVERDUE
- name: detailed
in: path
description: determines whether an detailed response is required or not
required: true required: true
schema: schema:
type: boolean type: boolean
@ -905,9 +915,14 @@ paths:
content: content:
application/json: application/json:
schema: schema:
type: array oneOf:
items: - type: array
$ref: '#/components/schemas/TaskShortInfo' items:
$ref: '#/components/schemas/TaskShortInfo'
- type: array
items:
$ref: '#/components/schemas/TaskEntityInfo'
/tasks/{taskgroupID}/{status}: /tasks/{taskgroupID}/{status}:
get: get: